[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <153126250894.14533.11701155170173292521.stgit@warthog.procyon.org.uk>
Date: Tue, 10 Jul 2018 23:41:48 +0100
From: David Howells <dhowells@...hat.com>
To: viro@...iv.linux.org.uk
Cc: dhowells@...hat.com, linux-fsdevel@...r.kernel.org,
torvalds@...ux-foundation.org, linux-kernel@...r.kernel.org
Subject: [PATCH 03/32] teach move_mount(2) to work with OPEN_TREE_CLONE [ver
#9]
From: Al Viro <viro@...iv.linux.org.uk>
Allow a detached tree created by open_tree(..., OPEN_TREE_CLONE) to be
attached by move_mount(2).
If by the time of final fput() of OPEN_TREE_CLONE-opened file its tree is
not detached anymore, it won't be dissolved. move_mount(2) is adjusted
to handle detached source.
That gives us equivalents of mount --bind and mount --rbind.
Signed-off-by: Al Viro <viro@...iv.linux.org.uk>
---
fs/namespace.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index e95b2bc8fcfe..bd2526b24afb 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1845,8 +1845,10 @@ void dissolve_on_fput(struct vfsmount *mnt)
{
namespace_lock();
lock_mount_hash();
- mntget(mnt);
- umount_tree(real_mount(mnt), UMOUNT_SYNC);
+ if (!real_mount(mnt)->mnt_ns) {
+ mntget(mnt);
+ umount_tree(real_mount(mnt), UMOUNT_SYNC);
+ }
unlock_mount_hash();
namespace_unlock();
}
@@ -2453,6 +2455,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
struct mount *old;
struct mountpoint *mp;
int err;
+ bool attached;
mp = lock_mount(new_path);
err = PTR_ERR(mp);
@@ -2463,10 +2466,19 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
p = real_mount(new_path->mnt);
err = -EINVAL;
- if (!check_mnt(p) || !check_mnt(old))
+ /* The mountpoint must be in our namespace. */
+ if (!check_mnt(p))
+ goto out1;
+ /* The thing moved should be either ours or completely unattached. */
+ if (old->mnt_ns && !check_mnt(old))
goto out1;
- if (!mnt_has_parent(old))
+ attached = mnt_has_parent(old);
+ /*
+ * We need to allow open_tree(OPEN_TREE_CLONE) followed by
+ * move_mount(), but mustn't allow "/" to be moved.
+ */
+ if (old->mnt_ns && !attached)
goto out1;
if (old->mnt.mnt_flags & MNT_LOCKED)
@@ -2481,7 +2493,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
/*
* Don't move a mount residing in a shared parent.
*/
- if (IS_MNT_SHARED(old->mnt_parent))
+ if (attached && IS_MNT_SHARED(old->mnt_parent))
goto out1;
/*
* Don't move a mount tree containing unbindable mounts to a destination
@@ -2495,7 +2507,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
goto out1;
err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp,
- &parent_path);
+ attached ? &parent_path : NULL);
if (err)
goto out1;
@@ -3179,6 +3191,8 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
/*
* Move a mount from one place to another.
+ * In combination with open_tree(OPEN_TREE_CLONE [| AT_RECURSIVE]) it can be
+ * used to copy a mount subtree.
*
* Note the flags value is a combination of MOVE_MOUNT_* flags.
*/
Powered by blists - more mailing lists