summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAditya Kali <adityakali@google.com>2016-01-29 03:54:08 -0500
committerTejun Heo <tj@kernel.org>2016-02-16 13:04:58 -0500
commitfb3c8315650f89a1993fb3ae3e74e9c7e4a1c9c0 (patch)
tree29772e52c73463ec3bd1f2c3b3c956ceaf143071
parenta0530e087e648263f81a81d62ca020f66b54bcb0 (diff)
kernfs: define kernfs_node_dentry
Add a new kernfs api is added to lookup the dentry for a particular kernfs path. Signed-off-by: Aditya Kali <adityakali@google.com> Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--fs/kernfs/mount.c69
-rw-r--r--include/linux/kernfs.h2
2 files changed, 71 insertions, 0 deletions
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index 8eaf417187f1..b67dbccdaf88 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -14,6 +14,7 @@
14#include <linux/magic.h> 14#include <linux/magic.h>
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/pagemap.h> 16#include <linux/pagemap.h>
17#include <linux/namei.h>
17 18
18#include "kernfs-internal.h" 19#include "kernfs-internal.h"
19 20
@@ -62,6 +63,74 @@ struct kernfs_root *kernfs_root_from_sb(struct super_block *sb)
62 return NULL; 63 return NULL;
63} 64}
64 65
66/*
67 * find the next ancestor in the path down to @child, where @parent was the
68 * ancestor whose descendant we want to find.
69 *
70 * Say the path is /a/b/c/d. @child is d, @parent is NULL. We return the root
71 * node. If @parent is b, then we return the node for c.
72 * Passing in d as @parent is not ok.
73 */
74static struct kernfs_node *find_next_ancestor(struct kernfs_node *child,
75 struct kernfs_node *parent)
76{
77 if (child == parent) {
78 pr_crit_once("BUG in find_next_ancestor: called with parent == child");
79 return NULL;
80 }
81
82 while (child->parent != parent) {
83 if (!child->parent)
84 return NULL;
85 child = child->parent;
86 }
87
88 return child;
89}
90
91/**
92 * kernfs_node_dentry - get a dentry for the given kernfs_node
93 * @kn: kernfs_node for which a dentry is needed
94 * @sb: the kernfs super_block
95 */
96struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
97 struct super_block *sb)
98{
99 struct dentry *dentry;
100 struct kernfs_node *knparent = NULL;
101
102 BUG_ON(sb->s_op != &kernfs_sops);
103
104 dentry = dget(sb->s_root);
105
106 /* Check if this is the root kernfs_node */
107 if (!kn->parent)
108 return dentry;
109
110 knparent = find_next_ancestor(kn, NULL);
111 if (WARN_ON(!knparent))
112 return ERR_PTR(-EINVAL);
113
114 do {
115 struct dentry *dtmp;
116 struct kernfs_node *kntmp;
117
118 if (kn == knparent)
119 return dentry;
120 kntmp = find_next_ancestor(kn, knparent);
121 if (WARN_ON(!kntmp))
122 return ERR_PTR(-EINVAL);
123 mutex_lock(&d_inode(dentry)->i_mutex);
124 dtmp = lookup_one_len(kntmp->name, dentry, strlen(kntmp->name));
125 mutex_unlock(&d_inode(dentry)->i_mutex);
126 dput(dentry);
127 if (IS_ERR(dtmp))
128 return dtmp;
129 knparent = kntmp;
130 dentry = dtmp;
131 } while (true);
132}
133
65static int kernfs_fill_super(struct super_block *sb, unsigned long magic) 134static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
66{ 135{
67 struct kernfs_super_info *info = kernfs_info(sb); 136 struct kernfs_super_info *info = kernfs_info(sb);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 716bfdede5f5..c06c44242f39 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -284,6 +284,8 @@ struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry);
284struct kernfs_root *kernfs_root_from_sb(struct super_block *sb); 284struct kernfs_root *kernfs_root_from_sb(struct super_block *sb);
285struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn); 285struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn);
286 286
287struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
288 struct super_block *sb);
287struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, 289struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
288 unsigned int flags, void *priv); 290 unsigned int flags, void *priv);
289void kernfs_destroy_root(struct kernfs_root *root); 291void kernfs_destroy_root(struct kernfs_root *root);