[CRIU] [PATCH 3/4] mount: create a clean mount only when it's required

Andrey Vagin avagin at openvz.org
Thu May 12 15:34:56 PDT 2016


From: Andrei Vagin <avagin at virtuozzo.com>

"clean mount" is a copy of target mount without child mounts.

Currently a clean mount is created when a target mount has children.
In this case a target path MAY be overmounted.

In this patch, a clean mount is created only if a target path is
overmounted. For that we enumerate all children and check that they
are not mounted over a target path.

Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
 criu/mount.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/criu/mount.c b/criu/mount.c
index f38ba1c..ec81351 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -2464,13 +2464,14 @@ static int do_bind_mount(struct mount_info *mi)
 	char mnt_fd_path[PSFDS];
 	char *root, *cut_root, rpath[PATH_MAX];
 	unsigned long mflags;
-	int exit_code = -1;
+	int exit_code = -1, mp_len;
 	bool shared = false;
 	bool master = false;
 	bool private = false;
 	char *mnt_path = NULL;
 	struct stat st;
 	bool umount_mnt_path = false;
+	struct mount_info *c;
 
 	if (mi->need_plugin) {
 		if (restore_ext_mount(mi))
@@ -2503,14 +2504,30 @@ static int do_bind_mount(struct mount_info *mi)
 	mi->private = mi->bind->private;
 
 	mnt_path = mi->bind->mountpoint;
+
+	/* Access a mount by fd if mi->bind->mountpoint is overmounted */
 	if (mi->bind->fd >= 0) {
 		snprintf(mnt_fd_path, sizeof(mnt_fd_path),
 					"/proc/self/fd/%d", mi->bind->fd);
 		mnt_path = mnt_fd_path;
 	}
 
-	if (!list_empty(&mi->bind->children)) {
-		/* mi->bind->mountpoint may be overmounted */
+	if (cut_root[0] == 0) /* This case is handled by mi->bind->fd */
+		goto skip_overmount_check;
+
+	mp_len = strlen(mi->bind->mountpoint);
+	if (mp_len > 1) /* skip a joining / if mi->bind->mountpoint isn't "/" */
+		mp_len++;
+
+	list_for_each_entry(c, &mi->bind->children, siblings) {
+		if (!c->mounted)
+			continue;
+		if (issubpath(cut_root, c->mountpoint + mp_len))
+			break; /* a source path is overmounted */
+	}
+
+	if (&c->siblings != &mi->bind->children) {
+		/* Get a copy of mi->bind without child mounts */
 		if (mount(mnt_path, mnt_clean_path, NULL, MS_BIND, NULL)) {
 			pr_perror("Unable to bind-mount %s to %s",
 					mi->bind->mountpoint, mnt_clean_path);
@@ -2518,9 +2535,11 @@ static int do_bind_mount(struct mount_info *mi)
 		mnt_path = mnt_clean_path;
 		umount_mnt_path = true;
 	}
+
 	if (mnt_path == NULL)
 		return -1;
 
+skip_overmount_check:
 	snprintf(rpath, sizeof(rpath), "%s/%s",
 			mnt_path, cut_root);
 	root = rpath;
-- 
2.7.4



More information about the CRIU mailing list