mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-04 16:25:31 +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__
|
#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)
|
|||||||
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
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) {
|
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
|
|||||||
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
|
|||||||
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)
|
|||||||
|
|
||||||
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:
|
|||||||
* 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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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()
|
|||||||
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
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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:
|
|||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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");
|
||||||
|
Reference in New Issue
Block a user