mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-30 22:05:36 +00:00
mount: setup mnt_bind list before using it in mnt_is_external
Before this patch mnt_is_external() used non-populated mnt_bind list when called from resolve_shared_mounts(), thus it could work not as intended. Let's add separate helper search_bindmounts() for populating mnt_bind list, and add mnt_bind_is_populated to differentiate between non-populated list and just empty populated list. This way we can add a BUG_ON to mnt_is_external to catch such order problems in future. Cherry-picked from Virtuozzo criu: https://src.openvz.org/projects/OVZ/repos/criu/commits/e464c1c6d Cherry-picked from Virtuozzo criu: https://src.openvz.org/projects/OVZ/repos/criu/commits/8b22b30d5 Cherry-picked one hunk from Virtuozzo criu: https://src.openvz.org/projects/OVZ/repos/criu/commits/ca9de41e3 Changes: simplify commit message, merge fixups: search bindmounts earlier so that we have bindmounts info as early as possible, rename mnt_no_bind to mnt_bind_is_populated and simplify it's logic a bit. Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
This commit is contained in:
committed by
Andrei Vagin
parent
30261a7515
commit
261b7a8fd4
@@ -73,6 +73,7 @@ struct mount_info {
|
||||
struct list_head siblings;
|
||||
|
||||
struct list_head mnt_bind; /* circular list of derivatives of one real mount */
|
||||
bool mnt_bind_is_populated; /* indicate that mnt_bind list is ready to use */
|
||||
struct list_head mnt_share; /* circular list of shared mounts */
|
||||
struct list_head mnt_slave_list; /* list of slave mounts */
|
||||
struct list_head mnt_slave; /* slave list entry */
|
||||
|
64
criu/mount.c
64
criu/mount.c
@@ -571,6 +571,11 @@ static bool mnt_is_external(struct mount_info *m)
|
||||
if (t->external)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Shouldn't use mnt_bind list before it was populated in search_bindmounts
|
||||
*/
|
||||
BUG_ON(!m->mnt_bind_is_populated);
|
||||
|
||||
if (m->master_id <= 0 && !list_empty(&m->mnt_bind))
|
||||
list_for_each_entry(t, &m->mnt_bind, mnt_bind)
|
||||
if (issubpath(m->root, t->root) && t->external)
|
||||
@@ -892,6 +897,43 @@ static int same_propagation_group(struct mount_info *a, struct mount_info *b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: Only valid if called consequently on all mounts in mntinfo list.
|
||||
*
|
||||
* Note: We may want to iterate over all bindmounts of some mount, and we would
|
||||
* use ->mnt_bind list for this, but iterating over ->mnt_bind list is
|
||||
* obviously meaningless before search_bindmounts had actually put bindmounts
|
||||
* in it. That's why we have ->mnt_bind_is_populated to protect from misuse of
|
||||
* ->mnt_bind. (As ->mnt_bind list can validly be empty when mount has no
|
||||
* bindmounts we need separate field to indicate population.)
|
||||
*/
|
||||
static void __search_bindmounts(struct mount_info *mi)
|
||||
{
|
||||
struct mount_info *t;
|
||||
|
||||
if (mi->mnt_bind_is_populated)
|
||||
return;
|
||||
|
||||
for (t = mi->next; t; t = t->next) {
|
||||
if (mounts_sb_equal(mi, t)) {
|
||||
list_add(&t->mnt_bind, &mi->mnt_bind);
|
||||
t->mnt_bind_is_populated = true;
|
||||
pr_debug("\tThe mount %3d is bind for %3d (@%s -> @%s)\n", t->mnt_id, mi->mnt_id, t->mountpoint,
|
||||
mi->mountpoint);
|
||||
}
|
||||
}
|
||||
|
||||
mi->mnt_bind_is_populated = true;
|
||||
}
|
||||
|
||||
static void search_bindmounts(void)
|
||||
{
|
||||
struct mount_info *mi;
|
||||
|
||||
for (mi = mntinfo; mi; mi = mi->next)
|
||||
__search_bindmounts(mi);
|
||||
}
|
||||
|
||||
static int resolve_shared_mounts(struct mount_info *info, int root_master_id)
|
||||
{
|
||||
struct mount_info *m, *t;
|
||||
@@ -944,21 +986,6 @@ static int resolve_shared_mounts(struct mount_info *info, int root_master_id)
|
||||
m->mnt_id, m->mountpoint, m->master_id, m->shared_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Search bind-mounts */
|
||||
if (list_empty(&m->mnt_bind)) {
|
||||
/*
|
||||
* A first mounted point will be set up as a source point
|
||||
* for others. Look at propagate_mount()
|
||||
*/
|
||||
for (t = m->next; t; t = t->next) {
|
||||
if (mounts_sb_equal(m, t)) {
|
||||
list_add(&t->mnt_bind, &m->mnt_bind);
|
||||
pr_debug("\tThe mount %3d is bind for %3d (@%s -> @%s)\n", t->mnt_id, m->mnt_id,
|
||||
t->mountpoint, m->mountpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Search propagation groups */
|
||||
@@ -1539,6 +1566,7 @@ static __maybe_unused int add_cr_time_mount(struct mount_info *root, char *fsnam
|
||||
break;
|
||||
}
|
||||
|
||||
mi->mnt_bind_is_populated = true;
|
||||
mi->nsid = parent->nsid;
|
||||
mi->parent = parent;
|
||||
mi->parent_mnt_id = parent->mnt_id;
|
||||
@@ -3143,6 +3171,9 @@ int read_mnt_ns_img(void)
|
||||
}
|
||||
|
||||
mntinfo = pms;
|
||||
|
||||
search_bindmounts();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3320,6 +3351,7 @@ static int populate_mnt_ns(void)
|
||||
|
||||
root_yard_mp->mountpoint = mnt_roots;
|
||||
root_yard_mp->mounted = true;
|
||||
root_yard_mp->mnt_bind_is_populated = true;
|
||||
|
||||
if (merge_mount_trees(root_yard_mp))
|
||||
return -1;
|
||||
@@ -3756,6 +3788,8 @@ int collect_mnt_namespaces(bool for_dump)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
search_bindmounts();
|
||||
|
||||
#ifdef CONFIG_BINFMT_MISC_VIRTUALIZED
|
||||
if (for_dump && !opts.has_binfmt_misc) {
|
||||
unsigned int s_dev = 0;
|
||||
|
Reference in New Issue
Block a user