ghost: Remove ghost files if restore fails

Issue #18. When restore fails ghost files remain there. And
to remove them we have to know their list, paths to original
files (to construct the ghost name) and the namespace ghost
lives in.

For the latter we keep the restore task namespace at hands
till the final stage and setns into it to kill ghosts.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
Pavel Emelyanov 2015-09-23 17:21:16 +03:00
parent a7c9f3011d
commit efa7dcf7c2
3 changed files with 96 additions and 2 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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);