[CRIU] [PATCH 4/5] mount: migrate bindmounts of external mounts

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Tue Mar 21 01:34:52 PDT 2017


If container has external bindmount given to criu through
--ext-mount-map option by admin, container user can bindmount
subdirs of these external bindmount to somewhere else inside
container creating secondary external bindmounts. Criu we will
fail to restore them as having unreachable sharing. But we can
restore secondary external bindmounts bindmounting them from
primary external bindmount.

https://jira.sw.ru/browse/PSBM-46753

v2: s/external_bind/mnt_is_external/, make mnt_is_external bool,
do mnt_is_external without recursion
v3: add debug message on propagate_mount when bind is set
v4: put NO_ROOT_MOUNT in root instead of external index

Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 criu/mount.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/criu/mount.c b/criu/mount.c
index ef5c1ec..d62813e 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -35,6 +35,7 @@
  * debugging.
  */
 #define AUTODETECTED_MOUNT "CRIU:AUTOGENERATED"
+#define NO_ROOT_MOUNT "CRIU:NO_ROOT"
 #define MS_PROPAGATE (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE | MS_SLAVE)
 
 #undef	LOG_PREFIX
@@ -644,6 +645,36 @@ static bool does_mnt_overmount(struct mount_info *m)
 	return false;
 }
 
+/*
+ * Say mount is external if it was explicitly specified as an
+ * external or it will be bind from such an explicit external
+ * mount, we set bind in propagate_mount and propagate_siblings
+ */
+
+static bool mnt_is_external(struct mount_info *m)
+{
+	struct mount_info *t;
+
+	while (m) {
+		if (m->external)
+			return 1;
+
+		if (!list_empty(&m->mnt_share))
+			list_for_each_entry(t, &m->mnt_share, mnt_share)
+				if (t->external)
+					return 1;
+
+		if (m->master_id <= 0 && !list_empty(&m->mnt_bind))
+			list_for_each_entry(t, &m->mnt_bind, mnt_bind)
+				if (issubpath(m->root, t->root) && t->external)
+					return 1;
+
+		m = m->mnt_master;
+	}
+
+	return 0;
+}
+
 static int validate_mounts(struct mount_info *info, bool for_dump)
 {
 	struct mount_info *m, *t;
@@ -656,7 +687,7 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
 		if (m->shared_id && validate_shared(m))
 			return -1;
 
-		if (m->external)
+		if (mnt_is_external(m))
 			goto skip_fstype;
 
 		/*
@@ -912,9 +943,9 @@ static int resolve_shared_mounts(struct mount_info *info, int root_master_id)
 
 		/*
 		 * If we haven't already determined this mount is external,
-		 * then we don't know where it came from.
+		 * or bind of external, then we don't know where it came from.
 		 */
-		if (need_master && m->parent && !m->external) {
+		if (need_master && m->parent && !mnt_is_external(m)) {
 			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);
@@ -1247,7 +1278,7 @@ static int dump_one_fs(struct mount_info *mi)
 	struct mount_info *t;
 	bool first = true;
 
-	if (mi->is_ns_root || mi->need_plugin || mi->external || !mi->fstype->dump)
+	if (mi->is_ns_root || mi->need_plugin || mnt_is_external(mi) || !mi->fstype->dump)
 		return 0;
 
 	/* mnt_bind is a cycled list, so list_for_each can't be used here. */
@@ -1663,7 +1694,7 @@ static int propagate_mount(struct mount_info *mi)
 	 * FIXME Currently non-root mounts can be restored
 	 * only if a proper root mount exists
 	 */
-	if (fsroot_mounted(mi) || mi->parent == root_yard_mp) {
+	if (fsroot_mounted(mi) || mi->parent == root_yard_mp || mi->external) {
 		list_for_each_entry(t, &mi->mnt_bind, mnt_bind) {
 			if (t->mounted)
 				continue;
@@ -1671,6 +1702,9 @@ static int propagate_mount(struct mount_info *mi)
 				continue;
 			if (t->master_id > 0)
 				continue;
+			if (!issubpath(t->root, mi->root))
+				continue;
+			pr_debug("\t\tBind private %s\n", t->mountpoint);
 			t->bind = mi;
 			t->s_dev_rt = mi->s_dev_rt;
 		}
@@ -2446,7 +2480,16 @@ static int get_mp_root(MntEntry *me, struct mount_info *mi)
 {
 	char *ext = NULL;
 
-	mi->root = xstrdup(me->ext_real_root ? : me->root);
+	/*
+	 * Puting the id of external mount which is provided by user,
+	 * to ->root can confuse mnt_is_external and other functions
+	 * which expect to see the path in the file system to the root
+	 * of these mount (mounts_equal, mnt_build_ids_tree,
+	 * find_wider_shared, find_fsroot_mount_for,
+	 * find_best_external_match, etc.), so put NO_ROOT_MOUNT there
+	 * for forward compatibility.
+	 */
+	mi->root = xstrdup(me->ext_real_root ? : (me->ext_mount ? NO_ROOT_MOUNT : me->root));
 	if (!mi->root)
 		return -1;
 
-- 
2.9.3



More information about the CRIU mailing list