[CRIU] [PATCH 2/2] mnt: cut shared root path from bind path

Tycho Andersen tycho.andersen at canonical.com
Tue Apr 14 16:23:26 PDT 2015


If a mount like:

96 95 0:21 /cgmanager /sys/fs/cgroup/cgmanager rw master:9 - tmpfs tmpfs rw,mode=755

is present in the container and the host has a similar bind mount, e.g.

46 27 0:21 /cgmanager /sys/fs/cgroup/cgmanager rw shared:9 - tmpfs tmpfs rw,mode=755

then the best match mount's root path /and/ the target mountpoint have part of
the path in them; we should cut the shared piece of the path and just
concatenate the non-duplicate pieces.

Reported-by: Andrew Vagin <avagin at odin.com>
CC: Andrew Vagin <avagin at odin.com>
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 mount.c | 47 +++++++++++++++++++++++++++++------------------
 1 file changed, 29 insertions(+), 18 deletions(-)

diff --git a/mount.c b/mount.c
index 381c483..1bb2ebc 100644
--- a/mount.c
+++ b/mount.c
@@ -647,6 +647,25 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
 	return 0;
 }
 
+static char *cut_root_for_bind(char *target_root, char *source_root)
+{
+	int tok = 0;
+	/*
+	 * Cut common part of root.
+	 * For non-root binds the source is always "/" (checked)
+	 * so this will result in this slash removal only.
+	 */
+	while (target_root[tok] == source_root[tok]) {
+		tok++;
+		if (source_root[tok] == '\0')
+			break;
+		BUG_ON(target_root[tok] == '\0');
+	}
+
+	return target_root + tok;
+
+}
+
 static struct mount_info *find_best_external_match(struct mount_info *list, struct mount_info *info)
 {
 	struct mount_info *it, *candidate = NULL;
@@ -722,7 +741,7 @@ static int resolve_external_mounts(struct mount_info *info)
 
 	for (m = info; m; m = m->next) {
 		int ret, size;
-		char *p;
+		char *p, *cut_root;
 		struct ext_mount *em;
 		struct mount_info *match;
 
@@ -764,12 +783,16 @@ static int resolve_external_mounts(struct mount_info *info)
 				continue;
 		}
 
-		size = strlen(match->mountpoint + 1) + strlen(m->root) + 1;
+		cut_root = cut_root_for_bind(m->root, match->root);
+
+		/* +2 for the NULL byte and the extra / in the sprintf below,
+		 * which we cut off in cut_root_for_bind(). */
+		size = strlen(match->mountpoint + 1) + strlen(cut_root) + 2;
 		p = xmalloc(sizeof(char) * size);
 		if (!p)
 			return -1;
 
-		ret = snprintf(p, size, "%s%s", match->mountpoint + 1, m->root);
+		ret = snprintf(p, size, "%s/%s", match->mountpoint + 1, cut_root);
 		if (ret < 0 || ret >= size) {
 			free(p);
 			return -1;
@@ -1817,8 +1840,7 @@ static int do_bind_mount(struct mount_info *mi)
 	bool force_private_remount = false;
 
 	if (!mi->need_plugin) {
-		char *root, rpath[PATH_MAX];
-		int tok = 0;
+		char *root, *cut_root, rpath[PATH_MAX];
 
 		if (mi->external) {
 			/*
@@ -1833,21 +1855,10 @@ static int do_bind_mount(struct mount_info *mi)
 		}
 
 		shared = mi->shared_id && mi->shared_id == mi->bind->shared_id;
-
-		/*
-		 * Cut common part of root.
-		 * For non-root binds the source is always "/" (checked)
-		 * so this will result in this slash removal only.
-		 */
-		while (mi->root[tok] == mi->bind->root[tok]) {
-			tok++;
-			if (mi->bind->root[tok] == '\0')
-				break;
-			BUG_ON(mi->root[tok] == '\0');
-		}
+		cut_root = cut_root_for_bind(mi->root, mi->bind->root);
 
 		snprintf(rpath, sizeof(rpath), "%s/%s",
-				mi->bind->mountpoint, mi->root + tok);
+				mi->bind->mountpoint, cut_root);
 		root = rpath;
 do_bind:
 		pr_info("\tBind %s to %s\n", root, mi->mountpoint);
-- 
2.1.4



More information about the CRIU mailing list