[CRIU] [PATCH v5 1/3] files-reg: Create ghost files in first existing parent directory
Kirill Tkhai
ktkhai at virtuozzo.com
Thu Jan 28 03:39:31 PST 2016
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() needs
that, because it uses link()).
---
files-reg.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 66 insertions(+), 17 deletions(-)
diff --git a/files-reg.c b/files-reg.c
index a394e65..1567174 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -95,6 +95,33 @@ 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;
@@ -142,45 +169,67 @@ static int ghost_apply_metadata(const char *path, GhostFileEntry *gfe)
static int create_ghost(struct ghost_file *gf, GhostFileEntry *gfe, struct cr_img *img)
{
+ int ret, len, root_len, try = 0;
char path[PATH_MAX];
- int ret;
+ char *msg;
- ret = rst_get_mnt_root(gf->remap.rmnt_id, path, sizeof(path));
+ root_len = ret = rst_get_mnt_root(gf->remap.rmnt_id, path, sizeof(path));
if (ret < 0) {
pr_err("The %d mount is not found for ghost\n", gf->remap.rmnt_id);
goto err;
}
- snprintf(path + ret, sizeof(path) - ret, "/%s", gf->remap.rpath);
+ len = snprintf(path + ret, sizeof(path) - ret, "/%s", gf->remap.rpath) + ret;
ret = -1;
-
+again:
if (S_ISFIFO(gfe->mode)) {
- if (mknod(path, gfe->mode, 0)) {
- pr_perror("Can't create node for ghost file");
- goto err;
- }
+ if ((ret = mknod(path, gfe->mode, 0)) < 0)
+ msg = "Can't create node for ghost file";
} else if (S_ISCHR(gfe->mode) || S_ISBLK(gfe->mode)) {
if (!gfe->has_rdev) {
pr_err("No rdev for ghost device\n");
goto err;
}
-
- if (mknod(path, gfe->mode, gfe->rdev)) {
- pr_perror("Can't create node for ghost dev");
- goto err;
- }
+ if ((ret = mknod(path, gfe->mode, gfe->rdev)) < 0)
+ msg = "Can't create node for ghost dev";
} else if (S_ISDIR(gfe->mode)) {
- if (mkdir(path, gfe->mode)) {
+ if ((ret = mkdir(path, gfe->mode)) < 0) {
pr_perror("Can't make ghost dir");
goto err;
}
} else {
- if (mkreg_ghost(path, gfe->mode, gf, img)) {
- pr_perror("Can't create ghost regfile\n");
+ if ((ret = mkreg_ghost(path, gfe->mode, gf, img)) < 0)
+ msg = "Can't create ghost regfile\n";
+ }
+
+ if (ret < 0) {
+ /* Use grand parent, if parent directory does not exist */
+ if (errno == ENOENT) {
+ if (trim_last_parent(path) < 0) {
+ pr_err("trim failed: @%s@\n", path);
+ goto err;
+ }
+ len = strlen(path);
+ goto again;
+ }
+
+ /* Use numeric suffix, if a namesake already exists */
+ if (errno != EEXIST) {
+ pr_perror("%s", msg);
goto err;
- }
+ }
+
+ if (++try == INT_MAX) {
+ pr_err("Can't find available file name\n");
+ goto err;
+ }
+ sprintf(path + len, ".%x", try);
+ goto again;
}
+ strcpy(gf->remap.rpath, path + root_len + 1);
+ pr_debug("Remap rpath is %s\n", gf->remap.rpath);
+
ret = -1;
if (ghost_apply_metadata(path, gfe))
goto err;
More information about the CRIU
mailing list