aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-11-20 15:55:52 -0500
committerTejun Heo <tj@kernel.org>2015-11-20 15:55:52 -0500
commitbd96f76a2454c6b97d70945902e30b4c31510678 (patch)
tree6700838f83e76e2558f9a36742acf81b589d3d38
parentb11cfb5807e30333b36c02701382b820b7dcf0d5 (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.c46
-rw-r--r--include/linux/kernfs.h12
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
697static 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,
719EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); 742EXPORT_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 */
754struct 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);
274struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); 274struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
275struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, 275struct 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);
277struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent,
278 const char *path, const void *ns);
277void kernfs_get(struct kernfs_node *kn); 279void kernfs_get(struct kernfs_node *kn);
278void kernfs_put(struct kernfs_node *kn); 280void kernfs_put(struct kernfs_node *kn);
279 281
@@ -350,6 +352,10 @@ static inline struct kernfs_node *
350kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, 352kernfs_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; }
355static inline struct kernfs_node *
356kernfs_walk_and_get_ns(struct kernfs_node *parent, const char *path,
357 const void *ns)
358{ return NULL; }
353 359
354static inline void kernfs_get(struct kernfs_node *kn) { } 360static inline void kernfs_get(struct kernfs_node *kn) { }
355static inline void kernfs_put(struct kernfs_node *kn) { } 361static 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
433static inline struct kernfs_node * 439static inline struct kernfs_node *
440kernfs_walk_and_get(struct kernfs_node *kn, const char *path)
441{
442 return kernfs_walk_and_get_ns(kn, path, NULL);
443}
444
445static inline struct kernfs_node *
434kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode, 446kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode,
435 void *priv) 447 void *priv)
436{ 448{