[CRIU] [PATCH v3 4/6] files-reg: Create ghost files in existing parent directory

Kirill Tkhai ktkhai at virtuozzo.com
Tue Dec 29 06:05:38 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 directory,
which is GhostFileEntry::nr_up order parent for the file.

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 "/".
v3: Use GhostFileEntry::nr_up instead of first existing parent.

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

diff --git a/files-reg.c b/files-reg.c
index 2f41a84..1e83a00 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -96,14 +96,54 @@ static int note_link_remap(char *path, struct ns_id *nsid)
 	return -1;
 }
 
+static int trim_parents(char *path, int nr)
+{
+	char *last, *p;
+
+	if (nr == 0)
+		return 0;
+
+	p = last = strrchr(path, '/');
+	if (!last)
+		return -1;
+
+	while (nr > 0 && --p >= path) {
+		if (*p == '/')
+			nr--;
+	}
+
+	if (nr) {
+		pr_err("Can't trim %d parent dir in %s", nr, path);
+		return -1;
+	}
+
+	while (*++last != '\0')
+		*++p = *last;
+	*++p = '\0';
+
+	return 0;
+}
+
 static int mkreg_ghost(char *path, GhostFileEntry *gfe, struct ghost_file *gf, struct cr_img *img)
 {
-	int gfd, ret;
+	int gfd, ret, len, i = 0;
 
-	gfd = open(path, O_WRONLY | O_CREAT | O_EXCL, gfe->mode);
-	if (gfd < 0)
+	if (trim_parents(path, gfe->nr_up) < 0)
 		return -1;
 
+	len = strlen(path);
+again:
+	gfd = open(path, O_WRONLY | O_CREAT | O_EXCL, gfe->mode);
+
+	if (gfd < 0) {
+		if (errno != EEXIST || ++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);
 
@@ -149,7 +189,8 @@ static int create_ghost(struct ghost_file *gf, GhostFileEntry *gfe, struct cr_im
 		if (mkreg_ghost(path, gfe, gf, img)) {
 			pr_perror("Can't create ghost regfile\n");
 			goto err;
-               }
+		}
+		/* path may be changed */
 	}
 
 	if (chown(path, gfe->uid, gfe->gid) < 0) {



More information about the CRIU mailing list