[CRIU] [PATCH] mnt: add support for external shared mounts

Pavel Emelyanov xemul at parallels.com
Fri Apr 3 04:44:23 PDT 2015


On 04/02/2015 11:22 PM, Tycho Andersen wrote:
> Add support for external shared mounts via the --enable-external-masters flag.
> This flag assumes that the mount is visible to criu via /proc/self/mountinfo
> and that it will be present at the same location on restore. No attempt to dump
> or restore the content is made; the external master is bind mounted into the
> mount ns and whatever is there is what the container sees.
> 
> Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>

Thanks :) Please, find my comments and questions inline.

> ---
>  crtools.c            |   6 +++
>  include/cr_options.h |   1 +
>  include/proc_parse.h |   1 +
>  mount.c              | 115 +++++++++++++++++++++++++++++++++++++++++++++------
>  protobuf/mnt.proto   |   2 +
>  5 files changed, 112 insertions(+), 13 deletions(-)
> 

> @@ -637,6 +641,8 @@ usage:
>  "  --force-irmap         force resolving names for inotify/fsnotify watches\n"
>  "  -M|--ext-mount-map KEY:VALUE\n"
>  "                        add external mount mapping\n"
> +"  --enable-external-masters\n"
> +"                        Allow mounts with external masters\n"

Nitpick -- help text starts with small letter :)

>  "  --manage-cgroups      dump or restore cgroups the process is in\n"
>  "  --cgroup-root [controller:]/newroot\n"
>  "                        change the root cgroup the controller will be\n"

> diff --git a/mount.c b/mount.c
> index 021c6e3..cbdad87 100644
> --- a/mount.c
> +++ b/mount.c
> @@ -566,6 +566,9 @@ static struct mount_info *find_fsroot_mount_for(struct mount_info *bm)
>  	return NULL;
>  }
>  
> +struct mount_info *external_mounts = NULL;

AFAIU the external_mounts is regular mounts list but collected for criu's
mount namespace. We already have ns_id object for criu and it has the
mnt.mntinfo_list/_tree fields. One thing is that in collect_mnt_namespaces()
we don't collect criu's one when we dump container.

Can fix the existing collection code to have the criu's ns_id collected
in case the --enable-external-masters is specified?

> +static int try_resolve_external_sharing(struct mount_info *m);
> +
>  static int validate_mounts(struct mount_info *info, bool for_dump)
>  {
>  	struct mount_info *m, *t;
> @@ -578,6 +581,11 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
>  		if (m->shared_id && validate_shared(m))
>  			return -1;
>  
> +		if (m->master_id && opts.enable_external_masters) {
> +			if (try_resolve_external_sharing(m) == 0)

Shouldn't this be in collect_shared()? Validation is just checking that
the tree is in dumpable state, while any interconnections are be set in
other places.

> +				continue;
> +		}
> +
>  		/*
>  		 * Mountpoint can point to / of an FS. In that case this FS
>  		 * should be of some known type so that we can just mount one.

> @@ -676,10 +685,28 @@ static int collect_shared(struct mount_info *info)
>  		}
>  
>  		if (need_master && m->parent) {
> -			pr_err("Mount %d (master_id: %d shared_id: %d) "
> -			       "has unreachable sharing\n", m->mnt_id,
> -				m->master_id, m->shared_id);
> -			return -1;
> +			if (opts.enable_external_masters) {
> +				struct mount_info *pm;
> +				bool found = false;
> +
> +				for (pm = external_mounts; pm->next != NULL; pm = pm->next) {
> +					if (pm->shared_id == m->master_id) {
> +						found = true;
> +						break;
> +					}

I mean this place -- once we foung shared_id == master_id we do the body
of try_resolve_external_mount().

> +				}
> +
> +				if (!found) {
> +					pr_err("couldn't find sharing for %d "
> +						"(master_id: %d shared_id: %d)",
> +						m->mnt_id, m->master_id, m->shared_id);
> +				}
> +			} else {
> +				pr_err("Mount %d (master_id: %d shared_id: %d) "
> +				       "has unreachable sharing. Try --enable-external-masters.\n", m->mnt_id,
> +					m->master_id, m->shared_id);
> +				return -1;
> +			}
>  		}
>  
>  		/* Search bind-mounts */

> @@ -1302,7 +1335,7 @@ again:
>  	if (!progress) {
>  		struct mount_info *m;
>  
> -		pr_err("A few mount points can't be mounted");
> +		pr_err("A few mount points can't be mounted\n");

I'd appreciate fixes and cleanups to be sent separately :)

>  		list_for_each_entry(m, &postpone2, postpone) {
>  			pr_err("%d:%d %s %s %s\n", m->mnt_id,
>  				m->parent_mnt_id, m->root,
> @@ -1475,17 +1508,19 @@ static int do_new_mount(struct mount_info *mi)
>  		return -1;
>  
>  	if (mount(src, mi->mountpoint, tp->name,
> -			mi->flags & (~MS_SHARED), mi->options) < 0) {
> +			mi->flags & ~(MS_SLAVE | MS_SHARED), mi->options) < 0) {

What if mountpoint is not slave? Doesn't this hunk break the existing restore?

>  		pr_perror("Can't mount at %s", mi->mountpoint);
>  		return -1;
>  	}
>  
> -	if (restore_shared_options(mi, 0, mi->shared_id, 0))
> +	if (restore_shared_options(mi, 0, mi->shared_id, mi->flags & MS_SLAVE || mi->external_master))
>  		return -1;
>  
>  	mi->mounted = true;
>  
> -	if (tp->restore && tp->restore(mi))
> +	// If there is an external master, the content of the mount comes from
> +	// there; otherwise, we restore it as usual.

We try to follow kernel coding style which encourages usage of /**/-style
comments. Please :)

> +	if (!mi->external_master && tp->restore && tp->restore(mi))
>  		return -1;
>  
>  	return 0;

-- Pavel


More information about the CRIU mailing list