[CRIU] [PATCH 5/6] [v2] mnt: try to split a mount tree to restore over-mounted mounts
Pavel Emelyanov
xemul at virtuozzo.com
Mon Dec 5 01:34:58 PST 2016
On 09/22/2016 09:16 AM, Andrei Vagin wrote:
> From: Andrei Vagin <avagin at virtuozzo.com>
>
> If a mount overmounts something else, we can try to restore it
> separetly and then move it to the right places after restoring
> all mounts.
>
> In this patch if we see that a mount is overmounts something,
> we create a new directory in the root yard and restore this
> mount and its sub-tree in this directory.
>
> https://bugs.openvz.org/browse/OVZ-6778
>
> v2: add more comments
> rename roots_mp into roots_yard_mp
>
> Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
> ---
> criu/mount.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 153 insertions(+), 1 deletion(-)
>
> diff --git a/criu/mount.c b/criu/mount.c
> index a64671f..ccbe1eb 100644
> --- a/criu/mount.c
> +++ b/criu/mount.c
> @@ -734,7 +734,8 @@ static int validate_mounts(struct mount_info *info, bool for_dump)
> }
> }
> skip_fstype:
> - if (does_mnt_overmount(m)) {
> + if (does_mnt_overmount(m) &&
> + !list_empty(&m->parent->mnt_share)) {
So 'shared overmounts' are still not supported, do I get this hunk right?
> pr_err("Unable to handle mounts under %d:%s\n",
> m->mnt_id, m->mountpoint);
> return -1;
> @@ -2913,6 +2914,143 @@ static int do_umount_one(struct mount_info *mi)
> return 0;
> }
>
> +/*
> + * If a mount overmounts other mounts, it is restored separetly in the roots
> + * yard and then moved to the right place.
> + *
> + * mnt_remap_entry is created for each such mount and it's added into
> + * mnt_remap_list. The origin mount point is replaced on a new one in
> + * roots_yard where it will be restored. The remapped mount will be
> + * moved to the right places after restoring all mounts.
> + */
> +
> +static inline int print_ns_root(struct ns_id *ns, int remap_id, char *buf, int bs);
> +static int get_mp_mountpoint(char *mountpoint, struct mount_info *mi, char *root, int root_len);
> +
> +static LIST_HEAD(mnt_remap_list);
> +static int remap_id;
> +
> +struct mnt_remap_entry {
> + struct mount_info *child; /* child is remaped into the root yards */
So child is the mi to be remapped, isn't it?
> + struct mount_info *parent; /* the origin parent for the child*/
> + struct list_head node;
> +};
> +
> +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;
> +
> + /*
> + * 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;
> +}
> +
> +static int remap_mnt(struct mount_info *m)
check_mnt_remap()? try_remap_mount()?
And the do_mnt_remap(0 should be symmetrically renamed :) E.g.
check_mnt_remap/do_mnt_remap
try_remap_mount/do_remap_mount
> +{
> + struct mnt_remap_entry *r;
> +
> + if (!does_mnt_overmount(m))
> + return 0;
> +
> + BUG_ON(!m->parent || !list_empty(&m->parent->mnt_share));
> +
> + r = xmalloc(sizeof(struct mnt_remap_entry));
> + if (!r)
> + return -1;
> +
> + r->child = m;
> + list_add(&r->node, &mnt_remap_list);
> +
> + return 0;
> +}
> +
> +static int handle_overmounts(struct mount_info *root)
setup_mnt_remaps()? or remap_overmounts()?
> +{
> + struct mnt_remap_entry *r;
> + struct mount_info *m;
> +
> + /* It's imposiable to change a tree without interrupting
> + * enumeration, so on the first step mounts are added
> + * into mnt_remap_list and then they are connected to root_yard_mp.
> + */
> + if (mnt_tree_for_each(root, remap_mnt))
> + return -1;
> +
> + /* Move remapped mounts to root_yard */
> + list_for_each_entry(r, &mnt_remap_list, node) {
> + m = r->child;
> + r->parent = m->parent;
> + m->parent = root_yard_mp;
> + list_del(&m->siblings);
> + list_add(&m->siblings, &root_yard_mp->children);
> +
> + remap_id++;
> + mnt_tree_for_each(m, do_mnt_remap);
> + pr_debug("Restore the %d mount in %s\n", m->mnt_id, m->mountpoint);
> + }
> +
> + return 0;
> +}
> +
> +/* Move remapped mounts to places where they have to be */
> +static int move_back_mnt_remaps()
> +{
> + struct mnt_remap_entry *r;
> +
> + list_for_each_entry(r, &mnt_remap_list, node) {
> + struct mount_info *m = r->child;
> + 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] = '/';
> + }
> +
> + pr_debug("Move mount %s -> %s\n", m->mountpoint, path);
> + if (mount(m->mountpoint, path, NULL, MS_MOVE, NULL)) {
> + pr_perror("Unable to move mount %s -> %s", m->mountpoint, path);
> + return -1;
> + }
> +
> + /* Insert child back to its place in the tree */
> + list_del(&r->child->siblings);
> + list_add(&r->child->siblings, &r->parent->children);
> + r->child->parent = r->parent;
> + }
> +
> + return 0;
> +}
> +
> static int cr_pivot_root(char *root)
> {
> char tmp_dir_tmpl[] = "crtools-put-root.XXXXXX";
> @@ -3394,6 +3532,7 @@ void fini_restore_mntns(void)
> */
> static int populate_roots_yard(void)
> {
> + struct mnt_remap_entry *r;
> char path[PATH_MAX];
> struct ns_id *nsid;
>
> @@ -3414,6 +3553,13 @@ static int populate_roots_yard(void)
> }
> }
>
> + list_for_each_entry(r, &mnt_remap_list, node) {
> + if (mkdirpat(AT_FDCWD, r->child->mountpoint)) {
Please, add a code comment saying where the mnt_remap_list is populated.
> + pr_perror("Unable to create %s", r->child->mountpoint);
> + return -1;
> + }
> + }
> +
> return 0;
> }
>
> @@ -3462,6 +3608,9 @@ static int populate_mnt_ns(void)
> if (validate_mounts(mntinfo, false))
> return -1;
>
> + 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
> @@ -3479,6 +3628,9 @@ static int populate_mnt_ns(void)
> ret = mnt_tree_for_each(pms, do_mount_one);
> mnt_tree_for_each(pms, do_close_one);
>
> + if (ret == 0 && move_back_mnt_remaps())
> + return -1;
> +
> if (umount_clean_path())
> return -1;
> return ret;
>
More information about the CRIU
mailing list