diff options
author | Tejun Heo <tj@kernel.org> | 2015-11-20 15:55:52 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2015-11-20 15:55:52 -0500 |
commit | bd96f76a2454c6b97d70945902e30b4c31510678 (patch) | |
tree | 6700838f83e76e2558f9a36742acf81b589d3d38 | |
parent | b11cfb5807e30333b36c02701382b820b7dcf0d5 (diff) |
kernfs: implement kernfs_walk_and_get()
Implement kernfs_walk_and_get() which is similar to
kernfs_find_and_get() but can walk a path instead of just a name.
v2: Use strlcpy() instead of strlen() + memcpy() as suggested by
David.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: David Miller <davem@davemloft.net>
-rw-r--r-- | fs/kernfs/dir.c | 46 | ||||
-rw-r--r-- | include/linux/kernfs.h | 12 |
2 files changed, 58 insertions, 0 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 91e004518237..742bf4a230e8 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c | |||
@@ -694,6 +694,29 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, | |||
694 | return NULL; | 694 | return NULL; |
695 | } | 695 | } |
696 | 696 | ||
697 | static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent, | ||
698 | const unsigned char *path, | ||
699 | const void *ns) | ||
700 | { | ||
701 | static char path_buf[PATH_MAX]; /* protected by kernfs_mutex */ | ||
702 | size_t len = strlcpy(path_buf, path, PATH_MAX); | ||
703 | char *p = path_buf; | ||
704 | char *name; | ||
705 | |||
706 | lockdep_assert_held(&kernfs_mutex); | ||
707 | |||
708 | if (len >= PATH_MAX) | ||
709 | return NULL; | ||
710 | |||
711 | while ((name = strsep(&p, "/")) && parent) { | ||
712 | if (*name == '\0') | ||
713 | continue; | ||
714 | parent = kernfs_find_ns(parent, name, ns); | ||
715 | } | ||
716 | |||
717 | return parent; | ||
718 | } | ||
719 | |||
697 | /** | 720 | /** |
698 | * kernfs_find_and_get_ns - find and get kernfs_node with the given name | 721 | * kernfs_find_and_get_ns - find and get kernfs_node with the given name |
699 | * @parent: kernfs_node to search under | 722 | * @parent: kernfs_node to search under |
@@ -719,6 +742,29 @@ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, | |||
719 | EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); | 742 | EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); |
720 | 743 | ||
721 | /** | 744 | /** |
745 | * kernfs_walk_and_get_ns - find and get kernfs_node with the given path | ||
746 | * @parent: kernfs_node to search under | ||
747 | * @path: path to look for | ||
748 | * @ns: the namespace tag to use | ||
749 | * | ||
750 | * Look for kernfs_node with path @path under @parent and get a reference | ||
751 | * if found. This function may sleep and returns pointer to the found | ||
752 | * kernfs_node on success, %NULL on failure. | ||
753 | */ | ||
754 | struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, | ||
755 | const char *path, const void *ns) | ||
756 | { | ||
757 | struct kernfs_node *kn; | ||
758 | |||
759 | mutex_lock(&kernfs_mutex); | ||
760 | kn = kernfs_walk_ns(parent, path, ns); | ||
761 | kernfs_get(kn); | ||
762 | mutex_unlock(&kernfs_mutex); | ||
763 | |||
764 | return kn; | ||
765 | } | ||
766 | |||
767 | /** | ||
722 | * kernfs_create_root - create a new kernfs hierarchy | 768 | * kernfs_create_root - create a new kernfs hierarchy |
723 | * @scops: optional syscall operations for the hierarchy | 769 | * @scops: optional syscall operations for the hierarchy |
724 | * @flags: KERNFS_ROOT_* flags | 770 | * @flags: KERNFS_ROOT_* flags |
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 5d4e9c4b821d..af51df35d749 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
@@ -274,6 +274,8 @@ void pr_cont_kernfs_path(struct kernfs_node *kn); | |||
274 | struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); | 274 | struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); |
275 | struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, | 275 | struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, |
276 | const char *name, const void *ns); | 276 | const char *name, const void *ns); |
277 | struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, | ||
278 | const char *path, const void *ns); | ||
277 | void kernfs_get(struct kernfs_node *kn); | 279 | void kernfs_get(struct kernfs_node *kn); |
278 | void kernfs_put(struct kernfs_node *kn); | 280 | void kernfs_put(struct kernfs_node *kn); |
279 | 281 | ||
@@ -350,6 +352,10 @@ static inline struct kernfs_node * | |||
350 | kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, | 352 | kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, |
351 | const void *ns) | 353 | const void *ns) |
352 | { return NULL; } | 354 | { return NULL; } |
355 | static inline struct kernfs_node * | ||
356 | kernfs_walk_and_get_ns(struct kernfs_node *parent, const char *path, | ||
357 | const void *ns) | ||
358 | { return NULL; } | ||
353 | 359 | ||
354 | static inline void kernfs_get(struct kernfs_node *kn) { } | 360 | static inline void kernfs_get(struct kernfs_node *kn) { } |
355 | static inline void kernfs_put(struct kernfs_node *kn) { } | 361 | static inline void kernfs_put(struct kernfs_node *kn) { } |
@@ -431,6 +437,12 @@ kernfs_find_and_get(struct kernfs_node *kn, const char *name) | |||
431 | } | 437 | } |
432 | 438 | ||
433 | static inline struct kernfs_node * | 439 | static inline struct kernfs_node * |
440 | kernfs_walk_and_get(struct kernfs_node *kn, const char *path) | ||
441 | { | ||
442 | return kernfs_walk_and_get_ns(kn, path, NULL); | ||
443 | } | ||
444 | |||
445 | static inline struct kernfs_node * | ||
434 | kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode, | 446 | kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode, |
435 | void *priv) | 447 | void *priv) |
436 | { | 448 | { |