| .. | .. |
|---|
| 25 | 25 | #include <linux/sched.h> |
|---|
| 26 | 26 | #include <linux/slab.h> |
|---|
| 27 | 27 | #include <linux/kthread.h> |
|---|
| 28 | +#include <linux/init_syscalls.h> |
|---|
| 29 | +#include <uapi/linux/mount.h> |
|---|
| 28 | 30 | #include "base.h" |
|---|
| 29 | 31 | |
|---|
| 30 | 32 | static struct task_struct *thread; |
|---|
| 31 | 33 | |
|---|
| 32 | | -#if defined CONFIG_DEVTMPFS_MOUNT |
|---|
| 33 | | -static int mount_dev = 1; |
|---|
| 34 | | -#else |
|---|
| 35 | | -static int mount_dev; |
|---|
| 36 | | -#endif |
|---|
| 34 | +static int __initdata mount_dev = IS_ENABLED(CONFIG_DEVTMPFS_MOUNT); |
|---|
| 37 | 35 | |
|---|
| 38 | 36 | static DEFINE_SPINLOCK(req_lock); |
|---|
| 39 | 37 | |
|---|
| .. | .. |
|---|
| 55 | 53 | } |
|---|
| 56 | 54 | __setup("devtmpfs.mount=", mount_param); |
|---|
| 57 | 55 | |
|---|
| 58 | | -static struct dentry *dev_mount(struct file_system_type *fs_type, int flags, |
|---|
| 56 | +static struct vfsmount *mnt; |
|---|
| 57 | + |
|---|
| 58 | +static struct dentry *public_dev_mount(struct file_system_type *fs_type, int flags, |
|---|
| 59 | 59 | const char *dev_name, void *data) |
|---|
| 60 | 60 | { |
|---|
| 61 | | -#ifdef CONFIG_TMPFS |
|---|
| 62 | | - return mount_single(fs_type, flags, data, shmem_fill_super); |
|---|
| 63 | | -#else |
|---|
| 64 | | - return mount_single(fs_type, flags, data, ramfs_fill_super); |
|---|
| 65 | | -#endif |
|---|
| 61 | + struct super_block *s = mnt->mnt_sb; |
|---|
| 62 | + int err; |
|---|
| 63 | + |
|---|
| 64 | + atomic_inc(&s->s_active); |
|---|
| 65 | + down_write(&s->s_umount); |
|---|
| 66 | + err = reconfigure_single(s, flags, data); |
|---|
| 67 | + if (err < 0) { |
|---|
| 68 | + deactivate_locked_super(s); |
|---|
| 69 | + return ERR_PTR(err); |
|---|
| 70 | + } |
|---|
| 71 | + return dget(s->s_root); |
|---|
| 66 | 72 | } |
|---|
| 73 | + |
|---|
| 74 | +static struct file_system_type internal_fs_type = { |
|---|
| 75 | + .name = "devtmpfs", |
|---|
| 76 | +#ifdef CONFIG_TMPFS |
|---|
| 77 | + .init_fs_context = shmem_init_fs_context, |
|---|
| 78 | + .parameters = shmem_fs_parameters, |
|---|
| 79 | +#else |
|---|
| 80 | + .init_fs_context = ramfs_init_fs_context, |
|---|
| 81 | + .parameters = ramfs_fs_parameters, |
|---|
| 82 | +#endif |
|---|
| 83 | + .kill_sb = kill_litter_super, |
|---|
| 84 | +}; |
|---|
| 67 | 85 | |
|---|
| 68 | 86 | static struct file_system_type dev_fs_type = { |
|---|
| 69 | 87 | .name = "devtmpfs", |
|---|
| 70 | | - .mount = dev_mount, |
|---|
| 71 | | - .kill_sb = kill_litter_super, |
|---|
| 88 | + .mount = public_dev_mount, |
|---|
| 72 | 89 | }; |
|---|
| 73 | 90 | |
|---|
| 74 | 91 | #ifdef CONFIG_BLOCK |
|---|
| .. | .. |
|---|
| 79 | 96 | #else |
|---|
| 80 | 97 | static inline int is_blockdev(struct device *dev) { return 0; } |
|---|
| 81 | 98 | #endif |
|---|
| 99 | + |
|---|
| 100 | +static int devtmpfs_submit_req(struct req *req, const char *tmp) |
|---|
| 101 | +{ |
|---|
| 102 | + init_completion(&req->done); |
|---|
| 103 | + |
|---|
| 104 | + spin_lock(&req_lock); |
|---|
| 105 | + req->next = requests; |
|---|
| 106 | + requests = req; |
|---|
| 107 | + spin_unlock(&req_lock); |
|---|
| 108 | + |
|---|
| 109 | + wake_up_process(thread); |
|---|
| 110 | + wait_for_completion(&req->done); |
|---|
| 111 | + |
|---|
| 112 | + kfree(tmp); |
|---|
| 113 | + |
|---|
| 114 | + return req->err; |
|---|
| 115 | +} |
|---|
| 82 | 116 | |
|---|
| 83 | 117 | int devtmpfs_create_node(struct device *dev) |
|---|
| 84 | 118 | { |
|---|
| .. | .. |
|---|
| 104 | 138 | |
|---|
| 105 | 139 | req.dev = dev; |
|---|
| 106 | 140 | |
|---|
| 107 | | - init_completion(&req.done); |
|---|
| 108 | | - |
|---|
| 109 | | - spin_lock(&req_lock); |
|---|
| 110 | | - req.next = requests; |
|---|
| 111 | | - requests = &req; |
|---|
| 112 | | - spin_unlock(&req_lock); |
|---|
| 113 | | - |
|---|
| 114 | | - wake_up_process(thread); |
|---|
| 115 | | - wait_for_completion(&req.done); |
|---|
| 116 | | - |
|---|
| 117 | | - kfree(tmp); |
|---|
| 118 | | - |
|---|
| 119 | | - return req.err; |
|---|
| 141 | + return devtmpfs_submit_req(&req, tmp); |
|---|
| 120 | 142 | } |
|---|
| 121 | 143 | |
|---|
| 122 | 144 | int devtmpfs_delete_node(struct device *dev) |
|---|
| .. | .. |
|---|
| 134 | 156 | req.mode = 0; |
|---|
| 135 | 157 | req.dev = dev; |
|---|
| 136 | 158 | |
|---|
| 137 | | - init_completion(&req.done); |
|---|
| 138 | | - |
|---|
| 139 | | - spin_lock(&req_lock); |
|---|
| 140 | | - req.next = requests; |
|---|
| 141 | | - requests = &req; |
|---|
| 142 | | - spin_unlock(&req_lock); |
|---|
| 143 | | - |
|---|
| 144 | | - wake_up_process(thread); |
|---|
| 145 | | - wait_for_completion(&req.done); |
|---|
| 146 | | - |
|---|
| 147 | | - kfree(tmp); |
|---|
| 148 | | - return req.err; |
|---|
| 159 | + return devtmpfs_submit_req(&req, tmp); |
|---|
| 149 | 160 | } |
|---|
| 150 | 161 | |
|---|
| 151 | 162 | static int dev_mkdir(const char *name, umode_t mode) |
|---|
| .. | .. |
|---|
| 252 | 263 | |
|---|
| 253 | 264 | static int delete_path(const char *nodepath) |
|---|
| 254 | 265 | { |
|---|
| 255 | | - const char *path; |
|---|
| 266 | + char *path; |
|---|
| 256 | 267 | int err = 0; |
|---|
| 257 | 268 | |
|---|
| 258 | 269 | path = kstrdup(nodepath, GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 346 | 357 | * If configured, or requested by the commandline, devtmpfs will be |
|---|
| 347 | 358 | * auto-mounted after the kernel mounted the root filesystem. |
|---|
| 348 | 359 | */ |
|---|
| 349 | | -int devtmpfs_mount(const char *mntdir) |
|---|
| 360 | +int __init devtmpfs_mount(void) |
|---|
| 350 | 361 | { |
|---|
| 351 | 362 | int err; |
|---|
| 352 | 363 | |
|---|
| .. | .. |
|---|
| 356 | 367 | if (!thread) |
|---|
| 357 | 368 | return 0; |
|---|
| 358 | 369 | |
|---|
| 359 | | - err = ksys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, |
|---|
| 360 | | - NULL); |
|---|
| 370 | + err = init_mount("devtmpfs", "dev", "devtmpfs", MS_SILENT, NULL); |
|---|
| 361 | 371 | if (err) |
|---|
| 362 | 372 | printk(KERN_INFO "devtmpfs: error mounting %i\n", err); |
|---|
| 363 | 373 | else |
|---|
| .. | .. |
|---|
| 376 | 386 | return handle_remove(name, dev); |
|---|
| 377 | 387 | } |
|---|
| 378 | 388 | |
|---|
| 379 | | -static int devtmpfsd(void *p) |
|---|
| 389 | +static void __noreturn devtmpfs_work_loop(void) |
|---|
| 380 | 390 | { |
|---|
| 381 | | - char options[] = "mode=0755"; |
|---|
| 382 | | - int *err = p; |
|---|
| 383 | | - *err = ksys_unshare(CLONE_NEWNS); |
|---|
| 384 | | - if (*err) |
|---|
| 385 | | - goto out; |
|---|
| 386 | | - *err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options); |
|---|
| 387 | | - if (*err) |
|---|
| 388 | | - goto out; |
|---|
| 389 | | - ksys_chdir("/.."); /* will traverse into overmounted root */ |
|---|
| 390 | | - ksys_chroot("."); |
|---|
| 391 | | - complete(&setup_done); |
|---|
| 392 | 391 | while (1) { |
|---|
| 393 | 392 | spin_lock(&req_lock); |
|---|
| 394 | 393 | while (requests) { |
|---|
| .. | .. |
|---|
| 408 | 407 | spin_unlock(&req_lock); |
|---|
| 409 | 408 | schedule(); |
|---|
| 410 | 409 | } |
|---|
| 411 | | - return 0; |
|---|
| 410 | +} |
|---|
| 411 | + |
|---|
| 412 | +static int __init devtmpfs_setup(void *p) |
|---|
| 413 | +{ |
|---|
| 414 | + int err; |
|---|
| 415 | + |
|---|
| 416 | + err = ksys_unshare(CLONE_NEWNS); |
|---|
| 417 | + if (err) |
|---|
| 418 | + goto out; |
|---|
| 419 | + err = init_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, NULL); |
|---|
| 420 | + if (err) |
|---|
| 421 | + goto out; |
|---|
| 422 | + init_chdir("/.."); /* will traverse into overmounted root */ |
|---|
| 423 | + init_chroot("."); |
|---|
| 412 | 424 | out: |
|---|
| 425 | + *(int *)p = err; |
|---|
| 426 | + return err; |
|---|
| 427 | +} |
|---|
| 428 | + |
|---|
| 429 | +/* |
|---|
| 430 | + * The __ref is because devtmpfs_setup needs to be __init for the routines it |
|---|
| 431 | + * calls. That call is done while devtmpfs_init, which is marked __init, |
|---|
| 432 | + * synchronously waits for it to complete. |
|---|
| 433 | + */ |
|---|
| 434 | +static int __ref devtmpfsd(void *p) |
|---|
| 435 | +{ |
|---|
| 436 | + int err = devtmpfs_setup(p); |
|---|
| 437 | + |
|---|
| 413 | 438 | complete(&setup_done); |
|---|
| 414 | | - return *err; |
|---|
| 439 | + if (err) |
|---|
| 440 | + return err; |
|---|
| 441 | + devtmpfs_work_loop(); |
|---|
| 442 | + return 0; |
|---|
| 415 | 443 | } |
|---|
| 416 | 444 | |
|---|
| 417 | 445 | /* |
|---|
| .. | .. |
|---|
| 420 | 448 | */ |
|---|
| 421 | 449 | int __init devtmpfs_init(void) |
|---|
| 422 | 450 | { |
|---|
| 423 | | - int err = register_filesystem(&dev_fs_type); |
|---|
| 451 | + char opts[] = "mode=0755"; |
|---|
| 452 | + int err; |
|---|
| 453 | + |
|---|
| 454 | + mnt = vfs_kern_mount(&internal_fs_type, 0, "devtmpfs", opts); |
|---|
| 455 | + if (IS_ERR(mnt)) { |
|---|
| 456 | + printk(KERN_ERR "devtmpfs: unable to create devtmpfs %ld\n", |
|---|
| 457 | + PTR_ERR(mnt)); |
|---|
| 458 | + return PTR_ERR(mnt); |
|---|
| 459 | + } |
|---|
| 460 | + err = register_filesystem(&dev_fs_type); |
|---|
| 424 | 461 | if (err) { |
|---|
| 425 | 462 | printk(KERN_ERR "devtmpfs: unable to register devtmpfs " |
|---|
| 426 | 463 | "type %i\n", err); |
|---|