From: Andrei Vagin <avagin@virtuozzo.com>
To: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>,
<linux-fsdevel@vger.kernel.org>, Ram Pai <linuxram@us.ibm.com>
Subject: Re: [REVIEW][PATCH] mnt: In umount propagation reparent in a separate pass
Date: Mon, 15 May 2017 16:12:45 -0700 [thread overview]
Message-ID: <20170515231243.GA2430@outlook.office365.com> (raw)
In-Reply-To: <871srpj2yp.fsf_-_@xmission.com>
On Mon, May 15, 2017 at 03:10:38PM -0500, Eric W. Biederman wrote:
>
> It was observed that in some pathlogical cases that the current code
> does not unmount everything it should. After investigation it was
> determined that the issue is that mnt_change_mntpoint can can change
> which mounts are available to be unmounted during mount propagation
> which is wrong.
>
> The trivial reproducer is:
> $ cat ./pathological.sh
>
> mount -t tmpfs test-base /mnt
> cd /mnt
> mkdir 1 2 1/1
> mount --bind 1 1
> mount --make-shared 1
> mount --bind 1 2
> mount --bind 1/1 1/1
> mount --bind 1/1 1/1
> echo
> grep test-base /proc/self/mountinfo
> umount 1/1
> echo
> grep test-base /proc/self/mountinfo
>
> $ unshare -Urm ./pathological.sh
>
> The expected output looks like:
> 46 31 0:25 / /mnt rw,relatime - tmpfs test-base rw,uid=1000,gid=1000
> 47 46 0:25 /1 /mnt/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 48 46 0:25 /1 /mnt/2 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 49 54 0:25 /1/1 /mnt/1/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 50 53 0:25 /1/1 /mnt/2/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 51 49 0:25 /1/1 /mnt/1/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 54 47 0:25 /1/1 /mnt/1/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 53 48 0:25 /1/1 /mnt/2/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 52 50 0:25 /1/1 /mnt/2/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
>
> 46 31 0:25 / /mnt rw,relatime - tmpfs test-base rw,uid=1000,gid=1000
> 47 46 0:25 /1 /mnt/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 48 46 0:25 /1 /mnt/2 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
>
> The output without the fix looks like:
> 46 31 0:25 / /mnt rw,relatime - tmpfs test-base rw,uid=1000,gid=1000
> 47 46 0:25 /1 /mnt/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 48 46 0:25 /1 /mnt/2 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 49 54 0:25 /1/1 /mnt/1/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 50 53 0:25 /1/1 /mnt/2/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 51 49 0:25 /1/1 /mnt/1/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 54 47 0:25 /1/1 /mnt/1/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 53 48 0:25 /1/1 /mnt/2/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 52 50 0:25 /1/1 /mnt/2/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
>
> 46 31 0:25 / /mnt rw,relatime - tmpfs test-base rw,uid=1000,gid=1000
> 47 46 0:25 /1 /mnt/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 48 46 0:25 /1 /mnt/2 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
> 52 48 0:25 /1/1 /mnt/2/1 rw,relatime shared:1 - tmpfs test-base rw,uid=1000,gid=1000
>
> That last mount in the output was in the propgation tree to be unmounted but
> was missed because the mnt_change_mountpoint changed it's parent before the walk
> through the mount propagation tree observed it.
>
It works for me and the patch looks correct. Thanks!
Acked-by: Andrei Vagin <avagin@virtuozzo.com>
> Cc: stable@vger.kernel.org
> Fixes: 1064f874abc0 ("mnt: Tuck mounts under others instead of creating shadow/side mounts.")
> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
> ---
> fs/mount.h | 1 +
> fs/namespace.c | 1 +
> fs/pnode.c | 35 ++++++++++++++++++++++++++++++-----
> 3 files changed, 32 insertions(+), 5 deletions(-)
>
> diff --git a/fs/mount.h b/fs/mount.h
> index bf1fda6eed8f..ede5a1d5cf99 100644
> --- a/fs/mount.h
> +++ b/fs/mount.h
> @@ -58,6 +58,7 @@ struct mount {
> struct mnt_namespace *mnt_ns; /* containing namespace */
> struct mountpoint *mnt_mp; /* where is it mounted */
> struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
> + struct list_head mnt_reparent; /* reparent list entry */
> #ifdef CONFIG_FSNOTIFY
> struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
> __u32 mnt_fsnotify_mask;
> diff --git a/fs/namespace.c b/fs/namespace.c
> index 8bd3e4d448b9..51e49866e1fe 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -236,6 +236,7 @@ static struct mount *alloc_vfsmnt(const char *name)
> INIT_LIST_HEAD(&mnt->mnt_slave_list);
> INIT_LIST_HEAD(&mnt->mnt_slave);
> INIT_HLIST_NODE(&mnt->mnt_mp_list);
> + INIT_LIST_HEAD(&mnt->mnt_reparent);
> init_fs_pin(&mnt->mnt_umount, drop_mountpoint);
> }
> return mnt;
> diff --git a/fs/pnode.c b/fs/pnode.c
> index 5bc7896d122a..52aca0a118ff 100644
> --- a/fs/pnode.c
> +++ b/fs/pnode.c
> @@ -439,7 +439,7 @@ static void mark_umount_candidates(struct mount *mnt)
> * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
> * parent propagates to.
> */
> -static void __propagate_umount(struct mount *mnt)
> +static void __propagate_umount(struct mount *mnt, struct list_head *to_reparent)
> {
> struct mount *parent = mnt->mnt_parent;
> struct mount *m;
> @@ -464,17 +464,38 @@ static void __propagate_umount(struct mount *mnt)
> */
> topper = find_topper(child);
> if (topper)
> - mnt_change_mountpoint(child->mnt_parent, child->mnt_mp,
> - topper);
> + list_add_tail(&topper->mnt_reparent, to_reparent);
>
> - if (list_empty(&child->mnt_mounts)) {
> + if (topper || list_empty(&child->mnt_mounts)) {
> list_del_init(&child->mnt_child);
> + list_del_init(&child->mnt_reparent);
> child->mnt.mnt_flags |= MNT_UMOUNT;
> list_move_tail(&child->mnt_list, &mnt->mnt_list);
> }
> }
> }
>
> +static void reparent_mounts(struct list_head *to_reparent)
> +{
> + while (!list_empty(to_reparent)) {
> + struct mount *mnt, *parent;
> + struct mountpoint *mp;
> +
> + mnt = list_first_entry(to_reparent, struct mount, mnt_reparent);
> + list_del_init(&mnt->mnt_reparent);
> +
> + /* Where should this mount be reparented to? */
> + mp = mnt->mnt_mp;
> + parent = mnt->mnt_parent;
> + while (parent->mnt.mnt_flags & MNT_UMOUNT) {
> + mp = parent->mnt_mp;
> + parent = parent->mnt_parent;
> + }
> +
> + mnt_change_mountpoint(parent, mp, mnt);
> + }
> +}
> +
> /*
> * collect all mounts that receive propagation from the mount in @list,
> * and return these additional mounts in the same list.
> @@ -485,11 +506,15 @@ static void __propagate_umount(struct mount *mnt)
> int propagate_umount(struct list_head *list)
> {
> struct mount *mnt;
> + LIST_HEAD(to_reparent);
>
> list_for_each_entry_reverse(mnt, list, mnt_list)
> mark_umount_candidates(mnt);
>
> list_for_each_entry(mnt, list, mnt_list)
> - __propagate_umount(mnt);
> + __propagate_umount(mnt, &to_reparent);
> +
> + reparent_mounts(&to_reparent);
> +
> return 0;
> }
> --
> 2.10.1
>
next prev parent reply other threads:[~2017-05-15 23:12 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-31 4:10 [PATCH] Fix a race in put_mountpoint Krister Johansen
2016-12-31 6:17 ` Al Viro
2017-01-03 0:51 ` Eric W. Biederman
2017-01-03 1:48 ` Al Viro
2017-01-03 3:17 ` Eric W. Biederman
2017-01-03 4:00 ` Al Viro
2017-01-04 3:52 ` Eric W. Biederman
2017-01-04 3:53 ` [PATCH] mnt: Protect the mountpoint hashtable with mount_lock Eric W. Biederman
2017-01-04 21:04 ` [REVIEW][PATCH] mnt: Tuck mounts under others instead of creating shadow/side mounts Eric W. Biederman
2017-01-07 5:06 ` Al Viro
2017-01-11 0:10 ` Eric W. Biederman
2017-01-11 4:11 ` Al Viro
2017-01-11 16:03 ` Eric W. Biederman
2017-01-11 16:18 ` [REVIEW][PATCH 1/2] mnt: Fix propagate_mount_busy to notice all cases of busy mounts Eric W. Biederman
2017-01-11 16:19 ` [REVIEW][PATCH 2/2] mnt: Tuck mounts under others instead of creating shadow/side mounts Eric W. Biederman
2017-01-12 5:45 ` Al Viro
2017-01-20 7:20 ` Eric W. Biederman
2017-01-20 7:26 ` [PATCH v5] " Eric W. Biederman
2017-01-21 3:58 ` Ram Pai
2017-01-21 4:15 ` Eric W. Biederman
2017-01-23 19:02 ` Ram Pai
2017-01-24 0:16 ` Eric W. Biederman
2017-02-03 10:54 ` Eric W. Biederman
2017-02-03 17:10 ` Ram Pai
2017-02-03 18:26 ` Eric W. Biederman
2017-02-03 20:28 ` Ram Pai
2017-02-03 20:58 ` Eric W. Biederman
2017-02-06 3:25 ` Andrei Vagin
2017-02-06 21:40 ` Ram Pai
2017-02-07 6:35 ` Andrei Vagin
2017-01-12 5:30 ` [REVIEW][PATCH 1/2] mnt: Fix propagate_mount_busy to notice all cases of busy mounts Al Viro
2017-01-20 7:18 ` Eric W. Biederman
2017-01-13 20:32 ` Andrei Vagin
2017-01-18 19:20 ` Andrei Vagin
2017-01-20 23:18 ` Ram Pai
2017-01-23 8:15 ` Eric W. Biederman
2017-01-23 17:04 ` Ram Pai
2017-01-12 5:03 ` [REVIEW][PATCH] mnt: Tuck mounts under others instead of creating shadow/side mounts Al Viro
2017-05-14 2:15 ` Andrei Vagin
2017-05-14 4:05 ` Eric W. Biederman
2017-05-14 9:26 ` Eric W. Biederman
2017-05-15 18:27 ` Andrei Vagin
2017-05-15 19:42 ` Eric W. Biederman
2017-05-15 20:10 ` [REVIEW][PATCH] mnt: In umount propagation reparent in a separate pass Eric W. Biederman
2017-05-15 23:12 ` Andrei Vagin [this message]
2017-05-16 5:42 ` [PATCH] test: check a case when a mount is propagated between exiting mounts Andrei Vagin
2017-05-17 5:54 ` [REVIEW][PATCH 1/2] mnt: In propgate_umount handle visiting mounts in any order Eric W. Biederman
2017-05-17 5:55 ` [REVIEW][PATCH 2/2] mnt: Make propagate_umount less slow for overlapping mount propagation trees Eric W. Biederman
2017-05-17 22:48 ` Andrei Vagin
2017-05-17 23:26 ` Eric W. Biederman
2017-05-18 0:51 ` Andrei Vagin
2017-05-24 20:42 ` [REVIEW][PATCH 1/2] mnt: In propgate_umount handle visiting mounts in any order Ram Pai
2017-05-24 21:54 ` Eric W. Biederman
2017-05-24 22:35 ` Ram Pai
2017-05-30 6:07 ` Ram Pai
2017-05-30 15:07 ` Eric W. Biederman
2017-06-07 9:54 ` Ram Pai
2017-06-07 13:09 ` Eric W. Biederman
2017-05-22 8:15 ` [REVIEW][PATCH] mnt: In umount propagation reparent in a separate pass Ram Pai
2017-05-22 18:33 ` Eric W. Biederman
2017-05-22 22:34 ` Ram Pai
2017-05-23 13:58 ` Eric W. Biederman
2017-01-06 7:00 ` [PATCH] mnt: Protect the mountpoint hashtable with mount_lock Krister Johansen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170515231243.GA2430@outlook.office365.com \
--to=avagin@virtuozzo.com \
--cc=ebiederm@xmission.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linuxram@us.ibm.com \
--cc=viro@ZenIV.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.