get rid of detach_mnt()

Lift getting the original mount (dentry is actually not needed at all)
of the mountpoint into the callers - to do_move_mount() and pivot_root()
level.  That simplifies the cleanup in those and allows to get saner
arguments for attach_mnt_recursive().

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2019-06-30 19:18:53 -04:00
parent 4edbe133f8
commit 2763d11912

View File

@ -820,16 +820,6 @@ static struct mountpoint *unhash_mnt(struct mount *mnt)
return mp; return mp;
} }
/*
* vfsmount lock must be held for write
*/
static void detach_mnt(struct mount *mnt, struct path *old_path)
{
old_path->dentry = dget(mnt->mnt_mountpoint);
old_path->mnt = &mnt->mnt_parent->mnt;
put_mountpoint(unhash_mnt(mnt));
}
/* /*
* vfsmount lock must be held for write * vfsmount lock must be held for write
*/ */
@ -2045,7 +2035,7 @@ int count_mounts(struct mnt_namespace *ns, struct mount *mnt)
static int attach_recursive_mnt(struct mount *source_mnt, static int attach_recursive_mnt(struct mount *source_mnt,
struct mount *dest_mnt, struct mount *dest_mnt,
struct mountpoint *dest_mp, struct mountpoint *dest_mp,
struct path *parent_path) bool moving)
{ {
struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
HLIST_HEAD(tree_list); HLIST_HEAD(tree_list);
@ -2063,7 +2053,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
return PTR_ERR(smp); return PTR_ERR(smp);
/* Is there space to add these mounts to the mount namespace? */ /* Is there space to add these mounts to the mount namespace? */
if (!parent_path) { if (!moving) {
err = count_mounts(ns, source_mnt); err = count_mounts(ns, source_mnt);
if (err) if (err)
goto out; goto out;
@ -2082,8 +2072,8 @@ static int attach_recursive_mnt(struct mount *source_mnt,
} else { } else {
lock_mount_hash(); lock_mount_hash();
} }
if (parent_path) { if (moving) {
detach_mnt(source_mnt, parent_path); unhash_mnt(source_mnt);
attach_mnt(source_mnt, dest_mnt, dest_mp); attach_mnt(source_mnt, dest_mnt, dest_mp);
touch_mnt_namespace(source_mnt->mnt_ns); touch_mnt_namespace(source_mnt->mnt_ns);
} else { } else {
@ -2181,7 +2171,7 @@ static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp)
d_is_dir(mnt->mnt.mnt_root)) d_is_dir(mnt->mnt.mnt_root))
return -ENOTDIR; return -ENOTDIR;
return attach_recursive_mnt(mnt, p, mp, NULL); return attach_recursive_mnt(mnt, p, mp, false);
} }
/* /*
@ -2574,11 +2564,11 @@ static bool check_for_nsfs_mounts(struct mount *subtree)
static int do_move_mount(struct path *old_path, struct path *new_path) static int do_move_mount(struct path *old_path, struct path *new_path)
{ {
struct path parent_path = {.mnt = NULL, .dentry = NULL};
struct mnt_namespace *ns; struct mnt_namespace *ns;
struct mount *p; struct mount *p;
struct mount *old; struct mount *old;
struct mountpoint *mp; struct mount *parent;
struct mountpoint *mp, *old_mp;
int err; int err;
bool attached; bool attached;
@ -2588,7 +2578,9 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
old = real_mount(old_path->mnt); old = real_mount(old_path->mnt);
p = real_mount(new_path->mnt); p = real_mount(new_path->mnt);
parent = old->mnt_parent;
attached = mnt_has_parent(old); attached = mnt_has_parent(old);
old_mp = old->mnt_mp;
ns = old->mnt_ns; ns = old->mnt_ns;
err = -EINVAL; err = -EINVAL;
@ -2616,7 +2608,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
/* /*
* Don't move a mount residing in a shared parent. * Don't move a mount residing in a shared parent.
*/ */
if (attached && IS_MNT_SHARED(old->mnt_parent)) if (attached && IS_MNT_SHARED(parent))
goto out; goto out;
/* /*
* Don't move a mount tree containing unbindable mounts to a destination * Don't move a mount tree containing unbindable mounts to a destination
@ -2632,18 +2624,21 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
goto out; goto out;
err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp, err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp,
attached ? &parent_path : NULL); attached);
if (err) if (err)
goto out; goto out;
/* if the mount is moved, it should no longer be expire /* if the mount is moved, it should no longer be expire
* automatically */ * automatically */
list_del_init(&old->mnt_expire); list_del_init(&old->mnt_expire);
if (attached)
put_mountpoint(old_mp);
out: out:
unlock_mount(mp); unlock_mount(mp);
if (!err) { if (!err) {
path_put(&parent_path); if (attached)
if (!attached) mntput_no_expire(parent);
else
free_mnt_ns(ns); free_mnt_ns(ns);
} }
return err; return err;
@ -3586,8 +3581,8 @@ EXPORT_SYMBOL(path_is_under);
SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
const char __user *, put_old) const char __user *, put_old)
{ {
struct path new, old, parent_path, root_parent, root; struct path new, old, root;
struct mount *new_mnt, *root_mnt, *old_mnt; struct mount *new_mnt, *root_mnt, *old_mnt, *root_parent, *ex_parent;
struct mountpoint *old_mp, *root_mp; struct mountpoint *old_mp, *root_mp;
int error; int error;
@ -3616,9 +3611,11 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
new_mnt = real_mount(new.mnt); new_mnt = real_mount(new.mnt);
root_mnt = real_mount(root.mnt); root_mnt = real_mount(root.mnt);
old_mnt = real_mount(old.mnt); old_mnt = real_mount(old.mnt);
ex_parent = new_mnt->mnt_parent;
root_parent = root_mnt->mnt_parent;
if (IS_MNT_SHARED(old_mnt) || if (IS_MNT_SHARED(old_mnt) ||
IS_MNT_SHARED(new_mnt->mnt_parent) || IS_MNT_SHARED(ex_parent) ||
IS_MNT_SHARED(root_mnt->mnt_parent)) IS_MNT_SHARED(root_parent))
goto out4; goto out4;
if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
goto out4; goto out4;
@ -3635,7 +3632,6 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
goto out4; /* not a mountpoint */ goto out4; /* not a mountpoint */
if (!mnt_has_parent(root_mnt)) if (!mnt_has_parent(root_mnt))
goto out4; /* not attached */ goto out4; /* not attached */
root_mp = root_mnt->mnt_mp;
if (new.mnt->mnt_root != new.dentry) if (new.mnt->mnt_root != new.dentry)
goto out4; /* not a mountpoint */ goto out4; /* not a mountpoint */
if (!mnt_has_parent(new_mnt)) if (!mnt_has_parent(new_mnt))
@ -3646,10 +3642,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
/* make certain new is below the root */ /* make certain new is below the root */
if (!is_path_reachable(new_mnt, new.dentry, &root)) if (!is_path_reachable(new_mnt, new.dentry, &root))
goto out4; goto out4;
root_mp->m_count++; /* pin it so it won't go away */
lock_mount_hash(); lock_mount_hash();
detach_mnt(new_mnt, &parent_path); umount_mnt(new_mnt);
detach_mnt(root_mnt, &root_parent); root_mp = unhash_mnt(root_mnt); /* we'll need its mountpoint */
if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { if (root_mnt->mnt.mnt_flags & MNT_LOCKED) {
new_mnt->mnt.mnt_flags |= MNT_LOCKED; new_mnt->mnt.mnt_flags |= MNT_LOCKED;
root_mnt->mnt.mnt_flags &= ~MNT_LOCKED; root_mnt->mnt.mnt_flags &= ~MNT_LOCKED;
@ -3657,7 +3652,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
/* mount old root on put_old */ /* mount old root on put_old */
attach_mnt(root_mnt, old_mnt, old_mp); attach_mnt(root_mnt, old_mnt, old_mp);
/* mount new_root on / */ /* mount new_root on / */
attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp); attach_mnt(new_mnt, root_parent, root_mp);
mnt_add_count(root_parent, -1);
touch_mnt_namespace(current->nsproxy->mnt_ns); touch_mnt_namespace(current->nsproxy->mnt_ns);
/* A moved mount should not expire automatically */ /* A moved mount should not expire automatically */
list_del_init(&new_mnt->mnt_expire); list_del_init(&new_mnt->mnt_expire);
@ -3667,10 +3663,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
error = 0; error = 0;
out4: out4:
unlock_mount(old_mp); unlock_mount(old_mp);
if (!error) { if (!error)
path_put(&root_parent); mntput_no_expire(ex_parent);
path_put(&parent_path);
}
out3: out3:
path_put(&root); path_put(&root);
out2: out2: