[CRIU] [PATCH v2 2/4] files-reg: Create ghost files in first existing parent directory

Kirill Tkhai ktkhai at odin.com
Tue Dec 22 03:43:37 PST 2015


Since a deleted file may belong to a deleted directory
(which, in turn, may belong to another deleted, etc),
it's necessary to recreate all missing dentries in the path.

Doing this in mkreg_ghost() is not a good idea, because
another ghost file may need some of the dentries in the path,
and this requires to do refcouting of recreated directories.

To avoid this, we restore a ghost file in the first existing
parent directory of the patch. This guarantees, the ghost file
will be in the same mount with target file (rfi_remap() uses
link() and it needs this).

v2: Create ghost file in parent directory instead of in "/".

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 files-reg.c |   68 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 57 insertions(+), 11 deletions(-)

diff --git a/files-reg.c b/files-reg.c
index c1b2e28..fb7b0a2 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -95,13 +95,60 @@ static int note_link_remap(char *path, struct ns_id *nsid)
 	return -1;
 }
 
+/* Trim "a/b/c/d" to "a/b/d" */
+static int trim_last_parent(char *path)
+{
+	char *fname, *p;
+
+	p = strrchr(path, '/');
+	fname = p + 1;
+	if (!p || *fname == '\0')
+		return -1;
+
+	while (p >= path && *p == '/')
+		p--;
+
+	if (p < path)
+		return -1;
+
+	while (p >= path && *p != '/')
+		p--;
+	p++;
+
+	while (*fname != '\0')
+		*p++ = *fname++;
+	*p = '\0';
+
+	return 0;
+}
+
 static int mkreg_ghost(char *path, u32 mode, struct ghost_file *gf, struct cr_img *img)
 {
-	int gfd, ret;
+	int gfd, ret, len, i = 0;
 
+	len = strlen(path);
+again:
 	gfd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
-	if (gfd < 0)
-		return -1;
+
+	if (gfd < 0 && errno == ENOENT) {
+		if (trim_last_parent(path) < 0) {
+			pr_err("trim failed: @%s@\n", path);
+			return -1;
+		}
+		len = strlen(path);
+		goto again;
+	}
+
+	if (gfd < 0) {
+		if (errno != EEXIST)
+			return -1;
+		if (++i == INT_MAX)
+			return -1;
+		sprintf(path + len, ".%x", i);
+		goto again;
+	}
+
+	strcpy(gf->remap.rpath, path);
 
 	ret = copy_file(img_raw_fd(img), gfd, 0);
 	close(gfd);
@@ -420,17 +467,18 @@ int prepare_remaps(void)
 	return ret;
 }
 
-static void try_clean_ghost(struct remap_info *ri)
+static void try_clean_ghost(struct ghost_file *gf)
 {
 	char path[PATH_MAX];
 	int mnt_id, ret;
 
-	mnt_id = ri->rfi->rfe->mnt_id; /* rirfirfe %) */
+	mnt_id = gf->remap.rmnt_id;
 	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);
+	sprintf(path + ret, "/%s", gf->remap.rpath);
+
 	if (!unlink(path)) {
 		pr_info(" `- X [%s] ghost\n", path);
 		return;
@@ -443,7 +491,6 @@ static void try_clean_ghost(struct remap_info *ri)
 	 */
 
 	if ((errno == EISDIR)) {
-		strncpy(path + ret, ri->rfi->path, sizeof(path) - 1);
 		if (!rmdir(path)) {
 			pr_info(" `- Xd [%s] ghost\n", path);
 			return;
@@ -455,7 +502,7 @@ static void try_clean_ghost(struct remap_info *ri)
 
 void try_clean_remaps(int ns_fd)
 {
-	struct remap_info *ri;
+	struct ghost_file *gf;
 	int old_ns = -1;
 	int cwd_fd = -1;
 
@@ -485,9 +532,8 @@ void try_clean_remaps(int ns_fd)
 		}
 	}
 
-	list_for_each_entry(ri, &remaps, list)
-		if (ri->rfe->remap_type == REMAP_TYPE__GHOST)
-			try_clean_ghost(ri);
+	list_for_each_entry(gf, &ghost_files, list)
+		try_clean_ghost(gf);
 
 	if (old_ns >= 0) {
 		if (setns(old_ns, CLONE_NEWNS) < 0)



More information about the CRIU mailing list