diff --git a/cr-restore.c b/cr-restore.c index 82611d47b..c2821325e 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 7c85e01b1..6851d508f 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 1bafdf43f..72f7390b1 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);