aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs/mount.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/kernfs/mount.c')
-rw-r--r--fs/kernfs/mount.c69
1 files changed, 69 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);