diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2005-11-07 17:15:04 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 18:18:09 -0800 |
commit | ccd48bc7fac284caf704dcdcafd223a24f70bccf (patch) | |
tree | 83b0b6643cb7ea302391e99ec57e07503a292646 | |
parent | 7b7b1ace2d9d06d76bce7481a045c22ed75e35dd (diff) |
[PATCH] cleanups and bug fix in do_loopback()
- check_mnt() on the source of binding should've been unconditional
from the very beginning. My fault - as far I could've trace it,
that's an old thinko made back in 2001. Kudos to Miklos for spotting
it...
Fixed.
- code cleaned up.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/namespace.c | 41 |
1 files changed, 22 insertions, 19 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 1d83302f30c..611f777bbd6 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -661,29 +661,32 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) down_write(¤t->namespace->sem); err = -EINVAL; - if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) { - err = -ENOMEM; - if (recurse) - mnt = copy_tree(old_nd.mnt, old_nd.dentry); - else - mnt = clone_mnt(old_nd.mnt, old_nd.dentry); - } + if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) + goto out; - if (mnt) { - /* stop bind mounts from expiring */ + err = -ENOMEM; + if (recurse) + mnt = copy_tree(old_nd.mnt, old_nd.dentry); + else + mnt = clone_mnt(old_nd.mnt, old_nd.dentry); + + if (!mnt) + goto out; + + /* stop bind mounts from expiring */ + spin_lock(&vfsmount_lock); + list_del_init(&mnt->mnt_expire); + spin_unlock(&vfsmount_lock); + + err = graft_tree(mnt, nd); + if (err) { spin_lock(&vfsmount_lock); - list_del_init(&mnt->mnt_expire); + umount_tree(mnt); spin_unlock(&vfsmount_lock); + } else + mntput(mnt); - err = graft_tree(mnt, nd); - if (err) { - spin_lock(&vfsmount_lock); - umount_tree(mnt); - spin_unlock(&vfsmount_lock); - } else - mntput(mnt); - } - +out: up_write(¤t->namespace->sem); path_release(&old_nd); return err; |