lkml.org 
[lkml]   [2018]   [Aug]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 03/33] teach move_mount(2) to work with OPEN_TREE_CLONE [ver #11]
    From
    Date
    From: Al Viro <viro@zeniv.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@zeniv.linux.org.uk>
    Signed-off-by: David Howells <dhowells@redhat.com>
    ---

    fs/namespace.c | 26 ++++++++++++++++++++------
    1 file changed, 20 insertions(+), 6 deletions(-)

    diff --git a/fs/namespace.c b/fs/namespace.c
    index e2934a4f342b..3981fd7b13f5 100644
    --- a/fs/namespace.c
    +++ b/fs/namespace.c
    @@ -1846,8 +1846,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();
    }
    @@ -2454,6 +2456,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);
    @@ -2464,10 +2467,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)
    @@ -2482,7 +2494,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
    @@ -2496,7 +2508,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;

    @@ -3182,6 +3194,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.
    */
    \
     
     \ /
      Last update: 2018-08-01 17:25    [W:3.930 / U:0.084 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site