Blame view

fs/kernfs/mount.c 9.56 KB
55716d264   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
b8441ed27   Tejun Heo   sysfs, kernfs: ad...
2
3
4
5
6
7
  /*
   * fs/kernfs/mount.c - kernfs mount implementation
   *
   * Copyright (c) 2001-3 Patrick Mochel
   * Copyright (c) 2007 SUSE Linux Products GmbH
   * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org>
b8441ed27   Tejun Heo   sysfs, kernfs: ad...
8
   */
fa736a951   Tejun Heo   sysfs, kernfs: mo...
9
10
11
12
13
14
15
  
  #include <linux/fs.h>
  #include <linux/mount.h>
  #include <linux/init.h>
  #include <linux/magic.h>
  #include <linux/slab.h>
  #include <linux/pagemap.h>
fb3c83156   Aditya Kali   kernfs: define ke...
16
  #include <linux/namei.h>
4f41fc596   Serge E. Hallyn   cgroup, kernfs: m...
17
  #include <linux/seq_file.h>
aa8188253   Shaohua Li   kernfs: add expor...
18
  #include <linux/exportfs.h>
fa736a951   Tejun Heo   sysfs, kernfs: mo...
19
20
  
  #include "kernfs-internal.h"
26e28d68b   Ayush Mittal   kernfs: Allocatin...
21
  struct kmem_cache *kernfs_node_cache, *kernfs_iattrs_cache;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
22

6a7fed4ee   Tejun Heo   kernfs: implement...
23
24
  static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry)
  {
319ba91d3   Shaohua Li   kernfs: don't set...
25
  	struct kernfs_root *root = kernfs_root(kernfs_dentry_node(dentry));
6a7fed4ee   Tejun Heo   kernfs: implement...
26
27
28
29
30
31
  	struct kernfs_syscall_ops *scops = root->syscall_ops;
  
  	if (scops && scops->show_options)
  		return scops->show_options(sf, root);
  	return 0;
  }
