[CRIU] [PATCH v2] mount: don't overmount a mount if it should be bind-mounted somewhere

Andrew Vagin avagin at virtuozzo.com
Thu May 5 00:24:58 PDT 2016


On Tue, May 03, 2016 at 02:11:24PM -0700, Andrew Vagin wrote:
> On Tue, May 03, 2016 at 08:55:50AM +0300, Andrey Vagin wrote:
> > From: Andrew Vagin <avagin at virtuozzo.com>
> > 
> > It's impossiable to make a bind-mount if a source is overmounted.
> > 
> > v2: make a bind-mount from an underlying mount via a file descriptor
> 
> Unfortunately this way doesn't work for autofs. Stat, could you give any
> comment about this error?
> 
> (00.390353)      1: Error (mount.c:2483): mnt: Can't mount at .criu.mntns.s2mn7B/14/proc/sys/fs/binfmt_misc: Too many levels of symbolic links

I found an answer why we get ELOOP:

Documentation/filesystems/autofs4.txt

	The automount daemon is only able to mange a single mount location for
	an autofs filesystem and if mounts on that are not 'shared', other
	locations will not behave as expected.  In particular access to those
	other locations will likely result in the `ELOOP` error

So this patch is correct.

Today I found a real reason why we have a problem to dump and restore a
clean container with a binfmt_misc mount and httpd.

httpd lives in a separate mount namespace. An autofs mount is a shared
mount and binfmt_misc is a child of it, so we need to mount autofs in
both namespaces and only then mount binfmt_misc.

This logic should be fixed by these patches:

mount: handle a case when parent and child mounts in the same directory
mount: remove an extra condition from mounts_equal()

> 
> Thanks,
> Andrew
> 
> > 
> > Reported-by: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
> > Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
> > ---
> >  criu/include/mount.h |  1 +
> >  criu/mount.c         | 27 +++++++++++++++++++++++----
> >  2 files changed, 24 insertions(+), 4 deletions(-)
> > 
> > diff --git a/criu/include/mount.h b/criu/include/mount.h
> > index 59e7f9a..c7992ac 100644
> > --- a/criu/include/mount.h
> > +++ b/criu/include/mount.h
> > @@ -49,6 +49,7 @@ struct mount_info {
> >  	 */
> >  	char			*mountpoint;
> >  	char			*ns_mountpoint;
> > +	int			fd;
> >  	unsigned		flags;
> >  	unsigned		sb_flags;
> >  	int			master_id;
> > diff --git a/criu/mount.c b/criu/mount.c
> > index 0b1c2ba..6133a72 100644
> > --- a/criu/mount.c
> > +++ b/criu/mount.c
> > @@ -2447,11 +2447,15 @@ static int do_bind_mount(struct mount_info *mi)
> >  	 */
> >  	mi->private = mi->bind->private;
> >  
> > -	if (list_empty(&mi->bind->children))
> > -		mnt_path = mi->bind->mountpoint;
> > -	else {
> > +	mnt_path = mi->bind->mountpoint;
> > +	if (mi->bind->fd >= 0) {
> > +		snprintf(rpath, sizeof(rpath), "/proc/self/fd/%d", mi->bind->fd);
> > +		mnt_path = rpath;
> > +	}
> > +
> > +	if (!list_empty(&mi->bind->children)) {
> >  		/* mi->bind->mountpoint may be overmounted */
> > -		if (mount(mi->bind->mountpoint, mnt_clean_path, NULL, MS_BIND, NULL)) {
> > +		if (mount(mnt_path, mnt_clean_path, NULL, MS_BIND, NULL)) {
> >  			pr_perror("Unable to bind-mount %s to %s",
> >  					mi->bind->mountpoint, mnt_clean_path);
> >  		}
> > @@ -2606,6 +2610,11 @@ static int do_mount_root(struct mount_info *mi)
> >  	return fetch_rt_stat(mi, mi->mountpoint);
> >  }
> >  
> > +static int do_close_one(struct mount_info *mi) {
> > +	close_safe(&mi->fd);
> > +	return 0;
> > +}
> > +
> >  static int do_mount_one(struct mount_info *mi)
> >  {
> >  	int ret;
> > @@ -2618,6 +2627,14 @@ static int do_mount_one(struct mount_info *mi)
> >  		return 1;
> >  	}
> >  
> > +	if (mi->parent && !strcmp(mi->parent->mountpoint, mi->mountpoint)) {
> > +		mi->parent->fd = open(mi->parent->mountpoint, O_PATH);
> > +		if (mi->parent->fd < 0) {
> > +			pr_perror("Unable to open %s", mi->mountpoint);
> > +			return -1;
> > +		}
> > +	}
> > +
> >  	pr_debug("\tMounting %s @%s (%d)\n", mi->fstype->name, mi->mountpoint, mi->need_plugin);
> >  
> >  	if (!mi->parent) {
> > @@ -2740,6 +2757,7 @@ struct mount_info *mnt_entry_alloc()
> >  
> >  	new = xzalloc(sizeof(struct mount_info));
> >  	if (new) {
> > +		new->fd = -1;
> >  		INIT_LIST_HEAD(&new->children);
> >  		INIT_LIST_HEAD(&new->siblings);
> >  		INIT_LIST_HEAD(&new->mnt_slave_list);
> > @@ -3211,6 +3229,7 @@ static int populate_mnt_ns(void)
> >  		return -1;
> >  
> >  	ret = mnt_tree_for_each(pms, do_mount_one);
> > +	mnt_tree_for_each(pms, do_close_one);
> >  
> >  	if (umount_clean_path())
> >  		return -1;
> > -- 
> > 2.5.5
> > 


More information about the CRIU mailing list