diff options
author | Tejun Heo <tj@kernel.org> | 2014-02-07 13:32:07 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-07 19:05:35 -0500 |
commit | 3eef34ad7dc369b7183ec383908aff3da2f6e5ec (patch) | |
tree | fac6ef1dd497adeff55fae499d953d5d51061867 /include/linux/kernfs.h | |
parent | 0c23b2259a4850494e2c53e864ea840597c6cdd3 (diff) |
kernfs: implement kernfs_get_parent(), kernfs_name/path() and friends
kernfs_node->parent and ->name are currently marked as "published"
indicating that kernfs users may access them directly; however, those
fields may get updated by kernfs_rename[_ns]() and unrestricted access
may lead to erroneous values or oops.
Protect ->parent and ->name updates with a irq-safe spinlock
kernfs_rename_lock and implement the following accessors for these
fields.
* kernfs_name() - format the node's name into the specified buffer
* kernfs_path() - format the node's path into the specified buffer
* pr_cont_kernfs_name() - pr_cont a node's name (doesn't need buffer)
* pr_cont_kernfs_path() - pr_cont a node's path (doesn't need buffer)
* kernfs_get_parent() - pin and return a node's parent
All can be called under any context. The recursive sysfs_pathname()
in fs/sysfs/dir.c is replaced with kernfs_path() and
sysfs_rename_dir_ns() is updated to use kernfs_get_parent() instead of
dereferencing parent directly.
v2: Dummy definition of kernfs_path() for !CONFIG_KERNFS was missing
static inline making it cause a lot of build warnings. Add it.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include/linux/kernfs.h')
-rw-r--r-- | include/linux/kernfs.h | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 9c899040c05e..8736ee86a1d6 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
@@ -91,7 +91,12 @@ struct kernfs_node { | |||
91 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 91 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
92 | struct lockdep_map dep_map; | 92 | struct lockdep_map dep_map; |
93 | #endif | 93 | #endif |
94 | /* the following two fields are published */ | 94 | /* |
95 | * Use kernfs_get_parent() and kernfs_name/path() instead of | ||
96 | * accessing the following two fields directly. If the node is | ||
97 | * never moved to a different parent, it is safe to access the | ||
98 | * parent directly. | ||
99 | */ | ||
95 | struct kernfs_node *parent; | 100 | struct kernfs_node *parent; |
96 | const char *name; | 101 | const char *name; |
97 | 102 | ||
@@ -229,6 +234,12 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) | |||
229 | return kn->flags & KERNFS_NS; | 234 | return kn->flags & KERNFS_NS; |
230 | } | 235 | } |
231 | 236 | ||
237 | int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen); | ||
238 | char * __must_check kernfs_path(struct kernfs_node *kn, char *buf, | ||
239 | size_t buflen); | ||
240 | void pr_cont_kernfs_name(struct kernfs_node *kn); | ||
241 | void pr_cont_kernfs_path(struct kernfs_node *kn); | ||
242 | struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); | ||
232 | struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, | 243 | struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, |
233 | const char *name, const void *ns); | 244 | const char *name, const void *ns); |
234 | void kernfs_get(struct kernfs_node *kn); | 245 | void kernfs_get(struct kernfs_node *kn); |
@@ -283,6 +294,19 @@ static inline void kernfs_enable_ns(struct kernfs_node *kn) { } | |||
283 | static inline bool kernfs_ns_enabled(struct kernfs_node *kn) | 294 | static inline bool kernfs_ns_enabled(struct kernfs_node *kn) |
284 | { return false; } | 295 | { return false; } |
285 | 296 | ||
297 | static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) | ||
298 | { return -ENOSYS; } | ||
299 | |||
300 | static inline char * __must_check kernfs_path(struct kernfs_node *kn, char *buf, | ||
301 | size_t buflen) | ||
302 | { return NULL; } | ||
303 | |||
304 | static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { } | ||
305 | static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { } | ||
306 | |||
307 | static inline struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) | ||
308 | { return NULL; } | ||
309 | |||
286 | static inline struct kernfs_node * | 310 | static inline struct kernfs_node * |
287 | kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, | 311 | kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, |
288 | const void *ns) | 312 | const void *ns) |