162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/pnode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright IBM Corporation 2005. 662306a36Sopenharmony_ci * Author : Ram Pai (linuxram@us.ibm.com) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/mnt_namespace.h> 962306a36Sopenharmony_ci#include <linux/mount.h> 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/nsproxy.h> 1262306a36Sopenharmony_ci#include <uapi/linux/mount.h> 1362306a36Sopenharmony_ci#include "internal.h" 1462306a36Sopenharmony_ci#include "pnode.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* return the next shared peer mount of @p */ 1762306a36Sopenharmony_cistatic inline struct mount *next_peer(struct mount *p) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci return list_entry(p->mnt_share.next, struct mount, mnt_share); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic inline struct mount *first_slave(struct mount *p) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic inline struct mount *last_slave(struct mount *p) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return list_entry(p->mnt_slave_list.prev, struct mount, mnt_slave); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic inline struct mount *next_slave(struct mount *p) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci return list_entry(p->mnt_slave.next, struct mount, mnt_slave); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic struct mount *get_peer_under_root(struct mount *mnt, 3862306a36Sopenharmony_ci struct mnt_namespace *ns, 3962306a36Sopenharmony_ci const struct path *root) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct mount *m = mnt; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci do { 4462306a36Sopenharmony_ci /* Check the namespace first for optimization */ 4562306a36Sopenharmony_ci if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root)) 4662306a36Sopenharmony_ci return m; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci m = next_peer(m); 4962306a36Sopenharmony_ci } while (m != mnt); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return NULL; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Get ID of closest dominating peer group having a representative 5662306a36Sopenharmony_ci * under the given root. 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Caller must hold namespace_sem 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ciint get_dominating_id(struct mount *mnt, const struct path *root) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct mount *m; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { 6562306a36Sopenharmony_ci struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root); 6662306a36Sopenharmony_ci if (d) 6762306a36Sopenharmony_ci return d->mnt_group_id; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int do_make_slave(struct mount *mnt) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct mount *master, *slave_mnt; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (list_empty(&mnt->mnt_share)) { 7862306a36Sopenharmony_ci if (IS_MNT_SHARED(mnt)) { 7962306a36Sopenharmony_ci mnt_release_group_id(mnt); 8062306a36Sopenharmony_ci CLEAR_MNT_SHARED(mnt); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci master = mnt->mnt_master; 8362306a36Sopenharmony_ci if (!master) { 8462306a36Sopenharmony_ci struct list_head *p = &mnt->mnt_slave_list; 8562306a36Sopenharmony_ci while (!list_empty(p)) { 8662306a36Sopenharmony_ci slave_mnt = list_first_entry(p, 8762306a36Sopenharmony_ci struct mount, mnt_slave); 8862306a36Sopenharmony_ci list_del_init(&slave_mnt->mnt_slave); 8962306a36Sopenharmony_ci slave_mnt->mnt_master = NULL; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci } else { 9462306a36Sopenharmony_ci struct mount *m; 9562306a36Sopenharmony_ci /* 9662306a36Sopenharmony_ci * slave 'mnt' to a peer mount that has the 9762306a36Sopenharmony_ci * same root dentry. If none is available then 9862306a36Sopenharmony_ci * slave it to anything that is available. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci for (m = master = next_peer(mnt); m != mnt; m = next_peer(m)) { 10162306a36Sopenharmony_ci if (m->mnt.mnt_root == mnt->mnt.mnt_root) { 10262306a36Sopenharmony_ci master = m; 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci list_del_init(&mnt->mnt_share); 10762306a36Sopenharmony_ci mnt->mnt_group_id = 0; 10862306a36Sopenharmony_ci CLEAR_MNT_SHARED(mnt); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave) 11162306a36Sopenharmony_ci slave_mnt->mnt_master = master; 11262306a36Sopenharmony_ci list_move(&mnt->mnt_slave, &master->mnt_slave_list); 11362306a36Sopenharmony_ci list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev); 11462306a36Sopenharmony_ci INIT_LIST_HEAD(&mnt->mnt_slave_list); 11562306a36Sopenharmony_ci mnt->mnt_master = master; 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* 12062306a36Sopenharmony_ci * vfsmount lock must be held for write 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_civoid change_mnt_propagation(struct mount *mnt, int type) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci if (type == MS_SHARED) { 12562306a36Sopenharmony_ci set_mnt_shared(mnt); 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci do_make_slave(mnt); 12962306a36Sopenharmony_ci if (type != MS_SLAVE) { 13062306a36Sopenharmony_ci list_del_init(&mnt->mnt_slave); 13162306a36Sopenharmony_ci mnt->mnt_master = NULL; 13262306a36Sopenharmony_ci if (type == MS_UNBINDABLE) 13362306a36Sopenharmony_ci mnt->mnt.mnt_flags |= MNT_UNBINDABLE; 13462306a36Sopenharmony_ci else 13562306a36Sopenharmony_ci mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * get the next mount in the propagation tree. 14162306a36Sopenharmony_ci * @m: the mount seen last 14262306a36Sopenharmony_ci * @origin: the original mount from where the tree walk initiated 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Note that peer groups form contiguous segments of slave lists. 14562306a36Sopenharmony_ci * We rely on that in get_source() to be able to find out if 14662306a36Sopenharmony_ci * vfsmount found while iterating with propagation_next() is 14762306a36Sopenharmony_ci * a peer of one we'd found earlier. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic struct mount *propagation_next(struct mount *m, 15062306a36Sopenharmony_ci struct mount *origin) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci /* are there any slaves of this mount? */ 15362306a36Sopenharmony_ci if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) 15462306a36Sopenharmony_ci return first_slave(m); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci while (1) { 15762306a36Sopenharmony_ci struct mount *master = m->mnt_master; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (master == origin->mnt_master) { 16062306a36Sopenharmony_ci struct mount *next = next_peer(m); 16162306a36Sopenharmony_ci return (next == origin) ? NULL : next; 16262306a36Sopenharmony_ci } else if (m->mnt_slave.next != &master->mnt_slave_list) 16362306a36Sopenharmony_ci return next_slave(m); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* back at master */ 16662306a36Sopenharmony_ci m = master; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic struct mount *skip_propagation_subtree(struct mount *m, 17162306a36Sopenharmony_ci struct mount *origin) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * Advance m such that propagation_next will not return 17562306a36Sopenharmony_ci * the slaves of m. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) 17862306a36Sopenharmony_ci m = last_slave(m); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return m; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic struct mount *next_group(struct mount *m, struct mount *origin) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci while (1) { 18662306a36Sopenharmony_ci while (1) { 18762306a36Sopenharmony_ci struct mount *next; 18862306a36Sopenharmony_ci if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) 18962306a36Sopenharmony_ci return first_slave(m); 19062306a36Sopenharmony_ci next = next_peer(m); 19162306a36Sopenharmony_ci if (m->mnt_group_id == origin->mnt_group_id) { 19262306a36Sopenharmony_ci if (next == origin) 19362306a36Sopenharmony_ci return NULL; 19462306a36Sopenharmony_ci } else if (m->mnt_slave.next != &next->mnt_slave) 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci m = next; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci /* m is the last peer */ 19962306a36Sopenharmony_ci while (1) { 20062306a36Sopenharmony_ci struct mount *master = m->mnt_master; 20162306a36Sopenharmony_ci if (m->mnt_slave.next != &master->mnt_slave_list) 20262306a36Sopenharmony_ci return next_slave(m); 20362306a36Sopenharmony_ci m = next_peer(master); 20462306a36Sopenharmony_ci if (master->mnt_group_id == origin->mnt_group_id) 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci if (master->mnt_slave.next == &m->mnt_slave) 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci m = master; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci if (m == origin) 21162306a36Sopenharmony_ci return NULL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* all accesses are serialized by namespace_sem */ 21662306a36Sopenharmony_cistatic struct mount *last_dest, *first_source, *last_source, *dest_master; 21762306a36Sopenharmony_cistatic struct hlist_head *list; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline bool peers(const struct mount *m1, const struct mount *m2) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int propagate_one(struct mount *m, struct mountpoint *dest_mp) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct mount *child; 22762306a36Sopenharmony_ci int type; 22862306a36Sopenharmony_ci /* skip ones added by this propagate_mnt() */ 22962306a36Sopenharmony_ci if (IS_MNT_NEW(m)) 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci /* skip if mountpoint isn't covered by it */ 23262306a36Sopenharmony_ci if (!is_subdir(dest_mp->m_dentry, m->mnt.mnt_root)) 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci if (peers(m, last_dest)) { 23562306a36Sopenharmony_ci type = CL_MAKE_SHARED; 23662306a36Sopenharmony_ci } else { 23762306a36Sopenharmony_ci struct mount *n, *p; 23862306a36Sopenharmony_ci bool done; 23962306a36Sopenharmony_ci for (n = m; ; n = p) { 24062306a36Sopenharmony_ci p = n->mnt_master; 24162306a36Sopenharmony_ci if (p == dest_master || IS_MNT_MARKED(p)) 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci do { 24562306a36Sopenharmony_ci struct mount *parent = last_source->mnt_parent; 24662306a36Sopenharmony_ci if (peers(last_source, first_source)) 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci done = parent->mnt_master == p; 24962306a36Sopenharmony_ci if (done && peers(n, parent)) 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci last_source = last_source->mnt_master; 25262306a36Sopenharmony_ci } while (!done); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci type = CL_SLAVE; 25562306a36Sopenharmony_ci /* beginning of peer group among the slaves? */ 25662306a36Sopenharmony_ci if (IS_MNT_SHARED(m)) 25762306a36Sopenharmony_ci type |= CL_MAKE_SHARED; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci child = copy_tree(last_source, last_source->mnt.mnt_root, type); 26162306a36Sopenharmony_ci if (IS_ERR(child)) 26262306a36Sopenharmony_ci return PTR_ERR(child); 26362306a36Sopenharmony_ci read_seqlock_excl(&mount_lock); 26462306a36Sopenharmony_ci mnt_set_mountpoint(m, dest_mp, child); 26562306a36Sopenharmony_ci if (m->mnt_master != dest_master) 26662306a36Sopenharmony_ci SET_MNT_MARK(m->mnt_master); 26762306a36Sopenharmony_ci read_sequnlock_excl(&mount_lock); 26862306a36Sopenharmony_ci last_dest = m; 26962306a36Sopenharmony_ci last_source = child; 27062306a36Sopenharmony_ci hlist_add_head(&child->mnt_hash, list); 27162306a36Sopenharmony_ci return count_mounts(m->mnt_ns, child); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/* 27562306a36Sopenharmony_ci * mount 'source_mnt' under the destination 'dest_mnt' at 27662306a36Sopenharmony_ci * dentry 'dest_dentry'. And propagate that mount to 27762306a36Sopenharmony_ci * all the peer and slave mounts of 'dest_mnt'. 27862306a36Sopenharmony_ci * Link all the new mounts into a propagation tree headed at 27962306a36Sopenharmony_ci * source_mnt. Also link all the new mounts using ->mnt_list 28062306a36Sopenharmony_ci * headed at source_mnt's ->mnt_list 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * @dest_mnt: destination mount. 28362306a36Sopenharmony_ci * @dest_dentry: destination dentry. 28462306a36Sopenharmony_ci * @source_mnt: source mount. 28562306a36Sopenharmony_ci * @tree_list : list of heads of trees to be attached. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ciint propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, 28862306a36Sopenharmony_ci struct mount *source_mnt, struct hlist_head *tree_list) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct mount *m, *n; 29162306a36Sopenharmony_ci int ret = 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * we don't want to bother passing tons of arguments to 29562306a36Sopenharmony_ci * propagate_one(); everything is serialized by namespace_sem, 29662306a36Sopenharmony_ci * so globals will do just fine. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci last_dest = dest_mnt; 29962306a36Sopenharmony_ci first_source = source_mnt; 30062306a36Sopenharmony_ci last_source = source_mnt; 30162306a36Sopenharmony_ci list = tree_list; 30262306a36Sopenharmony_ci dest_master = dest_mnt->mnt_master; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* all peers of dest_mnt, except dest_mnt itself */ 30562306a36Sopenharmony_ci for (n = next_peer(dest_mnt); n != dest_mnt; n = next_peer(n)) { 30662306a36Sopenharmony_ci ret = propagate_one(n, dest_mp); 30762306a36Sopenharmony_ci if (ret) 30862306a36Sopenharmony_ci goto out; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* all slave groups */ 31262306a36Sopenharmony_ci for (m = next_group(dest_mnt, dest_mnt); m; 31362306a36Sopenharmony_ci m = next_group(m, dest_mnt)) { 31462306a36Sopenharmony_ci /* everything in that slave group */ 31562306a36Sopenharmony_ci n = m; 31662306a36Sopenharmony_ci do { 31762306a36Sopenharmony_ci ret = propagate_one(n, dest_mp); 31862306a36Sopenharmony_ci if (ret) 31962306a36Sopenharmony_ci goto out; 32062306a36Sopenharmony_ci n = next_peer(n); 32162306a36Sopenharmony_ci } while (n != m); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ciout: 32462306a36Sopenharmony_ci read_seqlock_excl(&mount_lock); 32562306a36Sopenharmony_ci hlist_for_each_entry(n, tree_list, mnt_hash) { 32662306a36Sopenharmony_ci m = n->mnt_parent; 32762306a36Sopenharmony_ci if (m->mnt_master != dest_mnt->mnt_master) 32862306a36Sopenharmony_ci CLEAR_MNT_MARK(m->mnt_master); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci read_sequnlock_excl(&mount_lock); 33162306a36Sopenharmony_ci return ret; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic struct mount *find_topper(struct mount *mnt) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci /* If there is exactly one mount covering mnt completely return it. */ 33762306a36Sopenharmony_ci struct mount *child; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!list_is_singular(&mnt->mnt_mounts)) 34062306a36Sopenharmony_ci return NULL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci child = list_first_entry(&mnt->mnt_mounts, struct mount, mnt_child); 34362306a36Sopenharmony_ci if (child->mnt_mountpoint != mnt->mnt.mnt_root) 34462306a36Sopenharmony_ci return NULL; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return child; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * return true if the refcount is greater than count 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cistatic inline int do_refcount_check(struct mount *mnt, int count) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci return mnt_get_count(mnt) > count; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci/** 35862306a36Sopenharmony_ci * propagation_would_overmount - check whether propagation from @from 35962306a36Sopenharmony_ci * would overmount @to 36062306a36Sopenharmony_ci * @from: shared mount 36162306a36Sopenharmony_ci * @to: mount to check 36262306a36Sopenharmony_ci * @mp: future mountpoint of @to on @from 36362306a36Sopenharmony_ci * 36462306a36Sopenharmony_ci * If @from propagates mounts to @to, @from and @to must either be peers 36562306a36Sopenharmony_ci * or one of the masters in the hierarchy of masters of @to must be a 36662306a36Sopenharmony_ci * peer of @from. 36762306a36Sopenharmony_ci * 36862306a36Sopenharmony_ci * If the root of the @to mount is equal to the future mountpoint @mp of 36962306a36Sopenharmony_ci * the @to mount on @from then @to will be overmounted by whatever is 37062306a36Sopenharmony_ci * propagated to it. 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * Context: This function expects namespace_lock() to be held and that 37362306a36Sopenharmony_ci * @mp is stable. 37462306a36Sopenharmony_ci * Return: If @from overmounts @to, true is returned, false if not. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_cibool propagation_would_overmount(const struct mount *from, 37762306a36Sopenharmony_ci const struct mount *to, 37862306a36Sopenharmony_ci const struct mountpoint *mp) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci if (!IS_MNT_SHARED(from)) 38162306a36Sopenharmony_ci return false; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (IS_MNT_NEW(to)) 38462306a36Sopenharmony_ci return false; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (to->mnt.mnt_root != mp->m_dentry) 38762306a36Sopenharmony_ci return false; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci for (const struct mount *m = to; m; m = m->mnt_master) { 39062306a36Sopenharmony_ci if (peers(from, m)) 39162306a36Sopenharmony_ci return true; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return false; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci/* 39862306a36Sopenharmony_ci * check if the mount 'mnt' can be unmounted successfully. 39962306a36Sopenharmony_ci * @mnt: the mount to be checked for unmount 40062306a36Sopenharmony_ci * NOTE: unmounting 'mnt' would naturally propagate to all 40162306a36Sopenharmony_ci * other mounts its parent propagates to. 40262306a36Sopenharmony_ci * Check if any of these mounts that **do not have submounts** 40362306a36Sopenharmony_ci * have more references than 'refcnt'. If so return busy. 40462306a36Sopenharmony_ci * 40562306a36Sopenharmony_ci * vfsmount lock must be held for write 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ciint propagate_mount_busy(struct mount *mnt, int refcnt) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct mount *m, *child, *topper; 41062306a36Sopenharmony_ci struct mount *parent = mnt->mnt_parent; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (mnt == parent) 41362306a36Sopenharmony_ci return do_refcount_check(mnt, refcnt); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* 41662306a36Sopenharmony_ci * quickly check if the current mount can be unmounted. 41762306a36Sopenharmony_ci * If not, we don't have to go checking for all other 41862306a36Sopenharmony_ci * mounts 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt)) 42162306a36Sopenharmony_ci return 1; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci for (m = propagation_next(parent, parent); m; 42462306a36Sopenharmony_ci m = propagation_next(m, parent)) { 42562306a36Sopenharmony_ci int count = 1; 42662306a36Sopenharmony_ci child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); 42762306a36Sopenharmony_ci if (!child) 42862306a36Sopenharmony_ci continue; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Is there exactly one mount on the child that covers 43162306a36Sopenharmony_ci * it completely whose reference should be ignored? 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ci topper = find_topper(child); 43462306a36Sopenharmony_ci if (topper) 43562306a36Sopenharmony_ci count += 1; 43662306a36Sopenharmony_ci else if (!list_empty(&child->mnt_mounts)) 43762306a36Sopenharmony_ci continue; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (do_refcount_check(child, count)) 44062306a36Sopenharmony_ci return 1; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci/* 44662306a36Sopenharmony_ci * Clear MNT_LOCKED when it can be shown to be safe. 44762306a36Sopenharmony_ci * 44862306a36Sopenharmony_ci * mount_lock lock must be held for write 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_civoid propagate_mount_unlock(struct mount *mnt) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct mount *parent = mnt->mnt_parent; 45362306a36Sopenharmony_ci struct mount *m, *child; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci BUG_ON(parent == mnt); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci for (m = propagation_next(parent, parent); m; 45862306a36Sopenharmony_ci m = propagation_next(m, parent)) { 45962306a36Sopenharmony_ci child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); 46062306a36Sopenharmony_ci if (child) 46162306a36Sopenharmony_ci child->mnt.mnt_flags &= ~MNT_LOCKED; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic void umount_one(struct mount *mnt, struct list_head *to_umount) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci CLEAR_MNT_MARK(mnt); 46862306a36Sopenharmony_ci mnt->mnt.mnt_flags |= MNT_UMOUNT; 46962306a36Sopenharmony_ci list_del_init(&mnt->mnt_child); 47062306a36Sopenharmony_ci list_del_init(&mnt->mnt_umounting); 47162306a36Sopenharmony_ci list_move_tail(&mnt->mnt_list, to_umount); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* 47562306a36Sopenharmony_ci * NOTE: unmounting 'mnt' naturally propagates to all other mounts its 47662306a36Sopenharmony_ci * parent propagates to. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic bool __propagate_umount(struct mount *mnt, 47962306a36Sopenharmony_ci struct list_head *to_umount, 48062306a36Sopenharmony_ci struct list_head *to_restore) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci bool progress = false; 48362306a36Sopenharmony_ci struct mount *child; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* 48662306a36Sopenharmony_ci * The state of the parent won't change if this mount is 48762306a36Sopenharmony_ci * already unmounted or marked as without children. 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci if (mnt->mnt.mnt_flags & (MNT_UMOUNT | MNT_MARKED)) 49062306a36Sopenharmony_ci goto out; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Verify topper is the only grandchild that has not been 49362306a36Sopenharmony_ci * speculatively unmounted. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { 49662306a36Sopenharmony_ci if (child->mnt_mountpoint == mnt->mnt.mnt_root) 49762306a36Sopenharmony_ci continue; 49862306a36Sopenharmony_ci if (!list_empty(&child->mnt_umounting) && IS_MNT_MARKED(child)) 49962306a36Sopenharmony_ci continue; 50062306a36Sopenharmony_ci /* Found a mounted child */ 50162306a36Sopenharmony_ci goto children; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* Mark mounts that can be unmounted if not locked */ 50562306a36Sopenharmony_ci SET_MNT_MARK(mnt); 50662306a36Sopenharmony_ci progress = true; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* If a mount is without children and not locked umount it. */ 50962306a36Sopenharmony_ci if (!IS_MNT_LOCKED(mnt)) { 51062306a36Sopenharmony_ci umount_one(mnt, to_umount); 51162306a36Sopenharmony_ci } else { 51262306a36Sopenharmony_cichildren: 51362306a36Sopenharmony_ci list_move_tail(&mnt->mnt_umounting, to_restore); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ciout: 51662306a36Sopenharmony_ci return progress; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic void umount_list(struct list_head *to_umount, 52062306a36Sopenharmony_ci struct list_head *to_restore) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct mount *mnt, *child, *tmp; 52362306a36Sopenharmony_ci list_for_each_entry(mnt, to_umount, mnt_list) { 52462306a36Sopenharmony_ci list_for_each_entry_safe(child, tmp, &mnt->mnt_mounts, mnt_child) { 52562306a36Sopenharmony_ci /* topper? */ 52662306a36Sopenharmony_ci if (child->mnt_mountpoint == mnt->mnt.mnt_root) 52762306a36Sopenharmony_ci list_move_tail(&child->mnt_umounting, to_restore); 52862306a36Sopenharmony_ci else 52962306a36Sopenharmony_ci umount_one(child, to_umount); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic void restore_mounts(struct list_head *to_restore) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci /* Restore mounts to a clean working state */ 53762306a36Sopenharmony_ci while (!list_empty(to_restore)) { 53862306a36Sopenharmony_ci struct mount *mnt, *parent; 53962306a36Sopenharmony_ci struct mountpoint *mp; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci mnt = list_first_entry(to_restore, struct mount, mnt_umounting); 54262306a36Sopenharmony_ci CLEAR_MNT_MARK(mnt); 54362306a36Sopenharmony_ci list_del_init(&mnt->mnt_umounting); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* Should this mount be reparented? */ 54662306a36Sopenharmony_ci mp = mnt->mnt_mp; 54762306a36Sopenharmony_ci parent = mnt->mnt_parent; 54862306a36Sopenharmony_ci while (parent->mnt.mnt_flags & MNT_UMOUNT) { 54962306a36Sopenharmony_ci mp = parent->mnt_mp; 55062306a36Sopenharmony_ci parent = parent->mnt_parent; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci if (parent != mnt->mnt_parent) 55362306a36Sopenharmony_ci mnt_change_mountpoint(parent, mp, mnt); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic void cleanup_umount_visitations(struct list_head *visited) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci while (!list_empty(visited)) { 56062306a36Sopenharmony_ci struct mount *mnt = 56162306a36Sopenharmony_ci list_first_entry(visited, struct mount, mnt_umounting); 56262306a36Sopenharmony_ci list_del_init(&mnt->mnt_umounting); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci/* 56762306a36Sopenharmony_ci * collect all mounts that receive propagation from the mount in @list, 56862306a36Sopenharmony_ci * and return these additional mounts in the same list. 56962306a36Sopenharmony_ci * @list: the list of mounts to be unmounted. 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * vfsmount lock must be held for write 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ciint propagate_umount(struct list_head *list) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct mount *mnt; 57662306a36Sopenharmony_ci LIST_HEAD(to_restore); 57762306a36Sopenharmony_ci LIST_HEAD(to_umount); 57862306a36Sopenharmony_ci LIST_HEAD(visited); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* Find candidates for unmounting */ 58162306a36Sopenharmony_ci list_for_each_entry_reverse(mnt, list, mnt_list) { 58262306a36Sopenharmony_ci struct mount *parent = mnt->mnt_parent; 58362306a36Sopenharmony_ci struct mount *m; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * If this mount has already been visited it is known that it's 58762306a36Sopenharmony_ci * entire peer group and all of their slaves in the propagation 58862306a36Sopenharmony_ci * tree for the mountpoint has already been visited and there is 58962306a36Sopenharmony_ci * no need to visit them again. 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci if (!list_empty(&mnt->mnt_umounting)) 59262306a36Sopenharmony_ci continue; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci list_add_tail(&mnt->mnt_umounting, &visited); 59562306a36Sopenharmony_ci for (m = propagation_next(parent, parent); m; 59662306a36Sopenharmony_ci m = propagation_next(m, parent)) { 59762306a36Sopenharmony_ci struct mount *child = __lookup_mnt(&m->mnt, 59862306a36Sopenharmony_ci mnt->mnt_mountpoint); 59962306a36Sopenharmony_ci if (!child) 60062306a36Sopenharmony_ci continue; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (!list_empty(&child->mnt_umounting)) { 60362306a36Sopenharmony_ci /* 60462306a36Sopenharmony_ci * If the child has already been visited it is 60562306a36Sopenharmony_ci * know that it's entire peer group and all of 60662306a36Sopenharmony_ci * their slaves in the propgation tree for the 60762306a36Sopenharmony_ci * mountpoint has already been visited and there 60862306a36Sopenharmony_ci * is no need to visit this subtree again. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ci m = skip_propagation_subtree(m, parent); 61162306a36Sopenharmony_ci continue; 61262306a36Sopenharmony_ci } else if (child->mnt.mnt_flags & MNT_UMOUNT) { 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * We have come accross an partially unmounted 61562306a36Sopenharmony_ci * mount in list that has not been visited yet. 61662306a36Sopenharmony_ci * Remember it has been visited and continue 61762306a36Sopenharmony_ci * about our merry way. 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_ci list_add_tail(&child->mnt_umounting, &visited); 62062306a36Sopenharmony_ci continue; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* Check the child and parents while progress is made */ 62462306a36Sopenharmony_ci while (__propagate_umount(child, 62562306a36Sopenharmony_ci &to_umount, &to_restore)) { 62662306a36Sopenharmony_ci /* Is the parent a umount candidate? */ 62762306a36Sopenharmony_ci child = child->mnt_parent; 62862306a36Sopenharmony_ci if (list_empty(&child->mnt_umounting)) 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci umount_list(&to_umount, &to_restore); 63562306a36Sopenharmony_ci restore_mounts(&to_restore); 63662306a36Sopenharmony_ci cleanup_umount_visitations(&visited); 63762306a36Sopenharmony_ci list_splice_tail(&to_umount, list); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci} 641