diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2009-03-30 20:36:33 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2009-03-31 23:00:25 -0400 |
commit | f8ef3ed2bebd2c4cb9ece92efa185d7aead8831a (patch) | |
tree | f6208725f0b2ecd43e393435fa7fb8ad1be1b14b /fs/namespace.c | |
parent | 11d06b2a1e5658f448a308aa3beb97bacd64a940 (diff) |
Get rid of bumping fs_struct refcount in pivot_root(2)
Not because execve races with _that_ are serious - we really
need a situation when final drop of fs_struct refcount is
done by something that used to have it as current->fs.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 0a42e0e96027..f7ec283ccfbb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -2131,25 +2131,33 @@ static void chroot_fs_refs(struct path *old_root, struct path *new_root) | |||
2131 | { | 2131 | { |
2132 | struct task_struct *g, *p; | 2132 | struct task_struct *g, *p; |
2133 | struct fs_struct *fs; | 2133 | struct fs_struct *fs; |
2134 | int count = 0; | ||
2134 | 2135 | ||
2135 | read_lock(&tasklist_lock); | 2136 | read_lock(&tasklist_lock); |
2136 | do_each_thread(g, p) { | 2137 | do_each_thread(g, p) { |
2137 | task_lock(p); | 2138 | task_lock(p); |
2138 | fs = p->fs; | 2139 | fs = p->fs; |
2139 | if (fs) { | 2140 | if (fs) { |
2140 | atomic_inc(&fs->count); | 2141 | write_lock(&fs->lock); |
2141 | task_unlock(p); | ||
2142 | if (fs->root.dentry == old_root->dentry | 2142 | if (fs->root.dentry == old_root->dentry |
2143 | && fs->root.mnt == old_root->mnt) | 2143 | && fs->root.mnt == old_root->mnt) { |
2144 | set_fs_root(fs, new_root); | 2144 | path_get(new_root); |
2145 | fs->root = *new_root; | ||
2146 | count++; | ||
2147 | } | ||
2145 | if (fs->pwd.dentry == old_root->dentry | 2148 | if (fs->pwd.dentry == old_root->dentry |
2146 | && fs->pwd.mnt == old_root->mnt) | 2149 | && fs->pwd.mnt == old_root->mnt) { |
2147 | set_fs_pwd(fs, new_root); | 2150 | path_get(new_root); |
2148 | put_fs_struct(fs); | 2151 | fs->pwd = *new_root; |
2149 | } else | 2152 | count++; |
2150 | task_unlock(p); | 2153 | } |
2154 | write_unlock(&fs->lock); | ||
2155 | } | ||
2156 | task_unlock(p); | ||
2151 | } while_each_thread(g, p); | 2157 | } while_each_thread(g, p); |
2152 | read_unlock(&tasklist_lock); | 2158 | read_unlock(&tasklist_lock); |
2159 | while (count--) | ||
2160 | path_put(old_root); | ||
2153 | } | 2161 | } |
2154 | 2162 | ||
2155 | /* | 2163 | /* |