From patchwork Thu Oct 20 19:06:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [1/2] mount: create a mount point for the root mount namespace in the roots yard From: Andrei Vagin X-Patchwork-Id: 2084 Message-Id: <1476990420-16256-2-git-send-email-avagin@openvz.org> To: xemul@virtuozzo.com Cc: criu@openvz.org, Andrei Vagin Date: Thu, 20 Oct 2016 22:06:59 +0300 From: Andrei Vagin These chnages allows us to: * avoid difference between the root mount namespace and other mount namespaces * support a read-only root mount * don't create temporary directories in the root mount Signed-off-by: Andrei Vagin --- criu/include/path.h | 5 +- criu/mount.c | 205 ++++++++++------------------------------------------ 2 files changed, 42 insertions(+), 168 deletions(-) diff --git a/criu/include/path.h b/criu/include/path.h index 5fec3a9..b00c64a 100644 --- a/criu/include/path.h +++ b/criu/include/path.h @@ -1,6 +1,9 @@ #ifndef __CR_PATH_H__ #define __CR_PATH_H__ +#include "namespaces.h" +#include "pstree.h" + /* Asolute paths are used on dump and relative paths are used on restore */ static inline int is_root(char *p) { @@ -10,7 +13,7 @@ static inline int is_root(char *p) /* True for the root mount (the topmost one) */ static inline int is_root_mount(struct mount_info *mi) { - return is_root(mi->mountpoint + 1); + return mi->parent == NULL && mi->nsid->id == root_item->ids->mnt_ns_id; } /* diff --git a/criu/mount.c b/criu/mount.c index bb1378d..ba177f3 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -361,9 +361,10 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou if (!parent) { /* This should be / */ - if (root == NULL && is_root_mount(m)) { + if (root == NULL && (!tmp_root_mount || is_root_mount(m))) { root = m; - continue; + if (!tmp_root_mount) + continue; } pr_debug("Mountpoint %d (@%s) w/o parent %d\n", @@ -395,7 +396,7 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou pr_debug("Mountpoint %d (@%s) get parent %d (@%s)\n", m->mnt_id, m->mountpoint, parent->mnt_id, parent->mountpoint); - } else { + } else if (root != m) { pr_err("No root found for mountpoint %d (@%s)\n", m->mnt_id, m->mountpoint); return NULL; @@ -411,10 +412,8 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou return NULL; } - if (tmp_root_mount) { - tmp_root_mount->parent = root; - list_add_tail(&tmp_root_mount->siblings, &root->children); - } + if (tmp_root_mount) + return tmp_root_mount; return root; } @@ -634,7 +633,7 @@ static struct mount_info *find_fsroot_mount_for(struct mount_info *bm) list_for_each_entry(sm, &bm->mnt_bind, mnt_bind) if (fsroot_mounted(sm) || - (sm->parent == NULL && + (sm->parent == root_yard_mp && strstartswith(bm->root, sm->root))) return sm; @@ -1642,7 +1641,7 @@ skip_parent: * FIXME Currently non-root mounts can be restored * only if a proper root mount exists */ - if (fsroot_mounted(mi) || mi->parent == NULL) { + if (fsroot_mounted(mi) || mi->parent == root_yard_mp) { list_for_each_entry(t, &mi->mnt_bind, mnt_bind) { if (t->mounted) continue; @@ -1984,10 +1983,14 @@ err: return exit_code; } +static bool rst_mnt_is_root(struct mount_info *m) +{ + return (m->is_ns_root && m->nsid->id == root_item->ids->mnt_ns_id); +} + static bool can_mount_now(struct mount_info *mi) { - /* The root mount */ - if (!mi->parent) + if (rst_mnt_is_root(mi)) return true; if (mi->external) @@ -2060,7 +2063,7 @@ static int do_mount_one(struct mount_info *mi) return 1; } - if (mi->parent && !strcmp(mi->parent->mountpoint, mi->mountpoint)) { + if (!strcmp(mi->parent->mountpoint, mi->mountpoint)) { mi->parent->fd = open(mi->parent->mountpoint, O_PATH); if (mi->parent->fd < 0) { pr_perror("Unable to open %s", mi->mountpoint); @@ -2070,8 +2073,12 @@ static int do_mount_one(struct mount_info *mi) pr_debug("\tMounting %s @%s (%d)\n", mi->fstype->name, mi->mountpoint, mi->need_plugin); - if (!mi->parent) { + if (rst_mnt_is_root(mi)) { /* do_mount_root() is called from populate_mnt_ns() */ + if (mount(opts.root, mi->mountpoint, NULL, MS_BIND | MS_REC, NULL)) + return -1; + if (do_mount_root(mi)) + return -1; mi->mounted = true; ret = 0; } else if (!mi->bind && !mi->need_plugin && !mi->external) @@ -2144,33 +2151,10 @@ static int do_mnt_remap(struct mount_info *m) { int len; - if (m->nsid->type == NS_OTHER) { - /* - * m->mountpoint already contains a roots_yard prefix and - * it has a fixed size, so it can be just replaced. - */ - len = print_ns_root(m->nsid, remap_id, m->mountpoint, PATH_MAX); - m->mountpoint[len] = '/'; - } else if (m->nsid->type == NS_ROOT) { - char root[PATH_MAX], *mp, *ns_mp; - int len, ret; + /* A path in root_yard has a fixed size, so it can be replaced. */ + len = print_ns_root(m->nsid, remap_id, m->mountpoint, PATH_MAX); + m->mountpoint[len] = '/'; - /* - * Allocate a new path in the roots yard. m->mountpoint in the - * root namespace doesn't have a roots_yard prefix, so its - * size has to be changed and a new storage has to be - * allocated. - */ - mp = m->mountpoint; ns_mp = m->ns_mountpoint; - - len = print_ns_root(m->nsid, remap_id, root, PATH_MAX); - - ret = get_mp_mountpoint(ns_mp, m, root, len); - if (ret < 0) - return ret; - xfree(mp); - } else - BUG(); return 0; } @@ -2231,14 +2215,9 @@ static int move_back_mnt_remaps() char path[PATH_MAX]; int len; - if (m->nsid->type == NS_ROOT) { - path[0] = '.'; - strncpy(path + 1, m->ns_mountpoint, PATH_MAX - 1); - } else { - strncpy(path, m->mountpoint, PATH_MAX); - len = print_ns_root(m->nsid, 0, path, PATH_MAX); - path[len] = '/'; - } + strncpy(path, m->mountpoint, PATH_MAX); + len = print_ns_root(m->nsid, 0, path, PATH_MAX); + path[len] = '/'; pr_debug("Move mount %s -> %s\n", m->mountpoint, path); if (mount(m->mountpoint, path, NULL, MS_MOVE, NULL)) { @@ -2368,23 +2347,12 @@ static inline int print_ns_root(struct ns_id *ns, int remap_id, char *buf, int b static int create_mnt_roots(void) { - int exit_code = -1, cwd_fd; + int exit_code = -1; if (mnt_roots) return 0; - cwd_fd = open(".", O_DIRECTORY); - if (cwd_fd < 0) { - pr_perror("Unable to open cwd"); - return -1; - } - - if (chdir(opts.root ? : "/")) { - pr_perror("Unable to change working directory on %s", opts.root); - goto out; - } - - mnt_roots = strdup(".criu.mntns.XXXXXX"); + mnt_roots = strdup("/tmp/.criu.mntns.XXXXXX"); if (mnt_roots == NULL) { pr_perror("Can't allocate memory"); goto out; @@ -2395,15 +2363,10 @@ static int create_mnt_roots(void) mnt_roots = NULL; goto out; } + chmod(mnt_roots, 0777); exit_code = 0; out: - if (fchdir(cwd_fd)) { - pr_perror("Unable to restore cwd"); - exit_code = -1; - } - close(cwd_fd); - return exit_code; } @@ -2503,8 +2466,7 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) if (!img) return -1; - if (nsid->type == NS_OTHER) - root_len = print_ns_root(nsid, 0, root, sizeof(root)); + root_len = print_ns_root(nsid, 0, root, sizeof(root)); pr_debug("Reading mountpoint images (id %d pid %d)\n", nsid->id, (int)nsid->ns_pid); @@ -2624,8 +2586,7 @@ int rst_get_mnt_root(int mnt_id, char *path, int plen) if (m == NULL) return -1; - if (m->nsid->type == NS_OTHER) - return print_ns_root(m->nsid, 0, path, plen); + return print_ns_root(m->nsid, 0, path, plen); rroot: path[0] = '/'; @@ -2635,28 +2596,10 @@ rroot: int mntns_maybe_create_roots(void) { - struct ns_id *ns; - if (!(root_ns_mask & CLONE_NEWNS)) return 0; - for (ns = ns_ids; ns != NULL; ns = ns->next) { - if (ns->nd != &mnt_ns_desc) - continue; - - if (ns->type != NS_ROOT) { - BUG_ON(ns->type == NS_CRIU); - - /* - * If we have more than one (root) namespace, - * then we'll need the roots yard. - */ - return create_mnt_roots(); - } - } - - /* No "other" mntns found, just go ahead, we don't need roots yard. */ - return 0; + return create_mnt_roots(); } static int do_restore_task_mnt_ns(struct ns_id *nsid, struct pstree_item *current) @@ -2679,6 +2622,9 @@ static int do_restore_task_mnt_ns(struct ns_id *nsid, struct pstree_item *curren int restore_task_mnt_ns(struct pstree_item *current) { + if ((root_ns_mask & CLONE_NEWNS) == 0) + return 0; + if (current->ids && current->ids->has_mnt_ns_id) { unsigned int id = current->ids->mnt_ns_id; struct ns_id *nsid; @@ -2692,7 +2638,7 @@ int restore_task_mnt_ns(struct pstree_item *current) * already there, otherwise it will have to do * setns(). */ - if (!current->parent || id == current->parent->ids->mnt_ns_id) + if (current->parent && id == current->parent->ids->mnt_ns_id) return 0; nsid = lookup_ns_by_id(id, &mnt_ns_desc); @@ -2721,8 +2667,7 @@ void fini_restore_mntns(void) if (nsid->nd != &mnt_ns_desc) continue; close_safe(&nsid->mnt.ns_fd); - if (nsid->type != NS_ROOT) - close_safe(&nsid->mnt.root_fd); + close_safe(&nsid->mnt.root_fd); nsid->ns_populated = true; } } @@ -2736,9 +2681,6 @@ static int populate_roots_yard(void) char path[PATH_MAX]; struct ns_id *nsid; - if (mnt_roots == NULL) - return 0; - if (make_yard(mnt_roots)) return -1; @@ -2811,14 +2753,6 @@ static int populate_mnt_ns(void) if (handle_overmounts(pms)) return -1; - /* - * Set properties for the root before mounting a root yard, - * otherwise the root yard can be propagated into the host - * mntns and remain there. - */ - if (do_mount_root(pms)) - return -1; - if (populate_roots_yard()) return -1; @@ -2836,7 +2770,7 @@ static int populate_mnt_ns(void) return ret; } -static int __depopulate_roots_yard(void) +int __depopulate_roots_yard(void) { int ret = 0; @@ -2961,64 +2895,11 @@ int prepare_mnt_ns(void) pr_info("Cleaning mount namespace\n"); if (mnt_tree_for_each_reverse(ns.mnt.mntinfo_tree, do_umount_one)) return -1; - } else { - struct mount_info *mi; - char *ret; - char path[PATH_MAX]; - - /* - * The whole tree of mountpoints is to be moved into one - * place with the pivot_root() call. Don't do manual - * umount (as we do above), all this stuff will go away - * with a single umount call later. - */ - - ret = realpath(opts.root, path); - if (!ret) { - pr_err("Unable to find real path for %s\n", opts.root); - return -1; - } - - /* moving a mount residing under a shared mount is invalid. */ - mi = mount_resolve_path(ns.mnt.mntinfo_tree, path); - if (mi == NULL) { - pr_err("Unable to find mount point for %s\n", opts.root); - return -1; - } - if (mi->parent == NULL) { - pr_err("New root and old root are the same\n"); - return -1; - } - - /* Our root is mounted over the parent (in the same directory) */ - if (!strcmp(mi->parent->mountpoint, mi->mountpoint)) { - pr_err("The parent of the new root is unreachable\n"); - return -1; - } - - if (mount("none", mi->parent->mountpoint + 1, "none", MS_SLAVE, NULL)) { - pr_perror("Can't remount the parent of the new root with MS_SLAVE"); - return -1; - } - - /* Unprivileged users can't reveal what is under a mount */ - if (root_ns_mask & CLONE_NEWUSER) { - if (mount(opts.root, opts.root, NULL, MS_BIND | MS_REC, NULL)) { - pr_perror("Can't remount bind-mount %s into itself", opts.root); - return -1; - } - } - if (chdir(opts.root)) { - pr_perror("chdir(%s) failed", opts.root ? : "/"); - return -1; - } } free_mntinfo(old); ret = populate_mnt_ns(); - if (!ret && opts.root) - ret = cr_pivot_root(NULL); if (ret) return -1; @@ -3032,16 +2913,6 @@ int prepare_mnt_ns(void) if (nsid->nd != &mnt_ns_desc) continue; - if (nsid->type == NS_ROOT) { - /* Pin one with a file descriptor */ - nsid->mnt.ns_fd = open_proc(PROC_SELF, "ns/mnt"); - if (nsid->mnt.ns_fd < 0) - goto err; - /* we set ns_populated so we don't need to open root_fd */ - nsid->ns_populated = true; - continue; - } - /* Create the new mount namespace */ if (unshare(CLONE_NEWNS)) { pr_perror("Unable to create a new mntns");