mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 22:35:33 +00:00
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: Andrei Vagin <avagin@virtuozzo.com> Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
committed by
Pavel Emelyanov
parent
b20780d6a0
commit
2e8970beda
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
205
criu/mount.c
205
criu/mount.c
@@ -349,9 +349,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",
|
||||
@@ -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",
|
||||
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;
|
||||
@@ -399,10 +400,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;
|
||||
}
|
||||
@@ -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)
|
||||
if (fsroot_mounted(sm) ||
|
||||
(sm->parent == NULL &&
|
||||
(sm->parent == root_yard_mp &&
|
||||
strstartswith(bm->root, sm->root)))
|
||||
return sm;
|
||||
|
||||
@@ -1626,7 +1625,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;
|
||||
@@ -2003,10 +2002,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)
|
||||
@@ -2079,7 +2082,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);
|
||||
@@ -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);
|
||||
|
||||
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)
|
||||
@@ -2163,33 +2170,10 @@ static int do_remap_mount(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;
|
||||
}
|
||||
|
||||
@@ -2251,14 +2235,9 @@ static int fixup_remap_mounts()
|
||||
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)) {
|
||||
@@ -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)
|
||||
{
|
||||
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 = xstrdup(".criu.mntns.XXXXXX");
|
||||
mnt_roots = xstrdup("/tmp/.criu.mntns.XXXXXX");
|
||||
if (mnt_roots == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -2413,15 +2381,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;
|
||||
}
|
||||
|
||||
@@ -2519,8 +2482,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);
|
||||
@@ -2640,8 +2602,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] = '/';
|
||||
@@ -2651,28 +2612,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)
|
||||
@@ -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)
|
||||
{
|
||||
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;
|
||||
@@ -2708,7 +2654,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);
|
||||
@@ -2737,8 +2683,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;
|
||||
}
|
||||
}
|
||||
@@ -2752,9 +2697,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;
|
||||
|
||||
@@ -2833,14 +2775,6 @@ static int populate_mnt_ns(void)
|
||||
if (find_remap_mounts(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;
|
||||
|
||||
@@ -2858,7 +2792,7 @@ static int populate_mnt_ns(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __depopulate_roots_yard(void)
|
||||
int __depopulate_roots_yard(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -2982,64 +2916,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;
|
||||
|
||||
@@ -3053,16 +2934,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");
|
||||
|
Reference in New Issue
Block a user