.. | .. |
---|
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); |
---|