diff options
author | Tejun Heo <tj@kernel.org> | 2013-11-29 17:18:32 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-11-29 21:21:01 -0500 |
commit | cf9e5a73aaff0204801dd19cb4bd91d32f32026a (patch) | |
tree | 4a63d030a4c2ee08c06b97d348bcf42bdf7a3cd4 /include/linux/kernfs.h | |
parent | fa736a951e456b996a76826ba78ff974414c3b55 (diff) |
sysfs, kernfs: make sysfs_dirent definition public
sysfs_dirent includes some information which should be available to
kernfs users - the type, flags, name and parent pointer. This patch
moves sysfs_dirent definition from kernfs/kernfs-internal.h to
include/linux/kernfs.h so that kernfs users can access them.
The type part of flags is exported as enum kernfs_node_type, the flags
kernfs_node_flag, sysfs_type() and kernfs_enable_ns() are moved to
include/linux/kernfs.h and the former is updated to return the enum
type. sysfs_dirent->s_parent and ->s_name are marked explicitly as
public.
This patch doesn't introduce any functional changes.
v2: Flags exported too and kernfs_enable_ns() definition moved.
v3: While moving kernfs_enable_ns() to include/linux/kernfs.h, v1 and
v2 put the definition outside CONFIG_SYSFS replacing the dummy
implementation with the actual implementation too. Unfortunately,
this can lead to oops when !CONFIG_SYSFS because
kernfs_enable_ns() may be called on a NULL @sd and now tries to
dereference @sd instead of not doing anything. This issue was
reported by Yuanhan Liu.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include/linux/kernfs.h')
-rw-r--r-- | include/linux/kernfs.h | 118 |
1 files changed, 114 insertions, 4 deletions
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 75fcbe5c9d65..faaf4f29e33d 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
@@ -13,6 +13,9 @@ | |||
13 | #include <linux/mutex.h> | 13 | #include <linux/mutex.h> |
14 | #include <linux/idr.h> | 14 | #include <linux/idr.h> |
15 | #include <linux/lockdep.h> | 15 | #include <linux/lockdep.h> |
16 | #include <linux/rbtree.h> | ||
17 | #include <linux/atomic.h> | ||
18 | #include <linux/completion.h> | ||
16 | 19 | ||
17 | struct file; | 20 | struct file; |
18 | struct iattr; | 21 | struct iattr; |
@@ -21,7 +24,92 @@ struct vm_area_struct; | |||
21 | struct super_block; | 24 | struct super_block; |
22 | struct file_system_type; | 25 | struct file_system_type; |
23 | 26 | ||
24 | struct sysfs_dirent; | 27 | struct sysfs_open_dirent; |
28 | struct sysfs_inode_attrs; | ||
29 | |||
30 | enum kernfs_node_type { | ||
31 | SYSFS_DIR = 0x0001, | ||
32 | SYSFS_KOBJ_ATTR = 0x0002, | ||
33 | SYSFS_KOBJ_LINK = 0x0004, | ||
34 | }; | ||
35 | |||
36 | #define SYSFS_TYPE_MASK 0x000f | ||
37 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) | ||
38 | #define SYSFS_ACTIVE_REF SYSFS_KOBJ_ATTR | ||
39 | #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK | ||
40 | |||
41 | enum kernfs_node_flag { | ||
42 | SYSFS_FLAG_REMOVED = 0x0010, | ||
43 | SYSFS_FLAG_NS = 0x0020, | ||
44 | SYSFS_FLAG_HAS_SEQ_SHOW = 0x0040, | ||
45 | SYSFS_FLAG_HAS_MMAP = 0x0080, | ||
46 | SYSFS_FLAG_LOCKDEP = 0x0100, | ||
47 | }; | ||
48 | |||
49 | /* type-specific structures for sysfs_dirent->s_* union members */ | ||
50 | struct sysfs_elem_dir { | ||
51 | unsigned long subdirs; | ||
52 | /* children rbtree starts here and goes through sd->s_rb */ | ||
53 | struct rb_root children; | ||
54 | |||
55 | /* | ||
56 | * The kernfs hierarchy this directory belongs to. This fits | ||
57 | * better directly in sysfs_dirent but is here to save space. | ||
58 | */ | ||
59 | struct kernfs_root *root; | ||
60 | }; | ||
61 | |||
62 | struct sysfs_elem_symlink { | ||
63 | struct sysfs_dirent *target_sd; | ||
64 | }; | ||
65 | |||
66 | struct sysfs_elem_attr { | ||
67 | const struct kernfs_ops *ops; | ||
68 | struct sysfs_open_dirent *open; | ||
69 | loff_t size; | ||
70 | }; | ||
71 | |||
72 | /* | ||
73 | * sysfs_dirent - the building block of sysfs hierarchy. Each and every | ||
74 | * sysfs node is represented by single sysfs_dirent. Most fields are | ||
75 | * private to kernfs and shouldn't be accessed directly by kernfs users. | ||
76 | * | ||
77 | * As long as s_count reference is held, the sysfs_dirent itself is | ||
78 | * accessible. Dereferencing s_elem or any other outer entity | ||
79 | * requires s_active reference. | ||
80 | */ | ||
81 | struct sysfs_dirent { | ||
82 | atomic_t s_count; | ||
83 | atomic_t s_active; | ||
84 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
85 | struct lockdep_map dep_map; | ||
86 | #endif | ||
87 | /* the following two fields are published */ | ||
88 | struct sysfs_dirent *s_parent; | ||
89 | const char *s_name; | ||
90 | |||
91 | struct rb_node s_rb; | ||
92 | |||
93 | union { | ||
94 | struct completion *completion; | ||
95 | struct sysfs_dirent *removed_list; | ||
96 | } u; | ||
97 | |||
98 | const void *s_ns; /* namespace tag */ | ||
99 | unsigned int s_hash; /* ns + name hash */ | ||
100 | union { | ||
101 | struct sysfs_elem_dir s_dir; | ||
102 | struct sysfs_elem_symlink s_symlink; | ||
103 | struct sysfs_elem_attr s_attr; | ||
104 | }; | ||
105 | |||
106 | void *priv; | ||
107 | |||
108 | unsigned short s_flags; | ||
109 | umode_t s_mode; | ||
110 | unsigned int s_ino; | ||
111 | struct sysfs_inode_attrs *s_iattr; | ||
112 | }; | ||
25 | 113 | ||
26 | struct kernfs_root { | 114 | struct kernfs_root { |
27 | /* published fields */ | 115 | /* published fields */ |
@@ -82,6 +170,26 @@ struct kernfs_ops { | |||
82 | 170 | ||
83 | #ifdef CONFIG_SYSFS | 171 | #ifdef CONFIG_SYSFS |
84 | 172 | ||
173 | static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) | ||
174 | { | ||
175 | return sd->s_flags & SYSFS_TYPE_MASK; | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * kernfs_enable_ns - enable namespace under a directory | ||
180 | * @sd: directory of interest, should be empty | ||
181 | * | ||
182 | * This is to be called right after @sd is created to enable namespace | ||
183 | * under it. All children of @sd must have non-NULL namespace tags and | ||
184 | * only the ones which match the super_block's tag will be visible. | ||
185 | */ | ||
186 | static inline void kernfs_enable_ns(struct sysfs_dirent *sd) | ||
187 | { | ||
188 | WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); | ||
189 | WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); | ||
190 | sd->s_flags |= SYSFS_FLAG_NS; | ||
191 | } | ||
192 | |||
85 | struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, | 193 | struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, |
86 | const char *name, const void *ns); | 194 | const char *name, const void *ns); |
87 | void kernfs_get(struct sysfs_dirent *sd); | 195 | void kernfs_get(struct sysfs_dirent *sd); |
@@ -107,7 +215,6 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, | |||
107 | const void *ns); | 215 | const void *ns); |
108 | int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, | 216 | int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, |
109 | const char *new_name, const void *new_ns); | 217 | const char *new_name, const void *new_ns); |
110 | void kernfs_enable_ns(struct sysfs_dirent *sd); | ||
111 | int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); | 218 | int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); |
112 | void kernfs_notify(struct sysfs_dirent *sd); | 219 | void kernfs_notify(struct sysfs_dirent *sd); |
113 | 220 | ||
@@ -120,6 +227,11 @@ void kernfs_init(void); | |||
120 | 227 | ||
121 | #else /* CONFIG_SYSFS */ | 228 | #else /* CONFIG_SYSFS */ |
122 | 229 | ||
230 | static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) | ||
231 | { return 0; } /* whatever */ | ||
232 | |||
233 | static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } | ||
234 | |||
123 | static inline struct sysfs_dirent * | 235 | static inline struct sysfs_dirent * |
124 | kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, | 236 | kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, |
125 | const void *ns) | 237 | const void *ns) |
@@ -161,8 +273,6 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd, | |||
161 | const char *new_name, const void *new_ns) | 273 | const char *new_name, const void *new_ns) |
162 | { return -ENOSYS; } | 274 | { return -ENOSYS; } |
163 | 275 | ||
164 | static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } | ||
165 | |||
166 | static inline int kernfs_setattr(struct sysfs_dirent *sd, | 276 | static inline int kernfs_setattr(struct sysfs_dirent *sd, |
167 | const struct iattr *iattr) | 277 | const struct iattr *iattr) |
168 | { return -ENOSYS; } | 278 | { return -ENOSYS; } |