[CRIU] [PATCH 5/6] [v2] mnt: try to split a mount tree to restore over-mounted mounts
Andrei Vagin
avagin at virtuozzo.com
Wed Dec 7 17:35:51 PST 2016
On Mon, Dec 05, 2016 at 12:34:58PM +0300, Pavel Emelyanov wrote:
> 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?
Yes, you do
>
> > 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?
yes
>
> > + 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
Ok
>
> > +{
> > + 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()?
Ok
>
> > +{
> > + 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.
Ok
>
> > + 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