[CRIU] [PATCH 6/9] mntns: rework validation to support non-root shared bind-mounts

Andrey Vagin avagin at openvz.org
Thu Oct 23 06:49:04 PDT 2014


Currently we can restore shared bind-mounts only if they have the same
set of children. But if we have a non-root bind-mount, we should compare
children, which are accessiable from both mounts.

Now we take the next mount in the shared group, which is wider or equal
to current and compare children between them.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 mount.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 80 insertions(+), 12 deletions(-)

diff --git a/mount.c b/mount.c
index bd51686..7ccdef3 100644
--- a/mount.c
+++ b/mount.c
@@ -372,28 +372,96 @@ static int try_resolve_ext_mount(struct mount_info *info)
 	info->external = em;
 	return 0;
 }
+
 static int validate_shared(struct mount_info *m)
 {
-	struct mount_info *ct, *t;
+	struct mount_info *t, *ct, *cm, *tmp;
+	int t_root_len, m_root_len, tpm, mpm;
+	LIST_HEAD(children);
+
+	/* Try to find a mount, which is wider or equal */
+	list_for_each_entry(t, &m->mnt_share, mnt_share) {
+		if (strncmp(t->root, m->root, strlen(t->root)) == 0)
+			break;
+	}
 
-	if (!list_empty(&m->parent->mnt_share))
+	/*
+	 * The current mount is widest one in its shared group,
+	 * all others should be compared with it.
+	 */
+	if (&t->mnt_share == &m->mnt_share)
 		return 0;
 
-	t = list_first_entry(&m->parent->mnt_share, struct mount_info, mnt_share);
+	/* A set of childrent which ar visiable for both should be the same */
 
+	t_root_len = strlen(t->root);
+	m_root_len = strlen(m->root);
+	tpm = strlen(t->mountpoint);
+	mpm = strlen(m->mountpoint);
+	if (t->mountpoint[tpm - 1] == '/')
+		tpm--;
+	if (m->mountpoint[mpm - 1] == '/')
+		mpm--;
+
+	/*
+	 * ct:	| t->root	|        /reletive mount point	|
+	 * cm:	|	m->root		| /reletive mount point	|
+	 * 			| A     | B			|
+	 *      \ct->mountpoint + tpm
+	 *		     \m->root + strlen(t->root)
+	 */
 	list_for_each_entry(ct, &t->children, siblings) {
-		if (mounts_equal(m, ct, false))
+		char *tp, *mp;
+		int len;
+
+		if (ct->is_ns_root)
+			continue;
+
+		tp = ct->mountpoint + tpm;
+		mp = m->root + t_root_len;
+		len = m_root_len - t_root_len;
+
+		/* A */
+		if (strncmp(tp, mp, len))
+			continue;
+		if (tp[len] != '/')
+			continue;
+
+		list_for_each_entry_safe(cm, tmp, &m->children, siblings) {
+			/* B */
+			if (strcmp(ct->mountpoint + tpm + len, cm->mountpoint + mpm))
+				continue;
+
+			if (!mounts_equal(cm, ct, false)) {
+				pr_err("Two shared mounts on same spaces have different mounts\n");
+				pr_err("%d:%s\n", cm->mnt_id, cm->mountpoint);
+				pr_err("%d:%s\n", ct->mnt_id, ct->mountpoint);
+				return -1;
+			}
+
+			list_move(&cm->siblings, &children);
 			break;
+		}
+		if (&cm->siblings == &m->children) {
+			list_splice(&children, &m->children);
+
+			pr_err("%d:%s and %d:%s have different set of mounts\n",
+				m->mnt_id, m->mountpoint, t->mnt_id, t->mountpoint);
+			pr_err("For example %d:%s\n", ct->mnt_id, ct->mountpoint);
+			return -1;
+		}
 	}
-	if (&ct->siblings == &t->children) {
-		pr_err("Two shared mounts %d, %d have different sets of children\n",
-			m->parent->mnt_id, t->mnt_id);
-		pr_err("%d:%s doesn't have a proper point for %d:%s\n",
-			t->mnt_id, t->mountpoint,
-			m->mnt_id, m->mountpoint);
+
+	if (!list_empty(&m->children)) {
+		list_splice(&children, &m->children);
+
+		cm = list_first_entry(&m->children, struct mount_info, siblings);
+		pr_err("%d:%s and %d:%s have different set of mounts\n",
+			m->mnt_id, m->mountpoint, t->mnt_id, t->mountpoint);
+		pr_err("For example %d:%s\n", cm->mnt_id, cm->mountpoint);
 		return -1;
 	}
-
+	list_splice(&children, &m->children);
 	return 0;
 }
 
@@ -406,7 +474,7 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
 			/* root mount can be any */
 			continue;
 
-		if (m->parent->shared_id && validate_shared(m))
+		if (m->shared_id && validate_shared(m))
 			return -1;
 
 		/*
-- 
1.9.3



More information about the CRIU mailing list