[CRIU] [PATCH v2 3/4] mount: Forced mount unmounted binfmt_misc to do not lost its content

Kirill Tkhai ktkhai at virtuozzo.com
Fri Jun 24 03:46:19 PDT 2016


Umount does not remove binfmt_misc content. If it's mounted once again,
the same entries remain registered.

Criu does not dump content of umounted binfmt_misc. So, after C/R we
lose it at all.

This patch forces mounting of unmounted binfmt_misc before we collect
mountpoints. If it's unmounted, we mount it back and add this mount
to the list of forced mounted mountpoints. Next patch need this
list to mark the mount in special way in dump image.

v2: Print error in case of umount() fail.
    Move add_forced_mount() to another patch.

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 criu/cr-dump.c       |   13 ++++++++++++
 criu/include/mount.h |    1 +
 criu/mount.c         |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+)

diff --git a/criu/cr-dump.c b/criu/cr-dump.c
index 7609544..90da57b 100644
--- a/criu/cr-dump.c
+++ b/criu/cr-dump.c
@@ -747,6 +747,16 @@ static int dump_task_core_all(struct parasite_ctl *ctl,
 	return ret;
 }
 
+static int prepare_dump__tasks_freezed(void)
+{
+	int ret;
+
+	/* Tasks freezed, so we do not race with systemd's autofs unmounter */
+	ret = try_mount_binfmt_misc(root_item->pid.real);
+
+	return ret;
+}
+
 static int collect_pstree_ids_predump(void)
 {
 	struct pstree_item *item;
@@ -1682,6 +1692,9 @@ int cr_dump_tasks(pid_t pid)
 	if (collect_pstree())
 		goto err;
 
+	if (prepare_dump__tasks_freezed())
+		goto err;
+
 	if (collect_pstree_ids())
 		goto err;
 
diff --git a/criu/include/mount.h b/criu/include/mount.h
index 423b6d0..bd15468 100644
--- a/criu/include/mount.h
+++ b/criu/include/mount.h
@@ -129,4 +129,5 @@ extern int read_mnt_ns_img(void);
 extern void cleanup_mnt_ns(void);
 extern void cleanup_forced_mounts(void);
 
+extern int try_mount_binfmt_misc(pid_t pid);
 #endif /* __CR_MOUNT_H__ */
diff --git a/criu/mount.c b/criu/mount.c
index 1375ee8..7b13397 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -3761,4 +3761,60 @@ void cleanup_forced_mounts(void)
 	}
 }
 
+#define BINFMT_MISC_HOME "/proc/sys/fs/binfmt_misc"
+
+int try_mount_binfmt_misc(pid_t pid)
+{
+	int num, mnt_fd, ret, exit_code = -1;
+	struct dirent *de;
+	DIR *dir;
+
+	ret = switch_ns(pid, &mnt_ns_desc, &mnt_fd);
+	if (ret < 0) {
+		pr_err("Can't switch mnt_ns\n");
+		goto out;
+	}
+
+	ret = mount("binfmt_misc", BINFMT_MISC_HOME, "binfmt_misc", 0, NULL);
+	if (ret < 0) {
+		if (errno == EPERM) {
+			pr_info("Can't mount binfmt_misc: EPERM. Running in user_ns?\n");
+			exit_code = 0;
+			goto restore_ns;
+		}
+		if (errno != EBUSY && errno != ENODEV && errno != ENOENT) {
+			pr_perror("Can't mount binfmt_misc");
+			goto restore_ns;
+		}
+		pr_info("Prepare binfmt_misc: skipping(%d)\n", errno);
+	} else {
+		dir = opendir(BINFMT_MISC_HOME);
+		if (!dir) {
+			pr_perror("Can't read binfmt_misc dir");
+			goto restore_ns;
+		}
+
+		num = 0;
+		/* ".", "..", "register", "status" */
+		while (num <= 4 && (de = readdir(dir)) != NULL)
+			num++;
+		if (num <= 4) {
+			/* No entries */
+			if (umount(BINFMT_MISC_HOME) < 0)
+				pr_perror("Can't umount "BINFMT_MISC_HOME"\n");
+		} else {
+			ret = add_forced_mount(pid, BINFMT_MISC_HOME);
+			if (ret)
+				goto restore_ns;
+		}
+		closedir(dir);
+	}
+
+	exit_code = 0;
+restore_ns:
+	ret = restore_ns(mnt_fd, &mnt_ns_desc);
+out:
+	return ret ? -1 : exit_code;
+}
+
 struct ns_desc mnt_ns_desc = NS_DESC_ENTRY(CLONE_NEWNS, "mnt");



More information about the CRIU mailing list