4f41fc596   Serge E. Hallyn   cgroup, kernfs: m...
32
33
  static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
  {
319ba91d3   Shaohua Li   kernfs: don't set...
34
  	struct kernfs_node *node = kernfs_dentry_node(dentry);
4f41fc596   Serge E. Hallyn   cgroup, kernfs: m...
35
36
37
38
39
  	struct kernfs_root *root = kernfs_root(node);
  	struct kernfs_syscall_ops *scops = root->syscall_ops;
  
  	if (scops && scops->show_path)
  		return scops->show_path(sf, node, root);
3cc9b23c8   Serge E. Hallyn   kernfs: kernfs_so...
40
41
42
  	seq_dentry(sf, dentry, " \t
  \\");
  	return 0;
4f41fc596   Serge E. Hallyn   cgroup, kernfs: m...
43
  }
f41c59345   Li Zefan   kernfs: fix kernf...
44
  const struct super_operations kernfs_sops = {
fa736a951   Tejun Heo   sysfs, kernfs: mo...
45
46
  	.statfs		= simple_statfs,
  	.drop_inode	= generic_delete_inode,
c637b8acb   Tejun Heo   kernfs: s/sysfs/k...
47
  	.evict_inode	= kernfs_evict_inode,
6a7fed4ee   Tejun Heo   kernfs: implement...
48

6a7fed4ee   Tejun Heo   kernfs: implement...
49
  	.show_options	= kernfs_sop_show_options,
4f41fc596   Serge E. Hallyn   cgroup, kernfs: m...
50
  	.show_path	= kernfs_sop_show_path,
fa736a951   Tejun Heo   sysfs, kernfs: mo...
51
  };
33c5ac917   Tejun Heo   kernfs: implement...
52
53
  static int kernfs_encode_fh(struct inode *inode, __u32 *fh, int *max_len,
  			    struct inode *parent)
aa8188253   Shaohua Li   kernfs: add expor...
54
  {
33c5ac917   Tejun Heo   kernfs: implement...
55
  	struct kernfs_node *kn = inode->i_private;
aa8188253   Shaohua Li   kernfs: add expor...
56

33c5ac917   Tejun Heo   kernfs: implement...
57
58
59
60
  	if (*max_len < 2) {
  		*max_len = 2;
  		return FILEID_INVALID;
  	}
aa8188253   Shaohua Li   kernfs: add expor...
61

33c5ac917   Tejun Heo   kernfs: implement...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  	*max_len = 2;
  	*(u64 *)fh = kn->id;
  	return FILEID_KERNFS;
  }
  
  static struct dentry *__kernfs_fh_to_dentry(struct super_block *sb,
  					    struct fid *fid, int fh_len,
  					    int fh_type, bool get_parent)
  {
  	struct kernfs_super_info *info = kernfs_info(sb);
  	struct kernfs_node *kn;
  	struct inode *inode;
  	u64 id;
  
  	if (fh_len < 2)
  		return NULL;
  
  	switch (fh_type) {
  	case FILEID_KERNFS:
  		id = *(u64 *)fid;
  		break;
  	case FILEID_INO32_GEN:
  	case FILEID_INO32_GEN_PARENT:
  		/*
40430452f   Tejun Heo   kernfs: use 64bit...
86
87
88
89
  		 * blk_log_action() exposes "LOW32,HIGH32" pair without
  		 * type and userland can call us with generic fid
  		 * constructed from them.  Combine it back to ID.  See
  		 * blk_log_action().
33c5ac917   Tejun Heo   kernfs: implement...
90
91
92
93
94
95
96
97
  		 */
  		id = ((u64)fid->i32.gen << 32) | fid->i32.ino;
  		break;
  	default:
  		return NULL;
  	}
  
  	kn = kernfs_find_and_get_node_by_id(info->root, id);
aa8188253   Shaohua Li   kernfs: add expor...
98
99
  	if (!kn)
  		return ERR_PTR(-ESTALE);
33c5ac917   Tejun Heo   kernfs: implement...
100
101
102
103
104
105
106
107
108
109
  
  	if (get_parent) {
  		struct kernfs_node *parent;
  
  		parent = kernfs_get_parent(kn);
  		kernfs_put(kn);
  		kn = parent;
  		if (!kn)
  			return ERR_PTR(-ESTALE);
  	}
aa8188253   Shaohua Li   kernfs: add expor...
110
111
  	inode = kernfs_get_inode(sb, kn);
  	kernfs_put(kn);
ef13ecbc1   Dan Carpenter   kernfs: checking ...
112
113
  	if (!inode)
  		return ERR_PTR(-ESTALE);
aa8188253   Shaohua Li   kernfs: add expor...
114

33c5ac917   Tejun Heo   kernfs: implement...
115
  	return d_obtain_alias(inode);
aa8188253   Shaohua Li   kernfs: add expor...
116
  }
33c5ac917   Tejun Heo   kernfs: implement...
117
118
119
  static struct dentry *kernfs_fh_to_dentry(struct super_block *sb,
  					  struct fid *fid, int fh_len,
  					  int fh_type)
aa8188253   Shaohua Li   kernfs: add expor...
120
  {
33c5ac917   Tejun Heo   kernfs: implement...
121
  	return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, false);
aa8188253   Shaohua Li   kernfs: add expor...
122
  }
33c5ac917   Tejun Heo   kernfs: implement...
123
124
125
  static struct dentry *kernfs_fh_to_parent(struct super_block *sb,
  					  struct fid *fid, int fh_len,
  					  int fh_type)
aa8188253   Shaohua Li   kernfs: add expor...
126
  {
33c5ac917   Tejun Heo   kernfs: implement...
127
  	return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, true);
aa8188253   Shaohua Li   kernfs: add expor...
128
129
130
131
132
133
134
135
136
137
  }
  
  static struct dentry *kernfs_get_parent_dentry(struct dentry *child)
  {
  	struct kernfs_node *kn = kernfs_dentry_node(child);
  
  	return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent));
  }
  
  static const struct export_operations kernfs_export_ops = {
33c5ac917   Tejun Heo   kernfs: implement...
138
  	.encode_fh	= kernfs_encode_fh,
aa8188253   Shaohua Li   kernfs: add expor...
139
140
141
142
  	.fh_to_dentry	= kernfs_fh_to_dentry,
  	.fh_to_parent	= kernfs_fh_to_parent,
  	.get_parent	= kernfs_get_parent_dentry,
  };
0c23b2259   Tejun Heo   kernfs: implement...
143
144
145
146
147
148
149
150
151
152
153
154
155
  /**
   * kernfs_root_from_sb - determine kernfs_root associated with a super_block
   * @sb: the super_block in question
   *
   * Return the kernfs_root associated with @sb.  If @sb is not a kernfs one,
   * %NULL is returned.
   */
  struct kernfs_root *kernfs_root_from_sb(struct super_block *sb)
  {
  	if (sb->s_op == &kernfs_sops)
  		return kernfs_info(sb)->root;
  	return NULL;
  }
