]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Get rid of bumping fs_struct refcount in pivot_root(2)
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 31 Mar 2009 00:36:33 +0000 (20:36 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 8 May 2009 22:45:07 +0000 (15:45 -0700)
commit f8ef3ed2bebd2c4cb9ece92efa185d7aead8831a upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/namespace.c

index 06f8e63f6cb1dc929e0ad9c0627320066db57cb1..580b8d38d688704b5f6f2385b8e23a4a12548b59 100644 (file)
@@ -2127,25 +2127,33 @@ static void chroot_fs_refs(struct path *old_root, struct path *new_root)
 {
        struct task_struct *g, *p;
        struct fs_struct *fs;
+       int count = 0;
 
        read_lock(&tasklist_lock);
        do_each_thread(g, p) {
                task_lock(p);
                fs = p->fs;
                if (fs) {
-                       atomic_inc(&fs->count);
-                       task_unlock(p);
+                       write_lock(&fs->lock);
                        if (fs->root.dentry == old_root->dentry
-                           && fs->root.mnt == old_root->mnt)
-                               set_fs_root(fs, new_root);
+                           && fs->root.mnt == old_root->mnt) {
+                               path_get(new_root);
+                               fs->root = *new_root;
+                               count++;
+                       }
                        if (fs->pwd.dentry == old_root->dentry
-                           && fs->pwd.mnt == old_root->mnt)
-                               set_fs_pwd(fs, new_root);
-                       put_fs_struct(fs);
-               } else
-                       task_unlock(p);
+                           && fs->pwd.mnt == old_root->mnt) {
+                               path_get(new_root);
+                               fs->pwd = *new_root;
+                               count++;
+                       }
+                       write_unlock(&fs->lock);
+               }
+               task_unlock(p);
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
+       while (count--)
+               path_put(old_root);
 }
 
 /*