| .. | .. |
|---|
| 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 | } |
|---|