fb3c83156   Aditya Kali   kernfs: define ke...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  /*
   * find the next ancestor in the path down to @child, where @parent was the
   * ancestor whose descendant we want to find.
   *
   * Say the path is /a/b/c/d.  @child is d, @parent is NULL.  We return the root
   * node.  If @parent is b, then we return the node for c.
   * Passing in d as @parent is not ok.
   */
  static struct kernfs_node *find_next_ancestor(struct kernfs_node *child,
  					      struct kernfs_node *parent)
  {
  	if (child == parent) {
  		pr_crit_once("BUG in find_next_ancestor: called with parent == child");
  		return NULL;
  	}
  
  	while (child->parent != parent) {
  		if (!child->parent)
  			return NULL;
  		child = child->parent;
  	}
  
  	return child;
  }
  
  /**
   * kernfs_node_dentry - get a dentry for the given kernfs_node
   * @kn: kernfs_node for which a dentry is needed
   * @sb: the kernfs super_block
   */
  struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
  				  struct super_block *sb)
  {
  	struct dentry *dentry;
  	struct kernfs_node *knparent = NULL;
  
  	BUG_ON(sb->s_op != &kernfs_sops);
  
  	dentry = dget(sb->s_root);
  
  	/* Check if this is the root kernfs_node */
  	if (!kn->parent)
  		return dentry;
  
  	knparent = find_next_ancestor(kn, NULL);
399504e21   Al Viro   fix cgroup_do_mou...
201
202
  	if (WARN_ON(!knparent)) {
  		dput(dentry);
fb3c83156   Aditya Kali   kernfs: define ke...
203
  		return ERR_PTR(-EINVAL);
399504e21   Al Viro   fix cgroup_do_mou...
204
  	}
fb3c83156   Aditya Kali   kernfs: define ke...
205
206
207
208
209
210
211
212
  
  	do {
  		struct dentry *dtmp;
  		struct kernfs_node *kntmp;
  
  		if (kn == knparent)
  			return dentry;
  		kntmp = find_next_ancestor(kn, knparent);
399504e21   Al Viro   fix cgroup_do_mou...
213
214
  		if (WARN_ON(!kntmp)) {
  			dput(dentry);
fb3c83156   Aditya Kali   kernfs: define ke...
215
  			return ERR_PTR(-EINVAL);
399504e21   Al Viro   fix cgroup_do_mou...
216
  		}
6c2d4798a   Al Viro   new helper: looku...
217
  		dtmp = lookup_positive_unlocked(kntmp->name, dentry,
779b83913   Al Viro   kernfs: use looku...
218
  					       strlen(kntmp->name));
fb3c83156   Aditya Kali   kernfs: define ke...
219
220
221
222
223
224
225
  		dput(dentry);
  		if (IS_ERR(dtmp))
  			return dtmp;
  		knparent = kntmp;
  		dentry = dtmp;
  	} while (true);
  }
23bf1b6be   David Howells   kernfs, sysfs, cg...
226
  static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *kfc)
