.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * fs/kernfs/mount.c - kernfs mount implementation |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2001-3 Patrick Mochel |
---|
5 | 6 | * Copyright (c) 2007 SUSE Linux Products GmbH |
---|
6 | 7 | * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org> |
---|
7 | | - * |
---|
8 | | - * This file is released under the GPLv2. |
---|
9 | 8 | */ |
---|
10 | 9 | |
---|
11 | 10 | #include <linux/fs.h> |
---|
.. | .. |
---|
20 | 19 | |
---|
21 | 20 | #include "kernfs-internal.h" |
---|
22 | 21 | |
---|
23 | | -struct kmem_cache *kernfs_node_cache; |
---|
24 | | - |
---|
25 | | -static int kernfs_sop_remount_fs(struct super_block *sb, int *flags, char *data) |
---|
26 | | -{ |
---|
27 | | - struct kernfs_root *root = kernfs_info(sb)->root; |
---|
28 | | - struct kernfs_syscall_ops *scops = root->syscall_ops; |
---|
29 | | - |
---|
30 | | - if (scops && scops->remount_fs) |
---|
31 | | - return scops->remount_fs(root, flags, data); |
---|
32 | | - return 0; |
---|
33 | | -} |
---|
| 22 | +struct kmem_cache *kernfs_node_cache, *kernfs_iattrs_cache; |
---|
34 | 23 | |
---|
35 | 24 | static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry) |
---|
36 | 25 | { |
---|
.. | .. |
---|
60 | 49 | .drop_inode = generic_delete_inode, |
---|
61 | 50 | .evict_inode = kernfs_evict_inode, |
---|
62 | 51 | |
---|
63 | | - .remount_fs = kernfs_sop_remount_fs, |
---|
64 | 52 | .show_options = kernfs_sop_show_options, |
---|
65 | 53 | .show_path = kernfs_sop_show_path, |
---|
66 | 54 | }; |
---|
67 | 55 | |
---|
68 | | -/* |
---|
69 | | - * Similar to kernfs_fh_get_inode, this one gets kernfs node from inode |
---|
70 | | - * number and generation |
---|
71 | | - */ |
---|
72 | | -struct kernfs_node *kernfs_get_node_by_id(struct kernfs_root *root, |
---|
73 | | - const union kernfs_node_id *id) |
---|
| 56 | +static int kernfs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, |
---|
| 57 | + struct inode *parent) |
---|
74 | 58 | { |
---|
75 | | - struct kernfs_node *kn; |
---|
| 59 | + struct kernfs_node *kn = inode->i_private; |
---|
76 | 60 | |
---|
77 | | - kn = kernfs_find_and_get_node_by_ino(root, id->ino); |
---|
78 | | - if (!kn) |
---|
79 | | - return NULL; |
---|
80 | | - if (kn->id.generation != id->generation) { |
---|
81 | | - kernfs_put(kn); |
---|
82 | | - return NULL; |
---|
| 61 | + if (*max_len < 2) { |
---|
| 62 | + *max_len = 2; |
---|
| 63 | + return FILEID_INVALID; |
---|
83 | 64 | } |
---|
84 | | - return kn; |
---|
| 65 | + |
---|
| 66 | + *max_len = 2; |
---|
| 67 | + *(u64 *)fh = kn->id; |
---|
| 68 | + return FILEID_KERNFS; |
---|
85 | 69 | } |
---|
86 | 70 | |
---|
87 | | -static struct inode *kernfs_fh_get_inode(struct super_block *sb, |
---|
88 | | - u64 ino, u32 generation) |
---|
| 71 | +static struct dentry *__kernfs_fh_to_dentry(struct super_block *sb, |
---|
| 72 | + struct fid *fid, int fh_len, |
---|
| 73 | + int fh_type, bool get_parent) |
---|
89 | 74 | { |
---|
90 | 75 | struct kernfs_super_info *info = kernfs_info(sb); |
---|
91 | | - struct inode *inode; |
---|
92 | 76 | struct kernfs_node *kn; |
---|
| 77 | + struct inode *inode; |
---|
| 78 | + u64 id; |
---|
93 | 79 | |
---|
94 | | - if (ino == 0) |
---|
95 | | - return ERR_PTR(-ESTALE); |
---|
| 80 | + if (fh_len < 2) |
---|
| 81 | + return NULL; |
---|
96 | 82 | |
---|
97 | | - kn = kernfs_find_and_get_node_by_ino(info->root, ino); |
---|
| 83 | + switch (fh_type) { |
---|
| 84 | + case FILEID_KERNFS: |
---|
| 85 | + id = *(u64 *)fid; |
---|
| 86 | + break; |
---|
| 87 | + case FILEID_INO32_GEN: |
---|
| 88 | + case FILEID_INO32_GEN_PARENT: |
---|
| 89 | + /* |
---|
| 90 | + * blk_log_action() exposes "LOW32,HIGH32" pair without |
---|
| 91 | + * type and userland can call us with generic fid |
---|
| 92 | + * constructed from them. Combine it back to ID. See |
---|
| 93 | + * blk_log_action(). |
---|
| 94 | + */ |
---|
| 95 | + id = ((u64)fid->i32.gen << 32) | fid->i32.ino; |
---|
| 96 | + break; |
---|
| 97 | + default: |
---|
| 98 | + return NULL; |
---|
| 99 | + } |
---|
| 100 | + |
---|
| 101 | + kn = kernfs_find_and_get_node_by_id(info->root, id); |
---|
98 | 102 | if (!kn) |
---|
99 | 103 | return ERR_PTR(-ESTALE); |
---|
| 104 | + |
---|
| 105 | + if (get_parent) { |
---|
| 106 | + struct kernfs_node *parent; |
---|
| 107 | + |
---|
| 108 | + parent = kernfs_get_parent(kn); |
---|
| 109 | + kernfs_put(kn); |
---|
| 110 | + kn = parent; |
---|
| 111 | + if (!kn) |
---|
| 112 | + return ERR_PTR(-ESTALE); |
---|
| 113 | + } |
---|
| 114 | + |
---|
100 | 115 | inode = kernfs_get_inode(sb, kn); |
---|
101 | 116 | kernfs_put(kn); |
---|
102 | 117 | if (!inode) |
---|
103 | 118 | return ERR_PTR(-ESTALE); |
---|
104 | 119 | |
---|
105 | | - if (generation && inode->i_generation != generation) { |
---|
106 | | - /* we didn't find the right inode.. */ |
---|
107 | | - iput(inode); |
---|
108 | | - return ERR_PTR(-ESTALE); |
---|
109 | | - } |
---|
110 | | - return inode; |
---|
| 120 | + return d_obtain_alias(inode); |
---|
111 | 121 | } |
---|
112 | 122 | |
---|
113 | | -static struct dentry *kernfs_fh_to_dentry(struct super_block *sb, struct fid *fid, |
---|
114 | | - int fh_len, int fh_type) |
---|
| 123 | +static struct dentry *kernfs_fh_to_dentry(struct super_block *sb, |
---|
| 124 | + struct fid *fid, int fh_len, |
---|
| 125 | + int fh_type) |
---|
115 | 126 | { |
---|
116 | | - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, |
---|
117 | | - kernfs_fh_get_inode); |
---|
| 127 | + return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, false); |
---|
118 | 128 | } |
---|
119 | 129 | |
---|
120 | | -static struct dentry *kernfs_fh_to_parent(struct super_block *sb, struct fid *fid, |
---|
121 | | - int fh_len, int fh_type) |
---|
| 130 | +static struct dentry *kernfs_fh_to_parent(struct super_block *sb, |
---|
| 131 | + struct fid *fid, int fh_len, |
---|
| 132 | + int fh_type) |
---|
122 | 133 | { |
---|
123 | | - return generic_fh_to_parent(sb, fid, fh_len, fh_type, |
---|
124 | | - kernfs_fh_get_inode); |
---|
| 134 | + return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, true); |
---|
125 | 135 | } |
---|
126 | 136 | |
---|
127 | 137 | static struct dentry *kernfs_get_parent_dentry(struct dentry *child) |
---|
.. | .. |
---|
132 | 142 | } |
---|
133 | 143 | |
---|
134 | 144 | static const struct export_operations kernfs_export_ops = { |
---|
| 145 | + .encode_fh = kernfs_encode_fh, |
---|
135 | 146 | .fh_to_dentry = kernfs_fh_to_dentry, |
---|
136 | 147 | .fh_to_parent = kernfs_fh_to_parent, |
---|
137 | 148 | .get_parent = kernfs_get_parent_dentry, |
---|
.. | .. |
---|
212 | 223 | dput(dentry); |
---|
213 | 224 | return ERR_PTR(-EINVAL); |
---|
214 | 225 | } |
---|
215 | | - dtmp = lookup_one_len_unlocked(kntmp->name, dentry, |
---|
| 226 | + dtmp = lookup_positive_unlocked(kntmp->name, dentry, |
---|
216 | 227 | strlen(kntmp->name)); |
---|
217 | 228 | dput(dentry); |
---|
218 | 229 | if (IS_ERR(dtmp)) |
---|
.. | .. |
---|
222 | 233 | } while (true); |
---|
223 | 234 | } |
---|
224 | 235 | |
---|
225 | | -static int kernfs_fill_super(struct super_block *sb, unsigned long magic) |
---|
| 236 | +static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *kfc) |
---|
226 | 237 | { |
---|
227 | 238 | struct kernfs_super_info *info = kernfs_info(sb); |
---|
228 | 239 | struct inode *inode; |
---|
.. | .. |
---|
233 | 244 | sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; |
---|
234 | 245 | sb->s_blocksize = PAGE_SIZE; |
---|
235 | 246 | sb->s_blocksize_bits = PAGE_SHIFT; |
---|
236 | | - sb->s_magic = magic; |
---|
| 247 | + sb->s_magic = kfc->magic; |
---|
237 | 248 | sb->s_op = &kernfs_sops; |
---|
238 | 249 | sb->s_xattr = kernfs_xattr_handlers; |
---|
239 | 250 | if (info->root->flags & KERNFS_ROOT_SUPPORT_EXPORTOP) |
---|
240 | 251 | sb->s_export_op = &kernfs_export_ops; |
---|
241 | 252 | sb->s_time_gran = 1; |
---|
| 253 | + |
---|
| 254 | + /* sysfs dentries and inodes don't require IO to create */ |
---|
| 255 | + sb->s_shrink.seeks = 0; |
---|
242 | 256 | |
---|
243 | 257 | /* get root inode, initialize and unlock it */ |
---|
244 | 258 | mutex_lock(&kernfs_mutex); |
---|
.. | .. |
---|
260 | 274 | return 0; |
---|
261 | 275 | } |
---|
262 | 276 | |
---|
263 | | -static int kernfs_test_super(struct super_block *sb, void *data) |
---|
| 277 | +static int kernfs_test_super(struct super_block *sb, struct fs_context *fc) |
---|
264 | 278 | { |
---|
265 | 279 | struct kernfs_super_info *sb_info = kernfs_info(sb); |
---|
266 | | - struct kernfs_super_info *info = data; |
---|
| 280 | + struct kernfs_super_info *info = fc->s_fs_info; |
---|
267 | 281 | |
---|
268 | 282 | return sb_info->root == info->root && sb_info->ns == info->ns; |
---|
269 | 283 | } |
---|
270 | 284 | |
---|
271 | | -static int kernfs_set_super(struct super_block *sb, void *data) |
---|
| 285 | +static int kernfs_set_super(struct super_block *sb, struct fs_context *fc) |
---|
272 | 286 | { |
---|
273 | | - int error; |
---|
274 | | - error = set_anon_super(sb, data); |
---|
275 | | - if (!error) |
---|
276 | | - sb->s_fs_info = data; |
---|
277 | | - return error; |
---|
| 287 | + struct kernfs_fs_context *kfc = fc->fs_private; |
---|
| 288 | + |
---|
| 289 | + kfc->ns_tag = NULL; |
---|
| 290 | + return set_anon_super_fc(sb, fc); |
---|
278 | 291 | } |
---|
279 | 292 | |
---|
280 | 293 | /** |
---|
.. | .. |
---|
291 | 304 | } |
---|
292 | 305 | |
---|
293 | 306 | /** |
---|
294 | | - * kernfs_mount_ns - kernfs mount helper |
---|
295 | | - * @fs_type: file_system_type of the fs being mounted |
---|
296 | | - * @flags: mount flags specified for the mount |
---|
297 | | - * @root: kernfs_root of the hierarchy being mounted |
---|
298 | | - * @magic: file system specific magic number |
---|
299 | | - * @new_sb_created: tell the caller if we allocated a new superblock |
---|
300 | | - * @ns: optional namespace tag of the mount |
---|
| 307 | + * kernfs_get_tree - kernfs filesystem access/retrieval helper |
---|
| 308 | + * @fc: The filesystem context. |
---|
301 | 309 | * |
---|
302 | | - * This is to be called from each kernfs user's file_system_type->mount() |
---|
303 | | - * implementation, which should pass through the specified @fs_type and |
---|
304 | | - * @flags, and specify the hierarchy and namespace tag to mount via @root |
---|
305 | | - * and @ns, respectively. |
---|
306 | | - * |
---|
307 | | - * The return value can be passed to the vfs layer verbatim. |
---|
| 310 | + * This is to be called from each kernfs user's fs_context->ops->get_tree() |
---|
| 311 | + * implementation, which should set the specified ->@fs_type and ->@flags, and |
---|
| 312 | + * specify the hierarchy and namespace tag to mount via ->@root and ->@ns, |
---|
| 313 | + * respectively. |
---|
308 | 314 | */ |
---|
309 | | -struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, |
---|
310 | | - struct kernfs_root *root, unsigned long magic, |
---|
311 | | - bool *new_sb_created, const void *ns) |
---|
| 315 | +int kernfs_get_tree(struct fs_context *fc) |
---|
312 | 316 | { |
---|
| 317 | + struct kernfs_fs_context *kfc = fc->fs_private; |
---|
313 | 318 | struct super_block *sb; |
---|
314 | 319 | struct kernfs_super_info *info; |
---|
315 | 320 | int error; |
---|
316 | 321 | |
---|
317 | 322 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
---|
318 | 323 | if (!info) |
---|
319 | | - return ERR_PTR(-ENOMEM); |
---|
| 324 | + return -ENOMEM; |
---|
320 | 325 | |
---|
321 | | - info->root = root; |
---|
322 | | - info->ns = ns; |
---|
| 326 | + info->root = kfc->root; |
---|
| 327 | + info->ns = kfc->ns_tag; |
---|
323 | 328 | INIT_LIST_HEAD(&info->node); |
---|
324 | 329 | |
---|
325 | | - sb = sget_userns(fs_type, kernfs_test_super, kernfs_set_super, flags, |
---|
326 | | - &init_user_ns, info); |
---|
327 | | - if (IS_ERR(sb) || sb->s_fs_info != info) |
---|
328 | | - kfree(info); |
---|
| 330 | + fc->s_fs_info = info; |
---|
| 331 | + sb = sget_fc(fc, kernfs_test_super, kernfs_set_super); |
---|
329 | 332 | if (IS_ERR(sb)) |
---|
330 | | - return ERR_CAST(sb); |
---|
331 | | - |
---|
332 | | - if (new_sb_created) |
---|
333 | | - *new_sb_created = !sb->s_root; |
---|
| 333 | + return PTR_ERR(sb); |
---|
334 | 334 | |
---|
335 | 335 | if (!sb->s_root) { |
---|
336 | 336 | struct kernfs_super_info *info = kernfs_info(sb); |
---|
337 | 337 | |
---|
338 | | - error = kernfs_fill_super(sb, magic); |
---|
| 338 | + kfc->new_sb_created = true; |
---|
| 339 | + |
---|
| 340 | + error = kernfs_fill_super(sb, kfc); |
---|
339 | 341 | if (error) { |
---|
340 | 342 | deactivate_locked_super(sb); |
---|
341 | | - return ERR_PTR(error); |
---|
| 343 | + return error; |
---|
342 | 344 | } |
---|
343 | 345 | sb->s_flags |= SB_ACTIVE; |
---|
344 | 346 | |
---|
345 | 347 | mutex_lock(&kernfs_mutex); |
---|
346 | | - list_add(&info->node, &root->supers); |
---|
| 348 | + list_add(&info->node, &info->root->supers); |
---|
347 | 349 | mutex_unlock(&kernfs_mutex); |
---|
348 | 350 | } |
---|
349 | 351 | |
---|
350 | | - return dget(sb->s_root); |
---|
| 352 | + fc->root = dget(sb->s_root); |
---|
| 353 | + return 0; |
---|
| 354 | +} |
---|
| 355 | + |
---|
| 356 | +void kernfs_free_fs_context(struct fs_context *fc) |
---|
| 357 | +{ |
---|
| 358 | + /* Note that we don't deal with kfc->ns_tag here. */ |
---|
| 359 | + kfree(fc->s_fs_info); |
---|
| 360 | + fc->s_fs_info = NULL; |
---|
351 | 361 | } |
---|
352 | 362 | |
---|
353 | 363 | /** |
---|
.. | .. |
---|
374 | 384 | kfree(info); |
---|
375 | 385 | } |
---|
376 | 386 | |
---|
377 | | -/** |
---|
378 | | - * kernfs_pin_sb: try to pin the superblock associated with a kernfs_root |
---|
379 | | - * @kernfs_root: the kernfs_root in question |
---|
380 | | - * @ns: the namespace tag |
---|
381 | | - * |
---|
382 | | - * Pin the superblock so the superblock won't be destroyed in subsequent |
---|
383 | | - * operations. This can be used to block ->kill_sb() which may be useful |
---|
384 | | - * for kernfs users which dynamically manage superblocks. |
---|
385 | | - * |
---|
386 | | - * Returns NULL if there's no superblock associated to this kernfs_root, or |
---|
387 | | - * -EINVAL if the superblock is being freed. |
---|
388 | | - */ |
---|
389 | | -struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns) |
---|
390 | | -{ |
---|
391 | | - struct kernfs_super_info *info; |
---|
392 | | - struct super_block *sb = NULL; |
---|
393 | | - |
---|
394 | | - mutex_lock(&kernfs_mutex); |
---|
395 | | - list_for_each_entry(info, &root->supers, node) { |
---|
396 | | - if (info->ns == ns) { |
---|
397 | | - sb = info->sb; |
---|
398 | | - if (!atomic_inc_not_zero(&info->sb->s_active)) |
---|
399 | | - sb = ERR_PTR(-EINVAL); |
---|
400 | | - break; |
---|
401 | | - } |
---|
402 | | - } |
---|
403 | | - mutex_unlock(&kernfs_mutex); |
---|
404 | | - return sb; |
---|
405 | | -} |
---|
406 | | - |
---|
407 | 387 | void __init kernfs_init(void) |
---|
408 | 388 | { |
---|
409 | | - |
---|
410 | | - /* |
---|
411 | | - * the slab is freed in RCU context, so kernfs_find_and_get_node_by_ino |
---|
412 | | - * can access the slab lock free. This could introduce stale nodes, |
---|
413 | | - * please see how kernfs_find_and_get_node_by_ino filters out stale |
---|
414 | | - * nodes. |
---|
415 | | - */ |
---|
416 | 389 | kernfs_node_cache = kmem_cache_create("kernfs_node_cache", |
---|
417 | 390 | sizeof(struct kernfs_node), |
---|
418 | | - 0, |
---|
419 | | - SLAB_PANIC | SLAB_TYPESAFE_BY_RCU, |
---|
420 | | - NULL); |
---|
| 391 | + 0, SLAB_PANIC, NULL); |
---|
| 392 | + |
---|
| 393 | + /* Creates slab cache for kernfs inode attributes */ |
---|
| 394 | + kernfs_iattrs_cache = kmem_cache_create("kernfs_iattrs_cache", |
---|
| 395 | + sizeof(struct kernfs_iattrs), |
---|
| 396 | + 0, SLAB_PANIC, NULL); |
---|
421 | 397 | } |
---|