[CRIU] [PATCH 1/2] [v5] mount: dump a file system only if a mount point isn't overmounted

Andrey Vagin avagin at openvz.org
Thu May 12 14:53:43 PDT 2016


From: Andrew Vagin <avagin at virtuozzo.com>

Here we try to enumerate all mount points and try to find one,
which allows us to dump content of a file system.

It's should be a root mount and its mount point should not be
overmounted.

We don't have a separate call-back to dump content of a file system.
fstype->dump() isn't always requires access to a mount point (e.g.
autofs), so we check overmounts in open_mountpoint().

$ cat /proc/61693/root/etc/redhat-release
Fedora release 23 (Twenty Three)

$ cat /proc/61692/mountinfo  | grep '\s/tmp'
234 199 0:57 / /tmp rw shared:97 master:76 - tmpfs tmpfs rw,size=131072k,nr_inodes=32768
235 234 0:57 /systemd-private-dd74de99e1104383aa7cd6e27d3d0b8a-httpd.service-uFqNHk/tmp /tmp rw,relatime shared:98 master:76 - tmpfs tmpfs rw,size=131072k,nr_inodes=32768

v2: return an error if we can't dump a file system
v3: try to find a mount point which allows to dump a file system
v4: check that children are not overmounted a target mount instead
of getting a mnt_id for a file descriptor.
v5: add a special error code for unreachable mount points

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

diff --git a/criu/mount.c b/criu/mount.c
index e08f46e..8e545b1 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -1153,8 +1153,10 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_
 	return mnt_path;
 }
 
+#define MNT_UNREACHABLE INT_MIN
 static int open_mountpoint(struct mount_info *pm)
 {
+	struct mount_info *c;
 	int fd = -1, ns_old = -1;
 	char mnt_path_tmp[] = "/tmp/cr-tmpfs.XXXXXX";
 	char mnt_path_root[] = "/cr-tmpfs.XXXXXX";
@@ -1170,6 +1172,13 @@ static int open_mountpoint(struct mount_info *pm)
 
 	pr_info("Something is mounted on top of %s\n", pm->mountpoint);
 
+	list_for_each_entry(c, &pm->children, siblings) {
+		if (!strcmp(c->mountpoint, pm->mountpoint)) {
+			pr_debug("%d:%s is overmounted\n", pm->mnt_id, pm->mountpoint);
+			return MNT_UNREACHABLE;
+		}
+	}
+
 	/*
 	 * To create a "private" copy, the target mount is bind-mounted
 	 * in a temporary place w/o MS_REC (non-recursively).
@@ -1252,7 +1261,7 @@ static int tmpfs_dump(struct mount_info *pm)
 
 	fd = open_mountpoint(pm);
 	if (fd < 0)
-		return -1;
+		return fd;
 
 	/* if fd happens to be 0 here, we need to move it to something
 	 * non-zero, because cr_system_userns closes STDIN_FILENO as we are not
@@ -1463,7 +1472,7 @@ static int binfmt_misc_dump(struct mount_info *pm)
 
 	fd = open_mountpoint(pm);
 	if (fd < 0)
-		return -1;
+		return fd;
 
 	fdir = fdopendir(fd);
 	if (fdir == NULL) {
@@ -1634,7 +1643,7 @@ static int fusectl_dump(struct mount_info *pm)
 
 	fd = open_mountpoint(pm);
 	if (fd < 0)
-		return -1;
+		return fd;
 
 	fdir = fdopendir(fd);
 	if (fdir == NULL) {
@@ -1688,10 +1697,10 @@ static int cgroup_parse(struct mount_info *pm)
 static int dump_empty_fs(struct mount_info *pm)
 {
 	int fd, ret = -1;
-	fd = open_mountpoint(pm);
 
+	fd = open_mountpoint(pm);
 	if (fd < 0)
-		return -1;
+		return fd;
 
 	ret = is_empty_dir(fd);
 	close(fd);
@@ -1893,6 +1902,41 @@ uns:
 	return &fstypes[0];
 }
 
+static int dump_one_fs(struct mount_info *mi)
+{
+	struct mount_info *pm = mi;
+	struct mount_info *t;
+	bool first = true;
+
+	if (mi->is_ns_root || mi->need_plugin || mi->external || !mi->fstype->dump)
+		return 0;
+
+	/* mnt_bind is a cycled list, so list_for_each can't be used here. */
+	for (; &pm->mnt_bind != &mi->mnt_bind || first;
+	     pm = list_entry(pm->mnt_bind.next, typeof(*pm), mnt_bind)) {
+		int ret;
+
+		first = false;
+
+		if (!fsroot_mounted(pm))
+			continue;
+
+		ret = pm->fstype->dump(pm);
+		if (ret == MNT_UNREACHABLE)
+			continue;
+		if (ret < 0)
+			return ret;
+
+		list_for_each_entry(t, &pm->mnt_bind, mnt_bind)
+			t->dumped = true;
+		return 0;
+	}
+
+	pr_err("Unable to dump a file system for %d:%s\n",
+				mi->mnt_id, mi->mountpoint);
+	return -1;
+}
+
 static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img)
 {
 	MntEntry me = MNT_ENTRY__INIT;
@@ -1905,16 +1949,9 @@ static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img)
 	if (me.fstype == FSTYPE__AUTO)
 		me.fsname = pm->fsname;
 
-	if (pm->parent && !pm->dumped && !pm->need_plugin && !pm->external &&
-	    pm->fstype->dump && fsroot_mounted(pm)) {
-		struct mount_info *t;
-
-		if (pm->fstype->dump(pm))
-			return -1;
 
-		list_for_each_entry(t, &pm->mnt_bind, mnt_bind)
-			t->dumped = true;
-	}
+	if (!pm->dumped && dump_one_fs(pm))
+		return -1;
 
 	me.mnt_id		= pm->mnt_id;
 	me.root_dev		= pm->s_dev;
-- 
2.7.4



More information about the CRIU mailing list