[CRIU] [PATCH 3/3] ghost: Remove ghost files if restore fails

Pavel Emelyanov xemul at parallels.com
Wed Sep 23 07:21:16 PDT 2015


Issue #18. When restore fails ghost files remain there. And
to remove them we have to know their list, paths to original
files (to construct the ghost name) and the namespace ghost
lives in.

For the latter we keep the restore task namespace at hands
till the final stage and setns into it to kill ghosts.

Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
---
 cr-restore.c        | 17 +++++++++++-
 files-reg.c         | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/files-reg.h |  1 +
 3 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index 82611d4..c282132 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1732,7 +1732,7 @@ static void ignore_kids(void)
 static int restore_root_task(struct pstree_item *init)
 {
 	enum trace_flags flag = TRACE_ALL;
-	int ret, fd;
+	int ret, fd, mnt_ns_fd = -1;
 
 	fd = open("/proc", O_DIRECTORY | O_RDONLY);
 	if (fd < 0) {
@@ -1808,6 +1808,14 @@ static int restore_root_task(struct pstree_item *init)
 	if (ret)
 		goto out;
 
+	if (root_ns_mask & CLONE_NEWNS) {
+		mnt_ns_fd = open_proc(init->pid.real, "ns/mnt");
+		if (mnt_ns_fd < 0) {
+			pr_perror("Can't open init's mntns fd");
+			goto out;
+		}
+	}
+
 	ret = run_scripts(ACT_SETUP_NS);
 	if (ret)
 		goto out;
@@ -1837,6 +1845,12 @@ static int restore_root_task(struct pstree_item *init)
 	 */
 	task_entries->nr_threads -= atomic_read(&task_entries->nr_zombies);
 
+	if (mnt_ns_fd >= 0)
+		/*
+		 * Don't try_clean_remaps here, since restore went OK
+		 * and all ghosts were removed by the openers.
+		 */
+		close(mnt_ns_fd);
 	cleanup_mnt_ns();
 
 	ret = stop_usernsd();
@@ -1923,6 +1937,7 @@ out_kill:
 
 out:
 	fini_cgroup();
+	try_clean_remaps(mnt_ns_fd);
 	cleanup_mnt_ns();
 	stop_usernsd();
 	__restore_switch_stage(CR_STATE_FAIL);
diff --git a/files-reg.c b/files-reg.c
index 7c85e01..6851d50 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -157,6 +157,12 @@ err:
 	return ret;
 }
 
+static inline void ghost_path(char *path, int plen,
+		struct reg_file_info *rfi, RemapFilePathEntry *rfe)
+{
+	snprintf(path, plen, "%s.cr.%x.ghost", rfi->path, rfe->remap_id);
+}
+
 static int open_remap_ghost(struct reg_file_info *rfi,
 		RemapFilePathEntry *rfe)
 {
@@ -203,7 +209,7 @@ static int open_remap_ghost(struct reg_file_info *rfi,
 	if (S_ISDIR(gfe->mode))
 		strncpy(gf->remap.rpath, rfi->path, PATH_MAX);
 	else
-		snprintf(gf->remap.rpath, PATH_MAX, "%s.cr.%x.ghost", rfi->path, rfe->remap_id);
+		ghost_path(gf->remap.rpath, PATH_MAX, rfi, rfe);
 
 	if (create_ghost(gf, gfe, img))
 		goto close_ifd;
@@ -379,6 +385,78 @@ int prepare_remaps(void)
 	return ret;
 }
 
+static void try_clean_ghost(struct remap_info *ri)
+{
+	char path[PATH_MAX];
+	int mnt_id, ret;
+
+	mnt_id = ri->rfi->rfe->mnt_id; /* rirfirfe %) */
+	ret = rst_get_mnt_root(mnt_id, path, sizeof(path));
+	if (ret < 0)
+		return;
+
+	ghost_path(path + ret, sizeof(path) - 1, ri->rfi, ri->rfe);
+	if (!unlink(path)) {
+		pr_info(" `- X [%s] ghost\n", path);
+		return;
+	}
+
+	/*
+	 * We can also find out the ghost type by stat()-ing
+	 * it or by reading the ghost image, but this way
+	 * is the fastest one.
+	 */
+
+	if ((errno == EISDIR)) {
+		strncpy(path + ret, ri->rfi->path, sizeof(path) - 1);
+		if (!rmdir(path)) {
+			pr_info(" `- Xd [%s] ghost\n", path);
+			return;
+		}
+	}
+
+	pr_perror(" `- XFail [%s] ghost", path);
+}
+
+void try_clean_remaps(int ns_fd)
+{
+	struct remap_info *ri;
+	int old_ns = -1;
+
+	if (list_empty(&remaps))
+		goto out;
+
+	if (ns_fd >= 0) {
+		pr_info("Switching to new ns to clean ghosts\n");
+
+		old_ns = open_proc(PROC_SELF, "ns/mnt");
+		if (old_ns < 0) {
+			pr_perror("`- Can't keep old ns");
+			return;
+		}
+
+		if (setns(ns_fd, CLONE_NEWNS) < 0) {
+			close(old_ns);
+			pr_perror("`- Can't switch");
+			return;
+		}
+	}
+
+	list_for_each_entry(ri, &remaps, list)
+		if (ri->rfe->remap_type == REMAP_TYPE__GHOST)
+			try_clean_ghost(ri);
+
+	if (old_ns >= 0) {
+		if (setns(old_ns, CLONE_NEWNS) < 0)
+			pr_perror("Fail to switch back!");
+		close(old_ns);
+	}
+
+out:
+	if (ns_fd >= 0)
+		close(ns_fd);
+}
+
 static struct collect_image_info remap_cinfo = {
 	.fd_type = CR_FD_REMAP_FPATH,
 	.pb_type = PB_REMAP_FPATH,
diff --git a/include/files-reg.h b/include/files-reg.h
index 1bafdf4..72f7390 100644
--- a/include/files-reg.h
+++ b/include/files-reg.h
@@ -50,6 +50,7 @@ extern int collect_remaps_and_regfiles(void);
 extern void delete_link_remaps(void);
 extern void free_link_remaps(void);
 extern int prepare_remaps(void);
+extern void try_clean_remaps(int ns_fd);
 
 extern int strip_deleted(struct fd_link *link);
 
-- 
1.9.3




More information about the CRIU mailing list