Commit 2e8970be authored by Andrei Vagin's avatar Andrei Vagin Committed by Pavel Emelyanov

mount: create a mount point for the root mount namespace in the roots yard

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: 's avatarAndrei Vagin <avagin@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent b20780d6
#ifndef __CR_PATH_H__ #ifndef __CR_PATH_H__
#define __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 */ /* Asolute paths are used on dump and relative paths are used on restore */
static inline int is_root(char *p) static inline int is_root(char *p)
{ {
...@@ -10,7 +13,7 @@ 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) */ /* True for the root mount (the topmost one) */
static inline int is_root_mount(struct mount_info *mi) 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;
} }
/* /*
......
...@@ -349,9 +349,10 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou ...@@ -349,9 +349,10 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou
if (!parent) { if (!parent) {
/* This should be / */ /* This should be / */
if (root == NULL && is_root_mount(m)) { if (root == NULL && (!tmp_root_mount || is_root_mount(m))) {
root = m; root = m;
continue; if (!tmp_root_mount)
continue;
} }
pr_debug("Mountpoint %d (@%s) w/o parent %d\n", pr_debug("Mountpoint %d (@%s) w/o parent %d\n",
...@@ -383,7 +384,7 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou ...@@ -383,7 +384,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", pr_debug("Mountpoint %d (@%s) get parent %d (@%s)\n",
m->mnt_id, m->mountpoint, m->mnt_id, m->mountpoint,
parent->mnt_id, parent->mountpoint); parent->mnt_id, parent->mountpoint);
} else { } else if (root != m) {
pr_err("No root found for mountpoint %d (@%s)\n", pr_err("No root found for mountpoint %d (@%s)\n",
m->mnt_id, m->mountpoint); m->mnt_id, m->mountpoint);
return NULL; return NULL;
...@@ -399,10 +400,8 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou ...@@ -399,10 +400,8 @@ static struct mount_info *mnt_build_ids_tree(struct mount_info *list, struct mou
return NULL; return NULL;
} }
if (tmp_root_mount) { if (tmp_root_mount)
tmp_root_mount->parent = root; return tmp_root_mount;
list_add_tail(&tmp_root_mount->siblings, &root->children);
}
return root; return root;
} }
...@@ -622,7 +621,7 @@ static struct mount_info *find_fsroot_mount_for(struct mount_info *bm) ...@@ -622,7 +621,7 @@ static struct mount_info *find_fsroot_mount_for(struct mount_info *bm)
list_for_each_entry(sm, &bm->mnt_bind, mnt_bind) list_for_each_entry(sm, &bm->mnt_bind, mnt_bind)
if (fsroot_mounted(sm) || if (fsroot_mounted(sm) ||
(sm->parent == NULL && (sm->parent == root_yard_mp &&
strstartswith(bm->root, sm->root))) strstartswith(bm->root, sm->root)))
return sm; return sm;
...@@ -1626,7 +1625,7 @@ skip_parent: ...@@ -1626,7 +1625,7 @@ skip_parent:
* FIXME Currently non-root mounts can be restored * FIXME Currently non-root mounts can be restored
* only if a proper root mount exists * 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) { list_for_each_entry(t, &mi->mnt_bind, mnt_bind) {
if (t->mounted) if (t->mounted)
continue; continue;
...@@ -2003,10 +2002,14 @@ err: ...@@ -2003,10 +2002,14 @@ err:
return exit_code; 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) static bool can_mount_now(struct mount_info *mi)
{ {
/* The root mount */ if (rst_mnt_is_root(mi))
if (!mi->parent)
return true; return true;
if (mi->external) if (mi->external)
...@@ -2079,7 +2082,7 @@ static int do_mount_one(struct mount_info *mi) ...@@ -2079,7 +2082,7 @@ static int do_mount_one(struct mount_info *mi)
return 1; 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); mi->parent->fd = open(mi->parent->mountpoint, O_PATH);
if (mi->parent->fd < 0) { if (mi->parent->fd < 0) {
pr_perror("Unable to open %s", mi->mountpoint); pr_perror("Unable to open %s", mi->mountpoint);
...@@ -2089,8 +2092,12 @@ static int do_mount_one(struct mount_info *mi) ...@@ -2089,8 +2092,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); 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() */ /* 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; mi->mounted = true;
ret = 0; ret = 0;
} else if (!mi->bind && !mi->need_plugin && !mi->external) } else if (!mi->bind && !mi->need_plugin && !mi->external)
...@@ -2163,33 +2170,10 @@ static int do_remap_mount(struct mount_info *m) ...@@ -2163,33 +2170,10 @@ static int do_remap_mount(struct mount_info *m)
{ {
int len; int len;
if (m->nsid->type == NS_OTHER) { /* 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 already contains a roots_yard prefix and m->mountpoint[len] = '/';
* 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;
/*
* 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; return 0;
} }
...@@ -2251,14 +2235,9 @@ static int fixup_remap_mounts() ...@@ -2251,14 +2235,9 @@ static int fixup_remap_mounts()
char path[PATH_MAX]; char path[PATH_MAX];
int len; int len;
if (m->nsid->type == NS_ROOT) { strncpy(path, m->mountpoint, PATH_MAX);
path[0] = '.'; len = print_ns_root(m->nsid, 0, path, PATH_MAX);
strncpy(path + 1, m->ns_mountpoint, PATH_MAX - 1); path[len] = '/';
} else {
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); pr_debug("Move mount %s -> %s\n", m->mountpoint, path);
if (mount(m->mountpoint, path, NULL, MS_MOVE, NULL)) { if (mount(m->mountpoint, path, NULL, MS_MOVE, NULL)) {
...@@ -2388,23 +2367,12 @@ static inline int print_ns_root(struct ns_id *ns, int remap_id, char *buf, int b ...@@ -2388,23 +2367,12 @@ static inline int print_ns_root(struct ns_id *ns, int remap_id, char *buf, int b
static int create_mnt_roots(void) static int create_mnt_roots(void)
{ {
int exit_code = -1, cwd_fd; int exit_code = -1;
if (mnt_roots) if (mnt_roots)
return 0; return 0;
cwd_fd = open(".", O_DIRECTORY); mnt_roots = xstrdup("/tmp/.criu.mntns.XXXXXX");
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 = xstrdup(".criu.mntns.XXXXXX");
if (mnt_roots == NULL) if (mnt_roots == NULL)
goto out; goto out;
...@@ -2413,15 +2381,10 @@ static int create_mnt_roots(void) ...@@ -2413,15 +2381,10 @@ static int create_mnt_roots(void)
mnt_roots = NULL; mnt_roots = NULL;
goto out; goto out;
} }
chmod(mnt_roots, 0777);
exit_code = 0; exit_code = 0;
out: out:
if (fchdir(cwd_fd)) {
pr_perror("Unable to restore cwd");
exit_code = -1;
}
close(cwd_fd);
return exit_code; return exit_code;
} }
...@@ -2519,8 +2482,7 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) ...@@ -2519,8 +2482,7 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
if (!img) if (!img)
return -1; 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", pr_debug("Reading mountpoint images (id %d pid %d)\n",
nsid->id, (int)nsid->ns_pid); nsid->id, (int)nsid->ns_pid);
...@@ -2640,8 +2602,7 @@ int rst_get_mnt_root(int mnt_id, char *path, int plen) ...@@ -2640,8 +2602,7 @@ int rst_get_mnt_root(int mnt_id, char *path, int plen)
if (m == NULL) if (m == NULL)
return -1; 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: rroot:
path[0] = '/'; path[0] = '/';
...@@ -2651,28 +2612,10 @@ rroot: ...@@ -2651,28 +2612,10 @@ rroot:
int mntns_maybe_create_roots(void) int mntns_maybe_create_roots(void)
{ {
struct ns_id *ns;
if (!(root_ns_mask & CLONE_NEWNS)) if (!(root_ns_mask & CLONE_NEWNS))
return 0; return 0;
for (ns = ns_ids; ns != NULL; ns = ns->next) { return create_mnt_roots();
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;
} }
static int do_restore_task_mnt_ns(struct ns_id *nsid, struct pstree_item *current) static int do_restore_task_mnt_ns(struct ns_id *nsid, struct pstree_item *current)
...@@ -2695,6 +2638,9 @@ static int do_restore_task_mnt_ns(struct ns_id *nsid, struct pstree_item *curren ...@@ -2695,6 +2638,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) 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) { if (current->ids && current->ids->has_mnt_ns_id) {
unsigned int id = current->ids->mnt_ns_id; unsigned int id = current->ids->mnt_ns_id;
struct ns_id *nsid; struct ns_id *nsid;
...@@ -2708,7 +2654,7 @@ int restore_task_mnt_ns(struct pstree_item *current) ...@@ -2708,7 +2654,7 @@ int restore_task_mnt_ns(struct pstree_item *current)
* already there, otherwise it will have to do * already there, otherwise it will have to do
* setns(). * setns().
*/ */
if (!current->parent || id == current->parent->ids->mnt_ns_id) if (current->parent && id == current->parent->ids->mnt_ns_id)
return 0; return 0;
nsid = lookup_ns_by_id(id, &mnt_ns_desc); nsid = lookup_ns_by_id(id, &mnt_ns_desc);
...@@ -2737,8 +2683,7 @@ void fini_restore_mntns(void) ...@@ -2737,8 +2683,7 @@ void fini_restore_mntns(void)
if (nsid->nd != &mnt_ns_desc) if (nsid->nd != &mnt_ns_desc)
continue; continue;
close_safe(&nsid->mnt.ns_fd); 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; nsid->ns_populated = true;
} }
} }
...@@ -2752,9 +2697,6 @@ static int populate_roots_yard(void) ...@@ -2752,9 +2697,6 @@ static int populate_roots_yard(void)
char path[PATH_MAX]; char path[PATH_MAX];
struct ns_id *nsid; struct ns_id *nsid;
if (mnt_roots == NULL)
return 0;
if (make_yard(mnt_roots)) if (make_yard(mnt_roots))
return -1; return -1;
...@@ -2833,14 +2775,6 @@ static int populate_mnt_ns(void) ...@@ -2833,14 +2775,6 @@ static int populate_mnt_ns(void)
if (find_remap_mounts(pms)) if (find_remap_mounts(pms))
return -1; 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()) if (populate_roots_yard())
return -1; return -1;
...@@ -2858,7 +2792,7 @@ static int populate_mnt_ns(void) ...@@ -2858,7 +2792,7 @@ static int populate_mnt_ns(void)
return ret; return ret;
} }
static int __depopulate_roots_yard(void) int __depopulate_roots_yard(void)
{ {
int ret = 0; int ret = 0;
...@@ -2982,64 +2916,11 @@ int prepare_mnt_ns(void) ...@@ -2982,64 +2916,11 @@ int prepare_mnt_ns(void)
pr_info("Cleaning mount namespace\n"); pr_info("Cleaning mount namespace\n");
if (mnt_tree_for_each_reverse(ns.mnt.mntinfo_tree, do_umount_one)) if (mnt_tree_for_each_reverse(ns.mnt.mntinfo_tree, do_umount_one))
return -1; 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); free_mntinfo(old);
ret = populate_mnt_ns(); ret = populate_mnt_ns();
if (!ret && opts.root)
ret = cr_pivot_root(NULL);
if (ret) if (ret)
return -1; return -1;
...@@ -3053,16 +2934,6 @@ int prepare_mnt_ns(void) ...@@ -3053,16 +2934,6 @@ int prepare_mnt_ns(void)
if (nsid->nd != &mnt_ns_desc) if (nsid->nd != &mnt_ns_desc)
continue; 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 */ /* Create the new mount namespace */
if (unshare(CLONE_NEWNS)) { if (unshare(CLONE_NEWNS)) {
pr_perror("Unable to create a new mntns"); pr_perror("Unable to create a new mntns");
......
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