Commit 545b0736 authored by Pavel Tikhomirov's avatar Pavel Tikhomirov Committed by Andrei Vagin

mount: improve can_mount_now using propagation groups

1) redo waiting for parents of propagation group to be mounted using
pre-found propagation groups
2) for shared mount wait for children of that shared group which has no
propagation in our shared mount

(2) - effectively is a support of non-uniform shares, that means two
mounts of shared group can have different sets of children now - we will
mount them in the right order, but propagate_mount and validate_shared
are still preventing c/r-ing such shares, will fix the former and remove
the latter in separate(next) patches.
Signed-off-by: 's avatarPavel Tikhomirov <ptikhomirov@virtuozzo.com>
parent bc930d12
......@@ -66,6 +66,7 @@ struct mount_info {
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 mnt_notprop; /* temporary list used in can_mount_now */
struct list_head postpone;
......
......@@ -2456,6 +2456,9 @@ static bool can_mount_now(struct mount_info *mi)
if (rst_mnt_is_root(mi))
return true;
/* Parent should be mounted already, that's how mnt_tree_for_each works */
BUG_ON(mi->parent && !mi->parent->mounted);
if (mi->external)
goto shared;
......@@ -2485,28 +2488,67 @@ static bool can_mount_now(struct mount_info *mi)
return false;
shared:
if (mi->parent->shared_id) {
struct mount_info *n;
/* Mount only after all parents of our propagation group mounted */
if (!list_empty(&mi->mnt_propagate)) {
struct mount_info *p;
list_for_each_entry(n, &mi->parent->mnt_share, mnt_share)
/*
* All mounts from mi's parent shared group which
* have mi's 'sibling' should receive it through
* mount propagation, so all such mounts in parent
* shared group should be mounted beforehand.
*/
if (!n->mounted) {
char path[PATH_MAX], *mp;
struct mount_info *c;
list_for_each_entry(p, &mi->mnt_propagate, mnt_propagate) {
BUG_ON(!p->parent);
if (!p->parent->mounted)
return false;
}
}
/*
* Mount only after all children of share, which shouldn't
* (but can if wrong order) propagate to us, are mounted
*/
if (mi->shared_id) {
struct mount_info *s, *c, *p, *t;
LIST_HEAD(mi_notprop);
bool can = true;
/* Add all children of the shared group */
list_for_each_entry(s, &mi->mnt_share, mnt_share) {
list_for_each_entry(c, &s->children, siblings) {
char root_path[PATH_MAX];
int ret;
ret = root_path_from_parent(c, root_path, PATH_MAX);
BUG_ON(ret);
mp = mnt_get_sibling_path(mi, n, path, sizeof(path));
if (mp == NULL)
/* Mount is out of our root */
if (!issubpath(root_path, mi->root))
continue;
list_for_each_entry(c, &n->children, siblings)
if (mounts_equal(mi, c) && !strcmp(mp, c->mountpoint))
return false;
list_add(&c->mnt_notprop, &mi_notprop);
}
}
/* Delete all members of our children's propagation groups */
list_for_each_entry(c, &mi->children, siblings) {
list_for_each_entry(p, &c->mnt_propagate, mnt_propagate) {
list_del_init(&p->mnt_notprop);
}
}
/* Delete all members of our propagation group */
list_for_each_entry(p, &mi->mnt_propagate, mnt_propagate) {
list_del_init(&p->mnt_notprop);
}
/* Delete self */
list_del_init(&mi->mnt_notprop);
/* Check not propagated mounts mounted and cleanup list */
list_for_each_entry_safe(p, t, &mi_notprop, mnt_notprop) {
if (!p->mounted)
can = false;
list_del_init(&p->mnt_notprop);
}
if (!can)
return false;
}
return true;
......@@ -2798,6 +2840,7 @@ struct mount_info *mnt_entry_alloc()
INIT_LIST_HEAD(&new->mnt_share);
INIT_LIST_HEAD(&new->mnt_bind);
INIT_LIST_HEAD(&new->mnt_propagate);
INIT_LIST_HEAD(&new->mnt_notprop);
INIT_LIST_HEAD(&new->postpone);
}
return new;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment