[CRIU] [PATCH] mount: Umount nested temporary mount pathes in do_bind_mount()

Andrew Vagin avagin at virtuozzo.com
Tue Mar 1 15:52:19 PST 2016


On Fri, Feb 26, 2016 at 01:43:13PM +0300, Kirill Tkhai wrote:
> Hi, Andrew,
> 
> On 26.02.2016 03:47, Andrew Vagin wrote:
> > On Thu, Feb 25, 2016 at 04:54:27PM +0300, Kirill Tkhai wrote:
> >> When a parent directory of restored mount is bound to itself,
> >> a temporary mount is cloned, so we need to umount it twice:
> >>
> >> # mkdir -p parent/child /tmp/cr-XXX
> >> # mount --bind parent parent
> >> # mount --bind parent/child /tmp/cr-XXX/
> >> # mount --bind /tmp/cr-XXX/ parent/child
> >> # umount /tmp/cr-XXX/
> >> # mount | grep "/tmp/cr-XXX"
> >> /dev/sda3 on /tmp/cr-XXX type ext4 (rw,noatime,nodiratime,data=ordered)
> >>
> >> Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
> >> ---
> >>  criu/mount.c |   27 ++++++++++++++++++++++++++-
> >>  1 file changed, 26 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/criu/mount.c b/criu/mount.c
> >> index 1a6b034..bce2465 100644
> >> --- a/criu/mount.c
> >> +++ b/criu/mount.c
> >> @@ -301,6 +301,26 @@ static bool mounts_equal(struct mount_info *a, struct mount_info *b)
> >>  }
> >>  
> >>  /*
> >> + * Successively umount all file systems mounted on @path
> >> + */
> >> +static int umount2_nested(const char *path, int flags)
> >> +{
> >> +	bool once = true;
> >> +	int ret;
> >> +
> >> +	while (1) {
> >> +		ret = umount2(path, flags);
> >> +		if (ret)
> >> +			break;
> >> +		once = false;
> >> +	}
> >> +
> >> +	if (once || errno != EINVAL)
> >> +		return -1;
> >> +	return 0;
> >> +}
> >> +
> >> +/*
> >>   * mnt_roots is a temporary directory for restoring sub-trees of
> >>   * non-root namespaces.
> >>   */
> >> @@ -2397,7 +2417,12 @@ static int do_bind_mount(struct mount_info *mi)
> >  if (mount(NULL, mnt_path, NULL, MS_PRIVATE, NULL)) {
> > 
> > I think we don't need to make it private ^^^^, because it may be
> > propagated to somewhere. Kirll, could you try to remove your changes and
> > this mount and check that everythink works as expected in this case.
> 
> No, it does not help. MS_PRIVATE would affect on child mounts, while the problem
> is with parent. Try this example
> 
> # mkdir -p parent/child /tmp/cr-XXX
> # mount --bind parent parent
> # mount --bind parent/child /tmp/cr-XXX/
> # mount --bind /tmp/cr-XXX/ parent/child
> # mount
> /dev/sda2 on /tmp/cr-XXX type ext4 (rw,relatime,data=ordered)
> /dev/sda2 on /root/parent/child type ext4 (rw,relatime,data=ordered)
> /dev/sda2 on /tmp/cr-XXX type ext4 (rw,relatime,data=ordered)
> /dev/sda2 on /root/parent/child type ext4 (rw,relatime,data=ordered)
> 
> Nothing changes if you modify /tmp/cr-XXX or /root/parent/child
> subtree type now.
> 
> The only different solution in our example is to make ./parent MS_PRIVATE
> right after it's bound to itself. Common solution will require to traverse
> to top of the tree and check every parent subtree type, and do it private,
> if it's need, and after all to return everything back. But it's too complex.

You can't recreate shared dependences for mounts.

The patch is incorrect, because "umount /tmp/cr-XXX" will umount
/tmp/cr-XXX and parent/child

[root at fc22-vm tmp]# bash -x test.sh 
+ mkdir -p parent/child /tmp/cr-XXX
+ mount --bind parent parent
+ mount --bind parent/child /tmp/cr-XXX/
+ mount --bind /tmp/cr-XXX/ parent/child
+ mount --make-private /tmp/cr-XXX/
+ umount /tmp/cr-XXX/
+ umount /tmp/cr-XXX/
+ mount
+ grep parent
/dev/vda2 on /root/tmp/parent type ext4 (rw,relatime,data=ordered)

[root at fc22-vm tmp]# cat test.sh 
mkdir -p parent/child /tmp/cr-XXX
mount --bind parent parent
mount --bind parent/child /tmp/cr-XXX/
mount --bind /tmp/cr-XXX/ parent/child
mount --make-private /tmp/cr-XXX/
umount /tmp/cr-XXX/
umount /tmp/cr-XXX/
mount | grep parent

I really recomend to write tests for such sort of problems.

I don't know how to fix this problem. Will think...

Let me know if you have any ideas.
> 
> Regards,
> Kirill
> >>  			pr_perror("Unable to make %s private", mnt_path);
> >>  			return -1;
> >>  		}
> >> -		if (umount2(mnt_path, MNT_DETACH)) {
> >> +		/*
> >> +		 * If mi and mi->bind have the same mountpoint, and
> >> +		 * a parent dir of the mountpoint is bound to itself,
> >> +		 * then we have several mounts on mnt_path.
> >> +		 */
> >> +		if (umount2_nested(mnt_path, MNT_DETACH)) {
> >>  			pr_perror("Unable to umount %s", mnt_path);
> >>  			return -1;
> >>  		}
> >>
> >> _______________________________________________
> >> CRIU mailing list
> >> CRIU at openvz.org
> >> https://lists.openvz.org/mailman/listinfo/criu


More information about the CRIU mailing list