[CRIU] [PATCH 2/6] mnt: add --ext-mount-map auto option

Tycho Andersen tycho.andersen at canonical.com
Tue Apr 7 16:37:17 PDT 2015


When this option is specified, if an external (private) bind mount is not
specified by --ext-mount-map KEY:VAL then it is attempted to be resolved
automatically.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 crtools.c            |   7 ++
 include/cr_options.h |   1 +
 mount.c              | 178 +++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 165 insertions(+), 21 deletions(-)

diff --git a/crtools.c b/crtools.c
index 9a0902d..a6ee2d7 100644
--- a/crtools.c
+++ b/crtools.c
@@ -425,6 +425,11 @@ int main(int argc, char *argv[], char *envp[])
 			{
 				char *aux;
 
+				if (strcmp(optarg, "auto") == 0) {
+					opts.autodetect_ext_mounts = true;
+					break;
+				}
+
 				aux = strchr(optarg, ':');
 				if (aux == NULL)
 					goto bad_arg;
@@ -642,6 +647,8 @@ usage:
 "  --force-irmap         force resolving names for inotify/fsnotify watches\n"
 "  -M|--ext-mount-map KEY:VALUE\n"
 "                        add external mount mapping\n"
+"  -M|--ext-mount-map auto\n"
+"                        attempt to autodetect external mount mapings\n"
 "  --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/include/cr_options.h b/include/cr_options.h
index 27102b7..f1cfc84 100644
--- a/include/cr_options.h
+++ b/include/cr_options.h
@@ -62,6 +62,7 @@ struct cr_options {
 	bool			manage_cgroups;
 	char			*new_global_cg_root;
 	struct list_head	new_cgroup_roots;
+	bool			autodetect_ext_mounts;
 	bool			aufs;		/* auto-deteced, not via cli */
 };
 
diff --git a/mount.c b/mount.c
index c4c2c86..49a07dd 100644
--- a/mount.c
+++ b/mount.c
@@ -601,11 +601,15 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
 				int ret;
 
 				if (for_dump) {
-					ret = run_plugins(DUMP_EXT_MOUNT, m->mountpoint, m->mnt_id);
-					if (ret == 0)
-						m->need_plugin = true;
-					else if (ret == -ENOTSUP)
-						ret = try_resolve_ext_mount(m);
+					// We've already resolved the mount
+					// and it is external.
+					if (m->external) {
+						ret = 0;
+					} else {
+						ret = run_plugins(DUMP_EXT_MOUNT, m->mountpoint, m->mnt_id);
+						if (ret == 0)
+							m->need_plugin = true;
+					}
 				} else {
 					if (m->need_plugin || m->external)
 						/*
@@ -641,7 +645,92 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
 	return 0;
 }
 
-static int collect_shared(struct mount_info *info)
+static int resolve_external_mounts(struct mount_info *info)
+{
+	struct mount_info *m;
+
+	for (m = info; m; m = m->next) {
+		struct mount_info *pm;
+		bool found = false;
+		struct ns_id *ns = NULL, *iter;
+		int ret;
+
+		if (m->parent == NULL || m->is_ns_root)
+			continue;
+
+		ret = try_resolve_ext_mount(m);
+		if (ret < 0 && ret != -ENOTSUP) {
+			return -1;
+		} else if (ret == -ENOTSUP && !opts.autodetect_ext_mounts) {
+			continue;
+		} else if (ret == 0) {
+			continue;
+		}
+
+		for (iter = ns_ids; iter->next; iter = iter->next) {
+			if (iter->pid == getpid() && iter->nd == &mnt_ns_desc) {
+				ns = iter;
+				break;
+			}
+		}
+
+		if (!ns) {
+			pr_err("Failed to find criu pid's mount ns!");
+			return -1;
+		}
+
+		for (pm = ns->mnt.mntinfo_list; pm; pm = pm->next) {
+			int size, ret;
+			char *p;
+			bool match = false;
+			struct ext_mount *em;
+
+			if (mounts_equal(pm, m, true))
+				match = true;
+
+			if (!match)
+				continue;
+
+			size = strlen(pm->mountpoint + 1) + strlen(m->root) + 1;
+			p = xmalloc(sizeof(char) * size);
+			if (!p)
+				return -1;
+
+			ret = snprintf(p, size+1, "%s%s", pm->mountpoint + 1, m->root);
+			if (ret < 0 || ret >= size) {
+				free(p);
+				return -1;
+			}
+
+			em = xmalloc(sizeof(struct ext_mount));
+			if (!em) {
+				free(p);
+				return -1;
+			}
+
+			em->val = "CRIU:AUTOGENERATED";
+			em->key = p;
+			m->external = em;
+
+			pr_info("autodetected external mount %s for %s\n", p, m->mountpoint);
+			xfree(m->source);
+			m->source = p;
+
+			found = true;
+			break;
+		}
+
+		if (!found) {
+			pr_info("couldn't find external bind mount for %d %s "
+				"(master_id: %d shared_id: %d)\n",
+				m->mnt_id, m->mountpoint, m->master_id, m->shared_id);
+		}
+	}
+
+	return 0;
+}
+
+static int collect_shared(struct mount_info *info, bool for_dump)
 {
 	struct mount_info *m, *t;
 
@@ -675,10 +764,12 @@ 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);
+		// If we haven't already determined this mount is external,
+		// then we don't know where it came from.
+		if (need_master && m->parent && !m->external) {
+			pr_err("Mount %d %s (master_id: %d shared_id: %d) "
+			       "has unreachable sharing. Try --enable-external-masters.\n", m->mnt_id,
+				m->mountpoint, m->master_id, m->shared_id);
 			return -1;
 		}
 
@@ -1594,6 +1685,9 @@ static bool can_mount_now(struct mount_info *mi)
 	if (mi->is_ns_root)
 		return true;
 
+	if (mi->external)
+		return true;
+
 	if (mi->master_id && mi->bind == NULL)
 		return false;
 
@@ -1880,6 +1974,11 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
 		pm->need_plugin		= me->with_plugin;
 		pm->is_ns_root		= is_root(me->mountpoint);
 
+		pr_debug("\t\tGetting source for %d\n", pm->mnt_id);
+		pm->source = xstrdup(me->source);
+		if (!pm->source)
+			goto err;
+
 		/* FIXME: abort unsupported early */
 		pm->fstype		= decode_fstype(me->fstype);
 
@@ -1893,8 +1992,29 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
 
 			em = ext_mount_lookup(me->root);
 			if (!em) {
-				pr_err("No mapping for %s mountpoint\n", me->mountpoint);
-				goto err;
+				if (!opts.autodetect_ext_mounts) {
+					pr_err("No mapping for %s mountpoint\n", me->mountpoint);
+					goto err;
+				}
+
+				/*
+				 * Make up an external mount entry for this
+				 * mount point, since we couldn't find a user
+				 * supplied one.
+				 */
+				em = xmalloc(sizeof(struct ext_mount));
+				if (!em)
+					goto err;
+
+				em->val = pm->source;
+
+				/*
+				 * Put a : in here since those are invalid on
+				 * the cli, so we know it's autogenerated in
+				 * debugging.
+				 */
+				em->key = "CRIU:AUTOGENERATED";
+				list_add_tail(&em->l, &opts.ext_mounts);
 			}
 
 			pm->external = em;
@@ -1926,11 +2046,6 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
 
 		pr_debug("\t\tGetting mpt for %d %s\n", pm->mnt_id, pm->mountpoint);
 
-		pr_debug("\t\tGetting source for %d\n", pm->mnt_id);
-		pm->source = xstrdup(me->source);
-		if (!pm->source)
-			goto err;
-
 		pr_debug("\t\tGetting opts for %d\n", pm->mnt_id);
 		pm->options = xstrdup(me->options);
 		if (!pm->options)
@@ -2108,7 +2223,7 @@ static int populate_mnt_ns(struct mount_info *mis)
 	if (!pms)
 		return -1;
 
-	if (collect_shared(mis))
+	if (collect_shared(mis, false))
 		return -1;
 
 	for (nsid = ns_ids; nsid; nsid = nsid->next) {
@@ -2346,6 +2461,7 @@ int mntns_get_root_by_mnt_id(int mnt_id)
 struct collect_mntns_arg {
 	bool need_to_validate;
 	bool for_dump;
+	bool really_collect_self_mounts;
 };
 
 static int collect_mntns(struct ns_id *ns, void *__arg)
@@ -2360,7 +2476,8 @@ static int collect_mntns(struct ns_id *ns, void *__arg)
 	if (arg->for_dump && ns->pid != getpid())
 		arg->need_to_validate = true;
 
-	mntinfo_add_list(pms);
+	if (!opts.autodetect_ext_mounts || ns->pid != getpid() || arg->really_collect_self_mounts)
+		mntinfo_add_list(pms);
 	return 0;
 }
 
@@ -2371,15 +2488,34 @@ int collect_mnt_namespaces(bool for_dump)
 
 	arg.for_dump = for_dump;
 	arg.need_to_validate = false;
+	arg.really_collect_self_mounts = false;
 
-	ret = walk_namespaces(&mnt_ns_desc, false, collect_mntns, &need_to_validate);
+	/*
+	 * XXX: this is a little bit of spaghetti. If we are autodetecting
+	 * external mounts, we want to collect the criu pid's mountinfo (and
+	 * thus the whole mountns) so we can corrolate the external masters.
+	 * So we clear the mountns bit for this call to walk_namespaces.
+	 *
+	 * However, we don't want to add criu's mountns to the dump target
+	 * list if it isn't really going to be dumped, so we set the
+	 * really_collect_self_mounts flag if we really do want to collect
+	 * them above.
+	 */
+	if (opts.autodetect_ext_mounts && !(root_ns_mask & CLONE_NEWNS)) {
+		arg.really_collect_self_mounts = true;
+	}
+
+	ret = walk_namespaces(&mnt_ns_desc, opts.autodetect_ext_mounts, collect_mntns, &arg);
 	if (ret)
 		goto err;
 
+	if (resolve_external_mounts(mntinfo))
+		goto err;
+
 	if (arg.need_to_validate) {
 		ret = -1;
 
-		if (collect_shared(mntinfo))
+		if (collect_shared(mntinfo, true))
 			goto err;
 		if (validate_mounts(mntinfo, true))
 			goto err;
-- 
2.1.4



More information about the CRIU mailing list