[CRIU] [PATCH 10/12] mounts: create a temporary directory for restoring non-root mntns
Andrey Vagin
avagin at openvz.org
Fri Jan 10 05:50:04 PST 2014
All non-root namespaces will be restored as sub-trees of the root tree.
This patch creates 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.
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
cr-restore.c | 22 ++++++++-----
include/mount.h | 2 ++
mount.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+), 7 deletions(-)
diff --git a/cr-restore.c b/cr-restore.c
index 003e0f0..5825849 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1281,10 +1281,10 @@ static int restore_task_with_children(void *_arg)
* Thus -- mount proc at custom location for any new namespace
*/
if (mount_proc())
- exit(1);
+ goto err;
if (root_prepare_shared())
- exit(1);
+ goto err;
}
/*
@@ -1297,31 +1297,39 @@ static int restore_task_with_children(void *_arg)
ret = sigprocmask(SIG_BLOCK, &blockmask, NULL);
if (ret) {
pr_perror("%d: Can't block signals", current->pid.virt);
- exit(1);
+ goto err;
}
if (prepare_mappings(pid))
- exit(1);
+ goto err;
if ((!(ca->clone_flags & CLONE_FILES)) &&
current->parent && current->parent->rst->fdt)
close_old_servie_fd(current->parent->rst->fdt->nr);
if (create_children_and_session())
- exit(1);
+ goto err;
if (unmap_guard_pages())
- exit(1);
+ goto err;
restore_pgid();
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)
return 0;
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)
diff --git a/include/mount.h b/include/mount.h
index a76c027..c71f6e0 100644
--- a/include/mount.h
+++ b/include/mount.h
@@ -25,4 +25,6 @@ extern struct ns_desc mnt_ns_desc;
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 int fini_mnt_ns(void);
+
#endif /* __CR_MOUNT_H__ */
diff --git a/mount.c b/mount.c
index 1eed6c9..e6d54d0 100644
--- a/mount.c
+++ b/mount.c
@@ -1373,6 +1373,34 @@ static void free_mounts(void)
}
}
+static char *get_mnt_roots(bool create)
+{
+ static char *mnt_roots = NULL;
+
+ if (!create || mnt_roots)
+ return mnt_roots;
+
+ if (chdir(opts.root ? : "/")) {
+ pr_perror("Unable to change working directory on %s", opts.root);
+ return NULL;
+ }
+
+ mnt_roots = strdup(".criu.mntns.XXXXXX");
+ if (mnt_roots == NULL) {
+ pr_perror("Can't allocate memory");
+ return NULL;
+ }
+
+ if (mkdtemp(mnt_roots) == NULL) {
+ pr_perror("Unable to create a temporary directory");
+ mnt_roots = NULL;
+ return NULL;
+ }
+
+ return mnt_roots;
+
+}
+
static struct mount_info *read_mnt_ns_img(int ns_pid)
{
MntEntry *me = NULL;
@@ -1452,6 +1480,45 @@ err:
return NULL;
}
+/*
+ * All nested mount namespaces are restore as sub-trees of the root namespace.
+ */
+static int prepare_temporary_roots()
+{
+ char path[PATH_MAX];
+ struct ns_id *nsid;
+ char *mnt_roots = get_mnt_roots(false);
+
+ 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)
{
struct mount_info *pms;
@@ -1459,6 +1526,9 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis)
mntinfo_tree = NULL;
mntinfo = mis;
+ if (prepare_temporary_roots())
+ return -1;
+
pms = mnt_build_tree(mntinfo);
if (!pms)
return -1;
@@ -1470,6 +1540,34 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis)
return mnt_tree_for_each(pms, do_mount_one);
}
+int fini_mnt_ns()
+{
+ char *mnt_roots = get_mnt_roots(false);
+ 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
+ */
+ 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 ret = -1;
--
1.8.3.1
More information about the CRIU
mailing list