[CRIU] [PATCH v3 5/6] files-reg: Recreate deleted parent directories during restore of ghost file
Kirill Tkhai
ktkhai at virtuozzo.com
Tue Dec 29 06:05:48 PST 2015
This patch makes ghost files to restore with the right path.
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
files-reg.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 97 insertions(+), 1 deletion(-)
diff --git a/files-reg.c b/files-reg.c
index 1e83a00..cb704b9 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -1230,6 +1230,89 @@ static int linkat_hard(int odir, char *opath, int ndir, char *npath, uid_t owner
return ret;
}
+/* Prints parent and returns place where last delimiter was */
+static char *sprintf_parent_dir(char *dst, const char *path)
+{
+ char *p;
+
+ strcpy(dst, path);
+
+ p = strrchr(dst, '/');
+ if (!p) {
+ pr_err("Path %s has no parent dir", path);
+ return NULL;
+ }
+ *p = '\0';
+
+ return p;
+}
+
+static void rm_parent_dirs(int mntns_root, char *path, int count)
+{
+ char pdir[PATH_MAX], *p;
+
+ if (!count || !sprintf_parent_dir(pdir, path))
+ return;
+
+ while (count--) {
+ if (unlinkat(mntns_root, pdir, AT_REMOVEDIR))
+ pr_perror("Can't remove %s AT %d", pdir, mntns_root);
+ else
+ pr_debug("Unlinked parent dir: %s AT %d\n", pdir, mntns_root);
+
+ p = strrchr(pdir, '/');
+ if (p)
+ *p = '\0';
+ }
+}
+
+/* Construct parent dir name and mkdir parent/grandparents if they're not exist */
+static int make_parent_dirs_if_need(struct ghost_file *gf, int mntns_root, char *path)
+{
+ char pdir[PATH_MAX], *p;
+ int err, count = 1;
+
+ if (!gf->nr_up)
+ return 0;
+ p = sprintf_parent_dir(pdir, path);
+ if (!p)
+ return -1;
+
+ while (count++ < gf->nr_up) {
+ while (--p >= pdir && *p != '/')
+ continue;
+ if (p < pdir) {
+ pr_err("Can't set %d parent of %s", gf->nr_up, pdir);
+ return -1;
+ }
+ }
+
+ count = 0;
+ do {
+ p = strchr(p, '/');
+ if (p)
+ *p = '\0';
+
+ err = mkdirat(mntns_root, pdir, 0777);
+ if (err) {
+ pr_perror("Can't create dir: %s AT %d", pdir, mntns_root);
+ if (errno != EEXIST)
+ goto cleanup;
+ }
+ count++;
+
+ pr_debug("Created parent dir: %s AT %d\n", pdir, mntns_root);
+
+ if (p)
+ *p++ = '/';
+ } while (p);
+
+ return count;
+cleanup:
+ rm_parent_dirs(mntns_root, pdir, count);
+ return -1;
+}
+
/*
* This routine properly resolves d's path handling ghost/link-remaps.
* The open_cb is a routine that does actual open, it differs for
@@ -1241,6 +1324,7 @@ static int rfi_remap(struct reg_file_info *rfi)
struct mount_info *mi, *rmi, *tmi;
char _path[PATH_MAX], *path = _path;
char _rpath[PATH_MAX], *rpath = _rpath;
+ struct ghost_file *gf;
int mntns_root;
if (rfi->rfe->mnt_id == -1) {
@@ -1282,13 +1366,23 @@ static int rfi_remap(struct reg_file_info *rfi)
mntns_root = mntns_get_root_fd(tmi->nsid);
out_root:
- return linkat_hard(mntns_root, rpath, mntns_root, path, rfi->remap->owner);
+ gf = container_of(rfi->remap, struct ghost_file, remap);
+ if (make_parent_dirs_if_need(gf, mntns_root, path) < 0)
+ return -1;
+
+ if (linkat_hard(mntns_root, rpath, mntns_root, path, rfi->remap->owner) < 0) {
+ rm_parent_dirs(mntns_root, path, gf->nr_up);
+ return -1;
+ }
+
+ return 0;
}
int open_path(struct file_desc *d,
int(*open_cb)(int mntns_root, struct reg_file_info *, void *), void *arg)
{
struct reg_file_info *rfi;
+ struct ghost_file *gf;
int tmp, mntns_root;
char *orig_path = NULL;
@@ -1368,7 +1462,9 @@ int open_path(struct file_desc *d,
if (rfi->remap) {
if (!rfi->remap->is_dir) {
+ gf = container_of(rfi->remap, struct ghost_file, remap);
unlinkat(mntns_root, rfi->path, 0);
+ rm_parent_dirs(mntns_root, rfi->path, gf->nr_up);
}
BUG_ON(!rfi->remap->users);
More information about the CRIU
mailing list