mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 06:15:24 +00:00
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 <ptikhomirov@virtuozzo.com>
This commit is contained in:
committed by
Andrei Vagin
parent
24bd5fcfff
commit
bc930d120e
@@ -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;
|
||||
|
||||
|
98
criu/mount.c
98
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;
|
||||
|
Reference in New Issue
Block a user