Commit e7e9c2ee authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

mounts: create a temporary directory for restoring non-root mntns (v2)

All non-root namespaces will be restored as sub-trees of the root tree.

This patch adds helpers to create a temporary directory and mount tmpfs
in it, then create directories for each non-root mount namespace.

tmpfs is quite useful here to simplify destroying this construction,
we don't need to unmount each namespace separately.

v2: add a comment why MNT_DETACH is not dangerous here
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent fa14bd83
...@@ -1249,7 +1249,7 @@ static int restore_task_with_children(void *_arg) ...@@ -1249,7 +1249,7 @@ static int restore_task_with_children(void *_arg)
* Thus -- mount proc at custom location for any new namespace * Thus -- mount proc at custom location for any new namespace
*/ */
if (mount_proc()) if (mount_proc())
exit(1); goto err;
if (close_old_fds(current)) if (close_old_fds(current))
exit(1); exit(1);
...@@ -1258,7 +1258,7 @@ static int restore_task_with_children(void *_arg) ...@@ -1258,7 +1258,7 @@ static int restore_task_with_children(void *_arg)
exit(1); exit(1);
if (root_prepare_shared()) if (root_prepare_shared())
exit(1); goto err;
} }
/* /*
...@@ -1271,11 +1271,11 @@ static int restore_task_with_children(void *_arg) ...@@ -1271,11 +1271,11 @@ static int restore_task_with_children(void *_arg)
ret = sigprocmask(SIG_BLOCK, &blockmask, NULL); ret = sigprocmask(SIG_BLOCK, &blockmask, NULL);
if (ret) { if (ret) {
pr_perror("%d: Can't block signals", current->pid.virt); pr_perror("%d: Can't block signals", current->pid.virt);
exit(1); goto err;
} }
if (prepare_mappings(pid)) if (prepare_mappings(pid))
exit(1); goto err;
if (!(ca->clone_flags & CLONE_FILES)) { if (!(ca->clone_flags & CLONE_FILES)) {
ret = close_old_fds(current); ret = close_old_fds(current);
...@@ -1284,20 +1284,28 @@ static int restore_task_with_children(void *_arg) ...@@ -1284,20 +1284,28 @@ static int restore_task_with_children(void *_arg)
} }
if (create_children_and_session()) if (create_children_and_session())
exit(1); goto err;
if (unmap_guard_pages()) if (unmap_guard_pages())
exit(1); goto err;
restore_pgid(); restore_pgid();
if (restore_finish_stage(CR_STATE_FORKING) < 0) if (restore_finish_stage(CR_STATE_FORKING) < 0)
exit(1); goto err;
if (current->parent == NULL && fini_mnt_ns())
exit (1);
if (current->state == TASK_HELPER) if (current->state == TASK_HELPER)
return 0; return 0;
return restore_one_task(current->pid.virt, ca->core); return restore_one_task(current->pid.virt, ca->core);
err:
if (current->parent == NULL)
fini_mnt_ns();
exit(1);
} }
static inline int stage_participants(int next_stage) static inline int stage_participants(int next_stage)
......
...@@ -24,4 +24,6 @@ extern struct ns_desc mnt_ns_desc; ...@@ -24,4 +24,6 @@ extern struct ns_desc mnt_ns_desc;
extern dev_t phys_stat_resolve_dev(dev_t st_dev, const char *path); extern dev_t phys_stat_resolve_dev(dev_t st_dev, const char *path);
extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path); extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path);
extern int fini_mnt_ns(void);
#endif /* __CR_MOUNT_H__ */ #endif /* __CR_MOUNT_H__ */
...@@ -1384,6 +1384,37 @@ static void free_mounts(void) ...@@ -1384,6 +1384,37 @@ static void free_mounts(void)
} }
} }
/*
* mnt_roots is a temporary directory for restoring sub-trees of
* non-root namespaces.
*/
static char *mnt_roots;
static int create_mnt_roots()
{
if (mnt_roots)
return 0;
if (chdir(opts.root ? : "/")) {
pr_perror("Unable to change working directory on %s", opts.root);
return -1;
}
mnt_roots = strdup(".criu.mntns.XXXXXX");
if (mnt_roots == NULL) {
pr_perror("Can't allocate memory");
return -1;
}
if (mkdtemp(mnt_roots) == NULL) {
pr_perror("Unable to create a temporary directory");
mnt_roots = NULL;
return -1;
}
return 0;
}
static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
{ {
MntEntry *me = NULL; MntEntry *me = NULL;
...@@ -1397,7 +1428,8 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) ...@@ -1397,7 +1428,8 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
while (1) { while (1) {
struct mount_info *pm; struct mount_info *pm;
int len; char root[PATH_MAX] = ".";
int len, root_len = 1;
ret = pb_read_one_eof(img, &me, PB_MNT); ret = pb_read_one_eof(img, &me, PB_MNT);
if (ret <= 0) if (ret <= 0)
...@@ -1427,8 +1459,10 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) ...@@ -1427,8 +1459,10 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
if (!pm->root) if (!pm->root)
goto err; goto err;
pr_debug("\t\tGetting mpt for %d:%s\n", pm->mnt_id, me->mountpoint); if (nsid->id != root_item->ids->mnt_ns_id)
len = strlen(me->mountpoint) + 2; root_len = snprintf(root, sizeof(root), "%s/%d/",
mnt_roots, nsid->id);
len = strlen(me->mountpoint) + root_len + 1;
pm->mountpoint = xmalloc(len); pm->mountpoint = xmalloc(len);
if (!pm->mountpoint) if (!pm->mountpoint)
goto err; goto err;
...@@ -1439,8 +1473,10 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) ...@@ -1439,8 +1473,10 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
* that. * that.
*/ */
pm->mountpoint[0] = '.'; strcpy(pm->mountpoint, root);
strcpy(pm->mountpoint + 1, me->mountpoint); strcpy(pm->mountpoint + root_len, me->mountpoint);
pr_debug("\t\tGetting mpt for %d %s\n", pm->mnt_id, pm->mountpoint);
pr_debug("\t\tGetting source for %d\n", pm->mnt_id); pr_debug("\t\tGetting source for %d\n", pm->mnt_id);
pm->source = xstrdup(me->source); pm->source = xstrdup(me->source);
...@@ -1478,6 +1514,10 @@ static struct mount_info *read_mnt_ns_img() ...@@ -1478,6 +1514,10 @@ static struct mount_info *read_mnt_ns_img()
continue; continue;
} }
if (nsid->id != root_item->ids->mnt_ns_id)
if (create_mnt_roots(true))
return NULL;
if (collect_mnt_from_image(&pms, nsid)) if (collect_mnt_from_image(&pms, nsid))
goto err; goto err;
...@@ -1488,6 +1528,44 @@ err: ...@@ -1488,6 +1528,44 @@ err:
return NULL; return NULL;
} }
/*
* All nested mount namespaces are restore as sub-trees of the root namespace.
*/
static int prepare_roots_yard(void)
{
char path[PATH_MAX];
struct ns_id *nsid;
if (mnt_roots == NULL)
return 0;
if (mount("none", mnt_roots, "tmpfs", 0, NULL)) {
pr_perror("Unable to mount tmpfs in %s", mnt_roots);
return -1;
}
if (mount("none", mnt_roots, NULL, MS_PRIVATE, NULL))
return -1;
nsid = ns_ids;
while (nsid) {
if (nsid->nd != &mnt_ns_desc) {
nsid = nsid->next;
continue;
}
snprintf(path, sizeof(path), "%s/%d",
mnt_roots, nsid->id);
if (mkdir(path, 0600)) {
pr_perror("Unable to create %s", path);
return -1;
}
nsid = nsid->next;
}
return 0;
}
static int populate_mnt_ns(int ns_pid, struct mount_info *mis) static int populate_mnt_ns(int ns_pid, struct mount_info *mis)
{ {
struct mount_info *pms; struct mount_info *pms;
...@@ -1495,6 +1573,9 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis) ...@@ -1495,6 +1573,9 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis)
mntinfo_tree = NULL; mntinfo_tree = NULL;
mntinfo = mis; mntinfo = mis;
if (prepare_roots_yard())
return -1;
pms = mnt_build_tree(mntinfo); pms = mnt_build_tree(mntinfo);
if (!pms) if (!pms)
return -1; return -1;
...@@ -1506,6 +1587,35 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis) ...@@ -1506,6 +1587,35 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis)
return mnt_tree_for_each(pms, do_mount_one); return mnt_tree_for_each(pms, do_mount_one);
} }
int fini_mnt_ns()
{
int ret = 0;
if (mnt_roots == NULL)
return 0;
if (mount("none", mnt_roots, "none", MS_REC|MS_PRIVATE, NULL)) {
pr_perror("Can't remount root with MS_PRIVATE");
ret = 1;
}
/*
* Don't exit after a first error, becuase this function
* can be used to rollback in a error case.
* Don't worry about MNT_DETACH, because files are restored after this
* and nobody will not be restored from a wrong mount namespace.
*/
if (umount2(mnt_roots, MNT_DETACH)) {
pr_perror("Can't unmount %s", mnt_roots);
ret = 1;
}
if (rmdir(mnt_roots)) {
pr_perror("Can't remove the directory %s", mnt_roots);
ret = 1;
}
return ret;
}
int prepare_mnt_ns(int ns_pid) int prepare_mnt_ns(int ns_pid)
{ {
int ret = -1; int ret = -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment