From bc930d120e70e9c219cb1dfc8e23c08ad5e06b6a Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Tue, 10 Jul 2018 19:02:27 +0300 Subject: [PATCH] mount: put all mounts which propagate from each other to a list These information will help improving the restore of tricky mounts configurations. Function same_propagation_group checks if two mounts were created simultaneousely through shared mount propagation, and the main part of these - they should be in exaclty the same place inside the share of their parents. Function root_path_from_parent prints the mountpoint path relative to the root of the parent's share, by first substracting parent's mountpoint from our mountpoint and second prepending parents root path (relative to the root of it's file system), e.g: id parent_id root mountpoint 1 0 / / 2 1 / /parent_a 3 1 /dir /parent_b 4 2 / /parent_a/dir/a 5 3 / /parent_b/a (Let 2 and 3 be a shared group) For mount 4 root_path_from_parent gives: "/parent_a/dir/a" - "/parent_a" == "/dir/a" "/" + "/dir/a" == "/dir/a" For mount 5: "/parent_b/a" - "/parent_b" == "/a" "/dir" + "/a" == "/dir/a" So mounts 4 and 5 are a propagation group. Signed-off-by: Pavel Tikhomirov --- criu/include/mount.h | 1 + criu/mount.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/criu/include/mount.h b/criu/include/mount.h index ed771ffac..84c62c8d0 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -65,6 +65,7 @@ struct mount_info { struct list_head mnt_slave_list; /* list of slave mounts */ struct list_head mnt_slave; /* slave list entry */ struct mount_info *mnt_master; /* slave is on master->mnt_slave_list */ + struct list_head mnt_propagate; /* circular list of mounts which propagate from each other */ struct list_head postpone; diff --git a/criu/mount.c b/criu/mount.c index d33a3cb86..1447e086a 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -931,6 +931,74 @@ static int resolve_external_mounts(struct mount_info *info) return 0; } +static int root_path_from_parent(struct mount_info *m, char *buf, int size) +{ + bool head_slash = false, tail_slash = false; + int p_len = strlen(m->parent->mountpoint), + m_len = strlen(m->mountpoint), + len; + + if (!m->parent) + return -1; + + len = snprintf(buf, size, "%s", m->parent->root); + if (len >= size) + return -1; + + BUG_ON(len <= 0); + if (buf[len-1] == '/') + tail_slash = true; + + size -= len; + buf += len; + + len = m_len - p_len; + BUG_ON(len < 0); + if (len) { + if (m->mountpoint[p_len] == '/') + head_slash = true; + + len = snprintf(buf, size, "%s%s", + (!tail_slash && !head_slash) ? "/" : "", + m->mountpoint + p_len + (tail_slash && head_slash)); + if (len >= size) + return -1; + } + + return 0; +} + +static int same_propagation_group(struct mount_info *a, struct mount_info *b) { + char root_path_a[PATH_MAX], root_path_b[PATH_MAX]; + + /* + * If mounts are in same propagation group: + * 1) Their parents should be different + * 2) Their parents should be together in same shared group + */ + if (!a->parent || !b->parent || a->parent == b->parent || + a->parent->shared_id != b->parent->shared_id) + return 0; + + if (root_path_from_parent(a, root_path_a, PATH_MAX)) { + pr_err("Failed to get root path for mount %d\n", a->mnt_id); + return -1; + } + + if (root_path_from_parent(b, root_path_b, PATH_MAX)) { + pr_err("Failed to get root path for mount %d\n", b->mnt_id); + return -1; + } + + /* + * 3) Their mountpoints relative to the root of the superblock of their + * parent's share should be equal + */ + if (!strcmp(root_path_a, root_path_b)) + return 1; + return 0; +} + static int resolve_shared_mounts(struct mount_info *info, int root_master_id) { struct mount_info *m, *t; @@ -1003,6 +1071,35 @@ static int resolve_shared_mounts(struct mount_info *info, int root_master_id) } } + /* Search propagation groups */ + for (m = info; m; m = m->next) { + struct mount_info *sparent; + + if (!list_empty(&m->mnt_propagate)) + continue; + + if (!m->parent || !m->parent->shared_id) + continue; + + list_for_each_entry(sparent, &m->parent->mnt_share, mnt_share) { + struct mount_info *schild; + + list_for_each_entry(schild, &sparent->children, siblings) { + int ret; + + ret = same_propagation_group(m, schild); + if (ret < 0) + return -1; + else if (ret) { + BUG_ON(!mounts_equal(m, schild)); + pr_debug("\tMount %3d is in same propagation group with %3d (@%s ~ @%s)\n", + m->mnt_id, schild->mnt_id, m->mountpoint, schild->mountpoint); + list_add(&schild->mnt_propagate, &m->mnt_propagate); + } + } + } + } + return 0; } @@ -2700,6 +2797,7 @@ struct mount_info *mnt_entry_alloc() INIT_LIST_HEAD(&new->mnt_slave_list); INIT_LIST_HEAD(&new->mnt_share); INIT_LIST_HEAD(&new->mnt_bind); + INIT_LIST_HEAD(&new->mnt_propagate); INIT_LIST_HEAD(&new->postpone); } return new;