fa736a951   Tejun Heo   sysfs, kernfs: mo...
227
  {
c525aaddc   Tejun Heo   kernfs: s/sysfs/k...
228
  	struct kernfs_super_info *info = kernfs_info(sb);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
229
230
  	struct inode *inode;
  	struct dentry *root;
7d568a838   Tejun Heo   kernfs: implement...
231
  	info->sb = sb;
a2982cc92   Eric W. Biederman   vfs: Generalize f...
232
233
  	/* Userspace would break if executables or devices appear on sysfs */
  	sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
234
235
  	sb->s_blocksize = PAGE_SIZE;
  	sb->s_blocksize_bits = PAGE_SHIFT;
23bf1b6be   David Howells   kernfs, sysfs, cg...
236
  	sb->s_magic = kfc->magic;
a797bfc30   Tejun Heo   kernfs: s/sysfs/k...
237
  	sb->s_op = &kernfs_sops;
e72a1a8b3   Andreas Gruenbacher   kernfs: Switch to...
238
  	sb->s_xattr = kernfs_xattr_handlers;
aa8188253   Shaohua Li   kernfs: add expor...
239
240
  	if (info->root->flags & KERNFS_ROOT_SUPPORT_EXPORTOP)
  		sb->s_export_op = &kernfs_export_ops;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
241
  	sb->s_time_gran = 1;
4b85afbda   Johannes Weiner   mm: zero-seek shr...
242
243
  	/* sysfs dentries and inodes don't require IO to create */
  	sb->s_shrink.seeks = 0;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
244
  	/* get root inode, initialize and unlock it */
a797bfc30   Tejun Heo   kernfs: s/sysfs/k...
245
  	mutex_lock(&kernfs_mutex);
c637b8acb   Tejun Heo   kernfs: s/sysfs/k...
246
  	inode = kernfs_get_inode(sb, info->root->kn);
a797bfc30   Tejun Heo   kernfs: s/sysfs/k...
247
  	mutex_unlock(&kernfs_mutex);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
248
  	if (!inode) {
c637b8acb   Tejun Heo   kernfs: s/sysfs/k...
249
250
  		pr_debug("kernfs: could not get root inode
  ");
fa736a951   Tejun Heo   sysfs, kernfs: mo...
251
252
253
254
255
256
257
258
259
260
  		return -ENOMEM;
  	}
  
  	/* instantiate and link root dentry */
  	root = d_make_root(inode);
  	if (!root) {
  		pr_debug("%s: could not get root dentry!
  ", __func__);
  		return -ENOMEM;
  	}
fa736a951   Tejun Heo   sysfs, kernfs: mo...
261
  	sb->s_root = root;
a797bfc30   Tejun Heo   kernfs: s/sysfs/k...
262
  	sb->s_d_op = &kernfs_dops;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
263
264
  	return 0;
  }
23bf1b6be   David Howells   kernfs, sysfs, cg...
265
  static int kernfs_test_super(struct super_block *sb, struct fs_context *fc)
fa736a951   Tejun Heo   sysfs, kernfs: mo...
266
  {
c525aaddc   Tejun Heo   kernfs: s/sysfs/k...
267
  	struct kernfs_super_info *sb_info = kernfs_info(sb);
23bf1b6be   David Howells   kernfs, sysfs, cg...
268
  	struct kernfs_super_info *info = fc->s_fs_info;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
269
270
271
  
  	return sb_info->root == info->root && sb_info->ns == info->ns;
  }
23bf1b6be   David Howells   kernfs, sysfs, cg...
272
  static int kernfs_set_super(struct super_block *sb, struct fs_context *fc)
fa736a951   Tejun Heo   sysfs, kernfs: mo...
273
  {
23bf1b6be   David Howells   kernfs, sysfs, cg...
274
275
276
277
  	struct kernfs_fs_context *kfc = fc->fs_private;
  
  	kfc->ns_tag = NULL;
  	return set_anon_super_fc(sb, fc);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
278
279
280
281
282
283
284
285
286
287
  }
  
  /**
   * kernfs_super_ns - determine the namespace tag of a kernfs super_block
   * @sb: super_block of interest
   *
   * Return the namespace tag associated with kernfs super_block @sb.
   */
  const void *kernfs_super_ns(struct super_block *sb)
  {
c525aaddc   Tejun Heo   kernfs: s/sysfs/k...
288
  	struct kernfs_super_info *info = kernfs_info(sb);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
289
290
291
292
293
  
  	return info->ns;
  }
  
  /**
23bf1b6be   David Howells   kernfs, sysfs, cg...
294
295
   * kernfs_get_tree - kernfs filesystem access/retrieval helper
   * @fc: The filesystem context.
fa736a951   Tejun Heo   sysfs, kernfs: mo...
296
   *
23bf1b6be   David Howells   kernfs, sysfs, cg...
297
298
299
300
   * This is to be called from each kernfs user's fs_context->ops->get_tree()
   * implementation, which should set the specified ->@fs_type and ->@flags, and
   * specify the hierarchy and namespace tag to mount via ->@root and ->@ns,
   * respectively.
fa736a951   Tejun Heo   sysfs, kernfs: mo...
301
   */
23bf1b6be   David Howells   kernfs, sysfs, cg...
302
  int kernfs_get_tree(struct fs_context *fc)
fa736a951   Tejun Heo   sysfs, kernfs: mo...
303
  {
23bf1b6be   David Howells   kernfs, sysfs, cg...
304
  	struct kernfs_fs_context *kfc = fc->fs_private;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
305
  	struct super_block *sb;
c525aaddc   Tejun Heo   kernfs: s/sysfs/k...
306
  	struct kernfs_super_info *info;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
307
308
309
310
  	int error;
  
  	info = kzalloc(sizeof(*info), GFP_KERNEL);
  	if (!info)
23bf1b6be   David Howells   kernfs, sysfs, cg...
311
  		return -ENOMEM;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
312

23bf1b6be   David Howells   kernfs, sysfs, cg...
313
314
  	info->root = kfc->root;
  	info->ns = kfc->ns_tag;
82382acec   Al Viro   kernfs: deal with...
315
  	INIT_LIST_HEAD(&info->node);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
316

23bf1b6be   David Howells   kernfs, sysfs, cg...
317
318
  	fc->s_fs_info = info;
  	sb = sget_fc(fc, kernfs_test_super, kernfs_set_super);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
319
  	if (IS_ERR(sb))
23bf1b6be   David Howells   kernfs, sysfs, cg...
320
  		return PTR_ERR(sb);
fed95bab8   Li Zefan   sysfs: fix namesp...
321

fa736a951   Tejun Heo   sysfs, kernfs: mo...
322
  	if (!sb->s_root) {
7d568a838   Tejun Heo   kernfs: implement...
323
  		struct kernfs_super_info *info = kernfs_info(sb);
23bf1b6be   David Howells   kernfs, sysfs, cg...
324
325
326
  		kfc->new_sb_created = true;
  
  		error = kernfs_fill_super(sb, kfc);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
327
328
  		if (error) {
  			deactivate_locked_super(sb);
23bf1b6be   David Howells   kernfs, sysfs, cg...
329
  			return error;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
330
  		}
1751e8a6c   Linus Torvalds   Rename superblock...
331
  		sb->s_flags |= SB_ACTIVE;
7d568a838   Tejun Heo   kernfs: implement...
332
333
  
  		mutex_lock(&kernfs_mutex);
23bf1b6be   David Howells   kernfs, sysfs, cg...
334
  		list_add(&info->node, &info->root->supers);
7d568a838   Tejun Heo   kernfs: implement...
335
  		mutex_unlock(&kernfs_mutex);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
336
  	}
23bf1b6be   David Howells   kernfs, sysfs, cg...
337
338
339
340
341
342
343
344
345
  	fc->root = dget(sb->s_root);
  	return 0;
  }
  
  void kernfs_free_fs_context(struct fs_context *fc)
  {
  	/* Note that we don't deal with kfc->ns_tag here. */
  	kfree(fc->s_fs_info);
  	fc->s_fs_info = NULL;
fa736a951   Tejun Heo   sysfs, kernfs: mo...
346
347
348
349
350
351
352
353
354
355
356
357
  }
  
  /**
   * kernfs_kill_sb - kill_sb for kernfs
   * @sb: super_block being killed
   *
   * This can be used directly for file_system_type->kill_sb().  If a kernfs
   * user needs extra cleanup, it can implement its own kill_sb() and call
   * this function at the end.
   */
  void kernfs_kill_sb(struct super_block *sb)
  {
c525aaddc   Tejun Heo   kernfs: s/sysfs/k...
358
  	struct kernfs_super_info *info = kernfs_info(sb);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
359

7d568a838   Tejun Heo   kernfs: implement...
360
361
362
  	mutex_lock(&kernfs_mutex);
  	list_del(&info->node);
  	mutex_unlock(&kernfs_mutex);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
363
364
  	/*
  	 * Remove the superblock from fs_supers/s_instances
c525aaddc   Tejun Heo   kernfs: s/sysfs/k...
365
  	 * so we can't find it, before freeing kernfs_super_info.
fa736a951   Tejun Heo   sysfs, kernfs: mo...
366
367
368
  	 */
  	kill_anon_super(sb);
  	kfree(info);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
369
370
371
372
  }
  
  void __init kernfs_init(void)
  {
a797bfc30   Tejun Heo   kernfs: s/sysfs/k...
373
  	kernfs_node_cache = kmem_cache_create("kernfs_node_cache",
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
374
  					      sizeof(struct kernfs_node),
b680b0817   Tejun Heo   kernfs: use dumbe...
375
  					      0, SLAB_PANIC, NULL);
26e28d68b   Ayush Mittal   kernfs: Allocatin...
376
377
378
379
380
  
  	/* Creates slab cache for kernfs inode attributes */
  	kernfs_iattrs_cache  = kmem_cache_create("kernfs_iattrs_cache",
  					      sizeof(struct kernfs_iattrs),
  					      0, SLAB_PANIC, NULL);
fa736a951   Tejun Heo   sysfs, kernfs: mo...
381
  }