aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fs_struct.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2009-03-30 07:20:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-03-31 23:00:26 -0400
commit498052bba55ecaff58db6a1436b0e25bfd75a7ff (patch)
treebd3644ac60737e3733995a203acebd70cfd1b21b /fs/fs_struct.c
parent3e93cd671813e204c258f1e6c797959920cf7772 (diff)
New locking/refcounting for fs_struct
* all changes of current->fs are done under task_lock and write_lock of old fs->lock * refcount is not atomic anymore (same protection) * its decrements are done when removing reference from current; at the same time we decide whether to free it. * put_fs_struct() is gone * new field - ->in_exec. Set by check_unsafe_exec() if we are trying to do execve() and only subthreads share fs_struct. Cleared when finishing exec (success and failure alike). Makes CLONE_FS fail with -EAGAIN if set. * check_unsafe_exec() may fail with -EAGAIN if another execve() from subthread is in progress. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fs_struct.c')
-rw-r--r--fs/fs_struct.c69
1 files changed, 49 insertions, 20 deletions
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
index 36e0a123bbf3..41cff72b377b 100644
--- a/fs/fs_struct.c
+++ b/fs/fs_struct.c
@@ -72,25 +72,27 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
72 path_put(old_root); 72 path_put(old_root);
73} 73}
74 74
75void put_fs_struct(struct fs_struct *fs) 75void free_fs_struct(struct fs_struct *fs)
76{ 76{
77 /* No need to hold fs->lock if we are killing it */ 77 path_put(&fs->root);
78 if (atomic_dec_and_test(&fs->count)) { 78 path_put(&fs->pwd);
79 path_put(&fs->root); 79 kmem_cache_free(fs_cachep, fs);
80 path_put(&fs->pwd);
81 kmem_cache_free(fs_cachep, fs);
82 }
83} 80}
84 81
85void exit_fs(struct task_struct *tsk) 82void exit_fs(struct task_struct *tsk)
86{ 83{
87 struct fs_struct * fs = tsk->fs; 84 struct fs_struct *fs = tsk->fs;
88 85
89 if (fs) { 86 if (fs) {
87 int kill;
90 task_lock(tsk); 88 task_lock(tsk);
89 write_lock(&fs->lock);
91 tsk->fs = NULL; 90 tsk->fs = NULL;
91 kill = !--fs->users;
92 write_unlock(&fs->lock);
92 task_unlock(tsk); 93 task_unlock(tsk);
93 put_fs_struct(fs); 94 if (kill)
95 free_fs_struct(fs);
94 } 96 }
95} 97}
96 98
@@ -99,7 +101,8 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
99 struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); 101 struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
100 /* We don't need to lock fs - think why ;-) */ 102 /* We don't need to lock fs - think why ;-) */
101 if (fs) { 103 if (fs) {
102 atomic_set(&fs->count, 1); 104 fs->users = 1;
105 fs->in_exec = 0;
103 rwlock_init(&fs->lock); 106 rwlock_init(&fs->lock);
104 fs->umask = old->umask; 107 fs->umask = old->umask;
105 read_lock(&old->lock); 108 read_lock(&old->lock);
@@ -114,28 +117,54 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
114 117
115int unshare_fs_struct(void) 118int unshare_fs_struct(void)
116{ 119{
117 struct fs_struct *fsp = copy_fs_struct(current->fs); 120 struct fs_struct *fs = current->fs;
118 if (!fsp) 121 struct fs_struct *new_fs = copy_fs_struct(fs);
122 int kill;
123
124 if (!new_fs)
119 return -ENOMEM; 125 return -ENOMEM;
120 exit_fs(current); 126
121 current->fs = fsp; 127 task_lock(current);
128 write_lock(&fs->lock);
129 kill = !--fs->users;
130 current->fs = new_fs;
131 write_unlock(&fs->lock);
132 task_unlock(current);
133
134 if (kill)
135 free_fs_struct(fs);
136
122 return 0; 137 return 0;
123} 138}
124EXPORT_SYMBOL_GPL(unshare_fs_struct); 139EXPORT_SYMBOL_GPL(unshare_fs_struct);
125 140
126/* to be mentioned only in INIT_TASK */ 141/* to be mentioned only in INIT_TASK */
127struct fs_struct init_fs = { 142struct fs_struct init_fs = {
128 .count = ATOMIC_INIT(1), 143 .users = 1,
129 .lock = __RW_LOCK_UNLOCKED(init_fs.lock), 144 .lock = __RW_LOCK_UNLOCKED(init_fs.lock),
130 .umask = 0022, 145 .umask = 0022,
131}; 146};
132 147
133void daemonize_fs_struct(void) 148void daemonize_fs_struct(void)
134{ 149{
135 struct fs_struct *fs; 150 struct fs_struct *fs = current->fs;
151
152 if (fs) {
153 int kill;
154
155 task_lock(current);
136 156
137 exit_fs(current); /* current->fs->count--; */ 157 write_lock(&init_fs.lock);
138 fs = &init_fs; 158 init_fs.users++;
139 current->fs = fs; 159 write_unlock(&init_fs.lock);
140 atomic_inc(&fs->count); 160
161 write_lock(&fs->lock);
162 current->fs = &init_fs;
163 kill = !--fs->users;
164 write_unlock(&fs->lock);
165
166 task_unlock(current);
167 if (kill)
168 free_fs_struct(fs);
169 }
141} 170}