Commit 3e93cd671813e204c258f1e6c797959920cf7772
1 parent
f8ef3ed2be
Exists in
master
and in
4 other branches
Take fs_struct handling to new file (fs/fs_struct.c)
Pure code move; two new helper functions for nfsd and daemonize (unshare_fs_struct() and daemonize_fs_struct() resp.; for now - the same code as used to be in callers). unshare_fs_struct() exported (for nfsd, as copy_fs_struct()/exit_fs() used to be), copy_fs_struct() and exit_fs() don't need exports anymore. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 9 changed files with 155 additions and 138 deletions Side-by-side Diff
fs/Makefile
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | attr.o bad_inode.o file.o filesystems.o namespace.o \ |
12 | 12 | seq_file.o xattr.o libfs.o fs-writeback.o \ |
13 | 13 | pnode.o drop_caches.o splice.o sync.o utimes.o \ |
14 | - stack.o | |
14 | + stack.o fs_struct.o | |
15 | 15 | |
16 | 16 | ifeq ($(CONFIG_BLOCK),y) |
17 | 17 | obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o |
fs/fs_struct.c
1 | +#include <linux/module.h> | |
2 | +#include <linux/sched.h> | |
3 | +#include <linux/fs.h> | |
4 | +#include <linux/path.h> | |
5 | +#include <linux/slab.h> | |
6 | + | |
7 | +/* | |
8 | + * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. | |
9 | + * It can block. | |
10 | + */ | |
11 | +void set_fs_root(struct fs_struct *fs, struct path *path) | |
12 | +{ | |
13 | + struct path old_root; | |
14 | + | |
15 | + write_lock(&fs->lock); | |
16 | + old_root = fs->root; | |
17 | + fs->root = *path; | |
18 | + path_get(path); | |
19 | + write_unlock(&fs->lock); | |
20 | + if (old_root.dentry) | |
21 | + path_put(&old_root); | |
22 | +} | |
23 | + | |
24 | +/* | |
25 | + * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. | |
26 | + * It can block. | |
27 | + */ | |
28 | +void set_fs_pwd(struct fs_struct *fs, struct path *path) | |
29 | +{ | |
30 | + struct path old_pwd; | |
31 | + | |
32 | + write_lock(&fs->lock); | |
33 | + old_pwd = fs->pwd; | |
34 | + fs->pwd = *path; | |
35 | + path_get(path); | |
36 | + write_unlock(&fs->lock); | |
37 | + | |
38 | + if (old_pwd.dentry) | |
39 | + path_put(&old_pwd); | |
40 | +} | |
41 | + | |
42 | +void chroot_fs_refs(struct path *old_root, struct path *new_root) | |
43 | +{ | |
44 | + struct task_struct *g, *p; | |
45 | + struct fs_struct *fs; | |
46 | + int count = 0; | |
47 | + | |
48 | + read_lock(&tasklist_lock); | |
49 | + do_each_thread(g, p) { | |
50 | + task_lock(p); | |
51 | + fs = p->fs; | |
52 | + if (fs) { | |
53 | + write_lock(&fs->lock); | |
54 | + if (fs->root.dentry == old_root->dentry | |
55 | + && fs->root.mnt == old_root->mnt) { | |
56 | + path_get(new_root); | |
57 | + fs->root = *new_root; | |
58 | + count++; | |
59 | + } | |
60 | + if (fs->pwd.dentry == old_root->dentry | |
61 | + && fs->pwd.mnt == old_root->mnt) { | |
62 | + path_get(new_root); | |
63 | + fs->pwd = *new_root; | |
64 | + count++; | |
65 | + } | |
66 | + write_unlock(&fs->lock); | |
67 | + } | |
68 | + task_unlock(p); | |
69 | + } while_each_thread(g, p); | |
70 | + read_unlock(&tasklist_lock); | |
71 | + while (count--) | |
72 | + path_put(old_root); | |
73 | +} | |
74 | + | |
75 | +void put_fs_struct(struct fs_struct *fs) | |
76 | +{ | |
77 | + /* No need to hold fs->lock if we are killing it */ | |
78 | + if (atomic_dec_and_test(&fs->count)) { | |
79 | + path_put(&fs->root); | |
80 | + path_put(&fs->pwd); | |
81 | + kmem_cache_free(fs_cachep, fs); | |
82 | + } | |
83 | +} | |
84 | + | |
85 | +void exit_fs(struct task_struct *tsk) | |
86 | +{ | |
87 | + struct fs_struct * fs = tsk->fs; | |
88 | + | |
89 | + if (fs) { | |
90 | + task_lock(tsk); | |
91 | + tsk->fs = NULL; | |
92 | + task_unlock(tsk); | |
93 | + put_fs_struct(fs); | |
94 | + } | |
95 | +} | |
96 | + | |
97 | +struct fs_struct *copy_fs_struct(struct fs_struct *old) | |
98 | +{ | |
99 | + struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); | |
100 | + /* We don't need to lock fs - think why ;-) */ | |
101 | + if (fs) { | |
102 | + atomic_set(&fs->count, 1); | |
103 | + rwlock_init(&fs->lock); | |
104 | + fs->umask = old->umask; | |
105 | + read_lock(&old->lock); | |
106 | + fs->root = old->root; | |
107 | + path_get(&old->root); | |
108 | + fs->pwd = old->pwd; | |
109 | + path_get(&old->pwd); | |
110 | + read_unlock(&old->lock); | |
111 | + } | |
112 | + return fs; | |
113 | +} | |
114 | + | |
115 | +int unshare_fs_struct(void) | |
116 | +{ | |
117 | + struct fs_struct *fsp = copy_fs_struct(current->fs); | |
118 | + if (!fsp) | |
119 | + return -ENOMEM; | |
120 | + exit_fs(current); | |
121 | + current->fs = fsp; | |
122 | + return 0; | |
123 | +} | |
124 | +EXPORT_SYMBOL_GPL(unshare_fs_struct); | |
125 | + | |
126 | +/* to be mentioned only in INIT_TASK */ | |
127 | +struct fs_struct init_fs = { | |
128 | + .count = ATOMIC_INIT(1), | |
129 | + .lock = __RW_LOCK_UNLOCKED(init_fs.lock), | |
130 | + .umask = 0022, | |
131 | +}; | |
132 | + | |
133 | +void daemonize_fs_struct(void) | |
134 | +{ | |
135 | + struct fs_struct *fs; | |
136 | + | |
137 | + exit_fs(current); /* current->fs->count--; */ | |
138 | + fs = &init_fs; | |
139 | + current->fs = fs; | |
140 | + atomic_inc(&fs->count); | |
141 | +} |
fs/internal.h
... | ... | @@ -11,6 +11,7 @@ |
11 | 11 | |
12 | 12 | struct super_block; |
13 | 13 | struct linux_binprm; |
14 | +struct path; | |
14 | 15 | |
15 | 16 | /* |
16 | 17 | * block_dev.c |
... | ... | @@ -60,4 +61,9 @@ |
60 | 61 | extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); |
61 | 62 | |
62 | 63 | extern void __init mnt_init(void); |
64 | + | |
65 | +/* | |
66 | + * fs_struct.c | |
67 | + */ | |
68 | +extern void chroot_fs_refs(struct path *, struct path *); |
fs/namei.c
... | ... | @@ -2897,11 +2897,4 @@ |
2897 | 2897 | EXPORT_SYMBOL(vfs_unlink); |
2898 | 2898 | EXPORT_SYMBOL(dentry_unhash); |
2899 | 2899 | EXPORT_SYMBOL(generic_readlink); |
2900 | - | |
2901 | -/* to be mentioned only in INIT_TASK */ | |
2902 | -struct fs_struct init_fs = { | |
2903 | - .count = ATOMIC_INIT(1), | |
2904 | - .lock = __RW_LOCK_UNLOCKED(init_fs.lock), | |
2905 | - .umask = 0022, | |
2906 | -}; |
fs/namespace.c
... | ... | @@ -2093,74 +2093,6 @@ |
2093 | 2093 | } |
2094 | 2094 | |
2095 | 2095 | /* |
2096 | - * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. | |
2097 | - * It can block. Requires the big lock held. | |
2098 | - */ | |
2099 | -void set_fs_root(struct fs_struct *fs, struct path *path) | |
2100 | -{ | |
2101 | - struct path old_root; | |
2102 | - | |
2103 | - write_lock(&fs->lock); | |
2104 | - old_root = fs->root; | |
2105 | - fs->root = *path; | |
2106 | - path_get(path); | |
2107 | - write_unlock(&fs->lock); | |
2108 | - if (old_root.dentry) | |
2109 | - path_put(&old_root); | |
2110 | -} | |
2111 | - | |
2112 | -/* | |
2113 | - * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. | |
2114 | - * It can block. Requires the big lock held. | |
2115 | - */ | |
2116 | -void set_fs_pwd(struct fs_struct *fs, struct path *path) | |
2117 | -{ | |
2118 | - struct path old_pwd; | |
2119 | - | |
2120 | - write_lock(&fs->lock); | |
2121 | - old_pwd = fs->pwd; | |
2122 | - fs->pwd = *path; | |
2123 | - path_get(path); | |
2124 | - write_unlock(&fs->lock); | |
2125 | - | |
2126 | - if (old_pwd.dentry) | |
2127 | - path_put(&old_pwd); | |
2128 | -} | |
2129 | - | |
2130 | -static void chroot_fs_refs(struct path *old_root, struct path *new_root) | |
2131 | -{ | |
2132 | - struct task_struct *g, *p; | |
2133 | - struct fs_struct *fs; | |
2134 | - int count = 0; | |
2135 | - | |
2136 | - read_lock(&tasklist_lock); | |
2137 | - do_each_thread(g, p) { | |
2138 | - task_lock(p); | |
2139 | - fs = p->fs; | |
2140 | - if (fs) { | |
2141 | - write_lock(&fs->lock); | |
2142 | - if (fs->root.dentry == old_root->dentry | |
2143 | - && fs->root.mnt == old_root->mnt) { | |
2144 | - path_get(new_root); | |
2145 | - fs->root = *new_root; | |
2146 | - count++; | |
2147 | - } | |
2148 | - if (fs->pwd.dentry == old_root->dentry | |
2149 | - && fs->pwd.mnt == old_root->mnt) { | |
2150 | - path_get(new_root); | |
2151 | - fs->pwd = *new_root; | |
2152 | - count++; | |
2153 | - } | |
2154 | - write_unlock(&fs->lock); | |
2155 | - } | |
2156 | - task_unlock(p); | |
2157 | - } while_each_thread(g, p); | |
2158 | - read_unlock(&tasklist_lock); | |
2159 | - while (count--) | |
2160 | - path_put(old_root); | |
2161 | -} | |
2162 | - | |
2163 | -/* | |
2164 | 2096 | * pivot_root Semantics: |
2165 | 2097 | * Moves the root file system of the current process to the directory put_old, |
2166 | 2098 | * makes new_root as the new root file system of the current process, and sets |
fs/nfsd/nfssvc.c
... | ... | @@ -404,7 +404,6 @@ |
404 | 404 | nfsd(void *vrqstp) |
405 | 405 | { |
406 | 406 | struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; |
407 | - struct fs_struct *fsp; | |
408 | 407 | int err, preverr = 0; |
409 | 408 | |
410 | 409 | /* Lock module and set up kernel thread */ |
411 | 410 | |
... | ... | @@ -413,13 +412,11 @@ |
413 | 412 | /* At this point, the thread shares current->fs |
414 | 413 | * with the init process. We need to create files with a |
415 | 414 | * umask of 0 instead of init's umask. */ |
416 | - fsp = copy_fs_struct(current->fs); | |
417 | - if (!fsp) { | |
415 | + if (unshare_fs_struct() < 0) { | |
418 | 416 | printk("Unable to start nfsd thread: out of memory\n"); |
419 | 417 | goto out; |
420 | 418 | } |
421 | - exit_fs(current); | |
422 | - current->fs = fsp; | |
419 | + | |
423 | 420 | current->fs->umask = 0; |
424 | 421 | |
425 | 422 | /* |
include/linux/fs_struct.h
... | ... | @@ -20,6 +20,8 @@ |
20 | 20 | extern void set_fs_pwd(struct fs_struct *, struct path *); |
21 | 21 | extern struct fs_struct *copy_fs_struct(struct fs_struct *); |
22 | 22 | extern void put_fs_struct(struct fs_struct *); |
23 | +extern void daemonize_fs_struct(void); | |
24 | +extern int unshare_fs_struct(void); | |
23 | 25 | |
24 | 26 | #endif /* _LINUX_FS_STRUCT_H */ |
kernel/exit.c
... | ... | @@ -429,7 +429,6 @@ |
429 | 429 | void daemonize(const char *name, ...) |
430 | 430 | { |
431 | 431 | va_list args; |
432 | - struct fs_struct *fs; | |
433 | 432 | sigset_t blocked; |
434 | 433 | |
435 | 434 | va_start(args, name); |
... | ... | @@ -462,11 +461,7 @@ |
462 | 461 | |
463 | 462 | /* Become as one with the init task */ |
464 | 463 | |
465 | - exit_fs(current); /* current->fs->count--; */ | |
466 | - fs = init_task.fs; | |
467 | - current->fs = fs; | |
468 | - atomic_inc(&fs->count); | |
469 | - | |
464 | + daemonize_fs_struct(); | |
470 | 465 | exit_files(current); |
471 | 466 | current->files = init_task.files; |
472 | 467 | atomic_inc(¤t->files->count); |
... | ... | @@ -564,30 +559,6 @@ |
564 | 559 | put_files_struct(files); |
565 | 560 | } |
566 | 561 | } |
567 | - | |
568 | -void put_fs_struct(struct fs_struct *fs) | |
569 | -{ | |
570 | - /* No need to hold fs->lock if we are killing it */ | |
571 | - if (atomic_dec_and_test(&fs->count)) { | |
572 | - path_put(&fs->root); | |
573 | - path_put(&fs->pwd); | |
574 | - kmem_cache_free(fs_cachep, fs); | |
575 | - } | |
576 | -} | |
577 | - | |
578 | -void exit_fs(struct task_struct *tsk) | |
579 | -{ | |
580 | - struct fs_struct * fs = tsk->fs; | |
581 | - | |
582 | - if (fs) { | |
583 | - task_lock(tsk); | |
584 | - tsk->fs = NULL; | |
585 | - task_unlock(tsk); | |
586 | - put_fs_struct(fs); | |
587 | - } | |
588 | -} | |
589 | - | |
590 | -EXPORT_SYMBOL_GPL(exit_fs); | |
591 | 562 | |
592 | 563 | #ifdef CONFIG_MM_OWNER |
593 | 564 | /* |
kernel/fork.c
... | ... | @@ -681,38 +681,13 @@ |
681 | 681 | return retval; |
682 | 682 | } |
683 | 683 | |
684 | -static struct fs_struct *__copy_fs_struct(struct fs_struct *old) | |
685 | -{ | |
686 | - struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); | |
687 | - /* We don't need to lock fs - think why ;-) */ | |
688 | - if (fs) { | |
689 | - atomic_set(&fs->count, 1); | |
690 | - rwlock_init(&fs->lock); | |
691 | - fs->umask = old->umask; | |
692 | - read_lock(&old->lock); | |
693 | - fs->root = old->root; | |
694 | - path_get(&old->root); | |
695 | - fs->pwd = old->pwd; | |
696 | - path_get(&old->pwd); | |
697 | - read_unlock(&old->lock); | |
698 | - } | |
699 | - return fs; | |
700 | -} | |
701 | - | |
702 | -struct fs_struct *copy_fs_struct(struct fs_struct *old) | |
703 | -{ | |
704 | - return __copy_fs_struct(old); | |
705 | -} | |
706 | - | |
707 | -EXPORT_SYMBOL_GPL(copy_fs_struct); | |
708 | - | |
709 | 684 | static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) |
710 | 685 | { |
711 | 686 | if (clone_flags & CLONE_FS) { |
712 | 687 | atomic_inc(¤t->fs->count); |
713 | 688 | return 0; |
714 | 689 | } |
715 | - tsk->fs = __copy_fs_struct(current->fs); | |
690 | + tsk->fs = copy_fs_struct(current->fs); | |
716 | 691 | if (!tsk->fs) |
717 | 692 | return -ENOMEM; |
718 | 693 | return 0; |
... | ... | @@ -1545,7 +1520,7 @@ |
1545 | 1520 | |
1546 | 1521 | if ((unshare_flags & CLONE_FS) && |
1547 | 1522 | (fs && atomic_read(&fs->count) > 1)) { |
1548 | - *new_fsp = __copy_fs_struct(current->fs); | |
1523 | + *new_fsp = copy_fs_struct(current->fs); | |
1549 | 1524 | if (!*new_fsp) |
1550 | 1525 | return -ENOMEM; |
1551 | 1526 | } |