159bd9dedSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 207b20889SRam Pai /* 307b20889SRam Pai * linux/fs/pnode.c 407b20889SRam Pai * 507b20889SRam Pai * (C) Copyright IBM Corporation 2005. 607b20889SRam Pai * Author : Ram Pai (linuxram@us.ibm.com) 707b20889SRam Pai */ 86b3286edSKirill Korotaev #include <linux/mnt_namespace.h> 907b20889SRam Pai #include <linux/mount.h> 1007b20889SRam Pai #include <linux/fs.h> 11132c94e3SEric W. Biederman #include <linux/nsproxy.h> 12e262e32dSDavid Howells #include <uapi/linux/mount.h> 136d59e7f5SAl Viro #include "internal.h" 1407b20889SRam Pai #include "pnode.h" 1507b20889SRam Pai 1603e06e68SRam Pai /* return the next shared peer mount of @p */ 17c937135dSAl Viro static inline struct mount *next_peer(struct mount *p) 1803e06e68SRam Pai { 196776db3dSAl Viro return list_entry(p->mnt_share.next, struct mount, mnt_share); 2003e06e68SRam Pai } 2103e06e68SRam Pai 22c937135dSAl Viro static inline struct mount *first_slave(struct mount *p) 235afe0022SRam Pai { 246776db3dSAl Viro return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave); 255afe0022SRam Pai } 265afe0022SRam Pai 27296990deSEric W. Biederman static inline struct mount *last_slave(struct mount *p) 28296990deSEric W. Biederman { 29296990deSEric W. Biederman return list_entry(p->mnt_slave_list.prev, struct mount, mnt_slave); 30296990deSEric W. Biederman } 31296990deSEric W. Biederman 32c937135dSAl Viro static inline struct mount *next_slave(struct mount *p) 335afe0022SRam Pai { 346776db3dSAl Viro return list_entry(p->mnt_slave.next, struct mount, mnt_slave); 355afe0022SRam Pai } 365afe0022SRam Pai 376fc7871fSAl Viro static struct mount *get_peer_under_root(struct mount *mnt, 3897e7e0f7SMiklos Szeredi struct mnt_namespace *ns, 3997e7e0f7SMiklos Szeredi const struct path *root) 4097e7e0f7SMiklos Szeredi { 416fc7871fSAl Viro struct mount *m = mnt; 4297e7e0f7SMiklos Szeredi 4397e7e0f7SMiklos Szeredi do { 4497e7e0f7SMiklos Szeredi /* Check the namespace first for optimization */ 45143c8c91SAl Viro if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root)) 466fc7871fSAl Viro return m; 4797e7e0f7SMiklos Szeredi 48c937135dSAl Viro m = next_peer(m); 496fc7871fSAl Viro } while (m != mnt); 5097e7e0f7SMiklos Szeredi 5197e7e0f7SMiklos Szeredi return NULL; 5297e7e0f7SMiklos Szeredi } 5397e7e0f7SMiklos Szeredi 5497e7e0f7SMiklos Szeredi /* 5597e7e0f7SMiklos Szeredi * Get ID of closest dominating peer group having a representative 5697e7e0f7SMiklos Szeredi * under the given root. 5797e7e0f7SMiklos Szeredi * 5897e7e0f7SMiklos Szeredi * Caller must hold namespace_sem 5997e7e0f7SMiklos Szeredi */ 606fc7871fSAl Viro int get_dominating_id(struct mount *mnt, const struct path *root) 6197e7e0f7SMiklos Szeredi { 626fc7871fSAl Viro struct mount *m; 6397e7e0f7SMiklos Szeredi 6432301920SAl Viro for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { 65143c8c91SAl Viro struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root); 6697e7e0f7SMiklos Szeredi if (d) 6715169fe7SAl Viro return d->mnt_group_id; 6897e7e0f7SMiklos Szeredi } 6997e7e0f7SMiklos Szeredi 7097e7e0f7SMiklos Szeredi return 0; 7197e7e0f7SMiklos Szeredi } 7297e7e0f7SMiklos Szeredi 736fc7871fSAl Viro static int do_make_slave(struct mount *mnt) 74a58b0eb8SRam Pai { 755235d448SAl Viro struct mount *master, *slave_mnt; 76a58b0eb8SRam Pai 775235d448SAl Viro if (list_empty(&mnt->mnt_share)) { 785235d448SAl Viro if (IS_MNT_SHARED(mnt)) { 796fc7871fSAl Viro mnt_release_group_id(mnt); 805235d448SAl Viro CLEAR_MNT_SHARED(mnt); 815235d448SAl Viro } 825235d448SAl Viro master = mnt->mnt_master; 835235d448SAl Viro if (!master) { 846776db3dSAl Viro struct list_head *p = &mnt->mnt_slave_list; 85a58b0eb8SRam Pai while (!list_empty(p)) { 86b5e61818SPavel Emelianov slave_mnt = list_first_entry(p, 876776db3dSAl Viro struct mount, mnt_slave); 886776db3dSAl Viro list_del_init(&slave_mnt->mnt_slave); 89a58b0eb8SRam Pai slave_mnt->mnt_master = NULL; 90a58b0eb8SRam Pai } 915235d448SAl Viro return 0; 92a58b0eb8SRam Pai } 935235d448SAl Viro } else { 945235d448SAl Viro struct mount *m; 955235d448SAl Viro /* 965235d448SAl Viro * slave 'mnt' to a peer mount that has the 975235d448SAl Viro * same root dentry. If none is available then 985235d448SAl Viro * slave it to anything that is available. 995235d448SAl Viro */ 1005235d448SAl Viro for (m = master = next_peer(mnt); m != mnt; m = next_peer(m)) { 1015235d448SAl Viro if (m->mnt.mnt_root == mnt->mnt.mnt_root) { 1025235d448SAl Viro master = m; 1035235d448SAl Viro break; 1045235d448SAl Viro } 1055235d448SAl Viro } 1065235d448SAl Viro list_del_init(&mnt->mnt_share); 1075235d448SAl Viro mnt->mnt_group_id = 0; 108fc7be130SAl Viro CLEAR_MNT_SHARED(mnt); 1095235d448SAl Viro } 1105235d448SAl Viro list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave) 1115235d448SAl Viro slave_mnt->mnt_master = master; 1125235d448SAl Viro list_move(&mnt->mnt_slave, &master->mnt_slave_list); 1135235d448SAl Viro list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev); 1145235d448SAl Viro INIT_LIST_HEAD(&mnt->mnt_slave_list); 1155235d448SAl Viro mnt->mnt_master = master; 116a58b0eb8SRam Pai return 0; 117a58b0eb8SRam Pai } 118a58b0eb8SRam Pai 11999b7db7bSNick Piggin /* 12099b7db7bSNick Piggin * vfsmount lock must be held for write 12199b7db7bSNick Piggin */ 1220f0afb1dSAl Viro void change_mnt_propagation(struct mount *mnt, int type) 12307b20889SRam Pai { 12403e06e68SRam Pai if (type == MS_SHARED) { 125b90fa9aeSRam Pai set_mnt_shared(mnt); 126a58b0eb8SRam Pai return; 127a58b0eb8SRam Pai } 1286fc7871fSAl Viro do_make_slave(mnt); 129a58b0eb8SRam Pai if (type != MS_SLAVE) { 1306776db3dSAl Viro list_del_init(&mnt->mnt_slave); 131d10e8defSAl Viro mnt->mnt_master = NULL; 1329676f0c6SRam Pai if (type == MS_UNBINDABLE) 1330f0afb1dSAl Viro mnt->mnt.mnt_flags |= MNT_UNBINDABLE; 1340b03cfb2SAndries E. Brouwer else 1350f0afb1dSAl Viro mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE; 13607b20889SRam Pai } 13703e06e68SRam Pai } 138b90fa9aeSRam Pai 139b90fa9aeSRam Pai /* 140b90fa9aeSRam Pai * get the next mount in the propagation tree. 141b90fa9aeSRam Pai * @m: the mount seen last 142b90fa9aeSRam Pai * @origin: the original mount from where the tree walk initiated 143796a6b52SAl Viro * 144796a6b52SAl Viro * Note that peer groups form contiguous segments of slave lists. 145796a6b52SAl Viro * We rely on that in get_source() to be able to find out if 146796a6b52SAl Viro * vfsmount found while iterating with propagation_next() is 147796a6b52SAl Viro * a peer of one we'd found earlier. 148b90fa9aeSRam Pai */ 149c937135dSAl Viro static struct mount *propagation_next(struct mount *m, 150c937135dSAl Viro struct mount *origin) 151b90fa9aeSRam Pai { 1525afe0022SRam Pai /* are there any slaves of this mount? */ 153143c8c91SAl Viro if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) 1545afe0022SRam Pai return first_slave(m); 1555afe0022SRam Pai 1565afe0022SRam Pai while (1) { 15732301920SAl Viro struct mount *master = m->mnt_master; 1585afe0022SRam Pai 15932301920SAl Viro if (master == origin->mnt_master) { 160c937135dSAl Viro struct mount *next = next_peer(m); 161c937135dSAl Viro return (next == origin) ? NULL : next; 1626776db3dSAl Viro } else if (m->mnt_slave.next != &master->mnt_slave_list) 1635afe0022SRam Pai return next_slave(m); 1645afe0022SRam Pai 1655afe0022SRam Pai /* back at master */ 1665afe0022SRam Pai m = master; 1675afe0022SRam Pai } 1685afe0022SRam Pai } 1695afe0022SRam Pai 170296990deSEric W. Biederman static struct mount *skip_propagation_subtree(struct mount *m, 171296990deSEric W. Biederman struct mount *origin) 172296990deSEric W. Biederman { 173296990deSEric W. Biederman /* 174296990deSEric W. Biederman * Advance m such that propagation_next will not return 175296990deSEric W. Biederman * the slaves of m. 176296990deSEric W. Biederman */ 177296990deSEric W. Biederman if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) 178296990deSEric W. Biederman m = last_slave(m); 179296990deSEric W. Biederman 180296990deSEric W. Biederman return m; 181296990deSEric W. Biederman } 182296990deSEric W. Biederman 183f2ebb3a9SAl Viro static struct mount *next_group(struct mount *m, struct mount *origin) 1845afe0022SRam Pai { 185f2ebb3a9SAl Viro while (1) { 186f2ebb3a9SAl Viro while (1) { 187f2ebb3a9SAl Viro struct mount *next; 188f2ebb3a9SAl Viro if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) 189f2ebb3a9SAl Viro return first_slave(m); 190f2ebb3a9SAl Viro next = next_peer(m); 191f2ebb3a9SAl Viro if (m->mnt_group_id == origin->mnt_group_id) { 192f2ebb3a9SAl Viro if (next == origin) 193f2ebb3a9SAl Viro return NULL; 194f2ebb3a9SAl Viro } else if (m->mnt_slave.next != &next->mnt_slave) 195f2ebb3a9SAl Viro break; 196f2ebb3a9SAl Viro m = next; 197f2ebb3a9SAl Viro } 198f2ebb3a9SAl Viro /* m is the last peer */ 199f2ebb3a9SAl Viro while (1) { 200f2ebb3a9SAl Viro struct mount *master = m->mnt_master; 201f2ebb3a9SAl Viro if (m->mnt_slave.next != &master->mnt_slave_list) 202f2ebb3a9SAl Viro return next_slave(m); 203f2ebb3a9SAl Viro m = next_peer(master); 204f2ebb3a9SAl Viro if (master->mnt_group_id == origin->mnt_group_id) 205f2ebb3a9SAl Viro break; 206f2ebb3a9SAl Viro if (master->mnt_slave.next == &m->mnt_slave) 207f2ebb3a9SAl Viro break; 208f2ebb3a9SAl Viro m = master; 209f2ebb3a9SAl Viro } 210f2ebb3a9SAl Viro if (m == origin) 211f2ebb3a9SAl Viro return NULL; 212f2ebb3a9SAl Viro } 2135afe0022SRam Pai } 2145afe0022SRam Pai 215f2ebb3a9SAl Viro /* all accesses are serialized by namespace_sem */ 2165ec0811dSEric W. Biederman static struct mount *last_dest, *first_source, *last_source, *dest_master; 217f2ebb3a9SAl Viro static struct mountpoint *mp; 218f2ebb3a9SAl Viro static struct hlist_head *list; 219f2ebb3a9SAl Viro 2207ae8fd03SMaxim Patlasov static inline bool peers(struct mount *m1, struct mount *m2) 2217ae8fd03SMaxim Patlasov { 2227ae8fd03SMaxim Patlasov return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id; 2237ae8fd03SMaxim Patlasov } 2247ae8fd03SMaxim Patlasov 225f2ebb3a9SAl Viro static int propagate_one(struct mount *m) 226f2ebb3a9SAl Viro { 227f2ebb3a9SAl Viro struct mount *child; 228f2ebb3a9SAl Viro int type; 229f2ebb3a9SAl Viro /* skip ones added by this propagate_mnt() */ 230f2ebb3a9SAl Viro if (IS_MNT_NEW(m)) 231f2ebb3a9SAl Viro return 0; 232f2ebb3a9SAl Viro /* skip if mountpoint isn't covered by it */ 233f2ebb3a9SAl Viro if (!is_subdir(mp->m_dentry, m->mnt.mnt_root)) 234f2ebb3a9SAl Viro return 0; 2357ae8fd03SMaxim Patlasov if (peers(m, last_dest)) { 236f2ebb3a9SAl Viro type = CL_MAKE_SHARED; 237f2ebb3a9SAl Viro } else { 238f2ebb3a9SAl Viro struct mount *n, *p; 2395ec0811dSEric W. Biederman bool done; 240f2ebb3a9SAl Viro for (n = m; ; n = p) { 241f2ebb3a9SAl Viro p = n->mnt_master; 2425ec0811dSEric W. Biederman if (p == dest_master || IS_MNT_MARKED(p)) 243f2ebb3a9SAl Viro break; 244b90fa9aeSRam Pai } 2455ec0811dSEric W. Biederman do { 2465ec0811dSEric W. Biederman struct mount *parent = last_source->mnt_parent; 2475ec0811dSEric W. Biederman if (last_source == first_source) 2485ec0811dSEric W. Biederman break; 2495ec0811dSEric W. Biederman done = parent->mnt_master == p; 2505ec0811dSEric W. Biederman if (done && peers(n, parent)) 2515ec0811dSEric W. Biederman break; 2525ec0811dSEric W. Biederman last_source = last_source->mnt_master; 2535ec0811dSEric W. Biederman } while (!done); 2545ec0811dSEric W. Biederman 255f2ebb3a9SAl Viro type = CL_SLAVE; 256796a6b52SAl Viro /* beginning of peer group among the slaves? */ 257f2ebb3a9SAl Viro if (IS_MNT_SHARED(m)) 258f2ebb3a9SAl Viro type |= CL_MAKE_SHARED; 259f2ebb3a9SAl Viro } 260f2ebb3a9SAl Viro 261f2ebb3a9SAl Viro child = copy_tree(last_source, last_source->mnt.mnt_root, type); 262f2ebb3a9SAl Viro if (IS_ERR(child)) 263f2ebb3a9SAl Viro return PTR_ERR(child); 264f2ebb3a9SAl Viro read_seqlock_excl(&mount_lock); 265*b0d3869cSAl Viro mnt_set_mountpoint(m, mp, child); 266*b0d3869cSAl Viro if (m->mnt_master != dest_master) 267f2ebb3a9SAl Viro SET_MNT_MARK(m->mnt_master); 268f2ebb3a9SAl Viro read_sequnlock_excl(&mount_lock); 269*b0d3869cSAl Viro last_dest = m; 270*b0d3869cSAl Viro last_source = child; 271f2ebb3a9SAl Viro hlist_add_head(&child->mnt_hash, list); 272d2921684SEric W. Biederman return count_mounts(m->mnt_ns, child); 273796a6b52SAl Viro } 274b90fa9aeSRam Pai 275b90fa9aeSRam Pai /* 276b90fa9aeSRam Pai * mount 'source_mnt' under the destination 'dest_mnt' at 277b90fa9aeSRam Pai * dentry 'dest_dentry'. And propagate that mount to 278b90fa9aeSRam Pai * all the peer and slave mounts of 'dest_mnt'. 279b90fa9aeSRam Pai * Link all the new mounts into a propagation tree headed at 280b90fa9aeSRam Pai * source_mnt. Also link all the new mounts using ->mnt_list 281b90fa9aeSRam Pai * headed at source_mnt's ->mnt_list 282b90fa9aeSRam Pai * 283b90fa9aeSRam Pai * @dest_mnt: destination mount. 284b90fa9aeSRam Pai * @dest_dentry: destination dentry. 285b90fa9aeSRam Pai * @source_mnt: source mount. 286b90fa9aeSRam Pai * @tree_list : list of heads of trees to be attached. 287b90fa9aeSRam Pai */ 28884d17192SAl Viro int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, 28938129a13SAl Viro struct mount *source_mnt, struct hlist_head *tree_list) 290b90fa9aeSRam Pai { 291f2ebb3a9SAl Viro struct mount *m, *n; 292b90fa9aeSRam Pai int ret = 0; 293b90fa9aeSRam Pai 294f2ebb3a9SAl Viro /* 295f2ebb3a9SAl Viro * we don't want to bother passing tons of arguments to 296f2ebb3a9SAl Viro * propagate_one(); everything is serialized by namespace_sem, 297f2ebb3a9SAl Viro * so globals will do just fine. 298f2ebb3a9SAl Viro */ 299f2ebb3a9SAl Viro last_dest = dest_mnt; 3005ec0811dSEric W. Biederman first_source = source_mnt; 301f2ebb3a9SAl Viro last_source = source_mnt; 302f2ebb3a9SAl Viro mp = dest_mp; 303f2ebb3a9SAl Viro list = tree_list; 304f2ebb3a9SAl Viro dest_master = dest_mnt->mnt_master; 305b90fa9aeSRam Pai 306f2ebb3a9SAl Viro /* all peers of dest_mnt, except dest_mnt itself */ 307f2ebb3a9SAl Viro for (n = next_peer(dest_mnt); n != dest_mnt; n = next_peer(n)) { 308f2ebb3a9SAl Viro ret = propagate_one(n); 309f2ebb3a9SAl Viro if (ret) 310b90fa9aeSRam Pai goto out; 311b90fa9aeSRam Pai } 312b90fa9aeSRam Pai 313f2ebb3a9SAl Viro /* all slave groups */ 314f2ebb3a9SAl Viro for (m = next_group(dest_mnt, dest_mnt); m; 315f2ebb3a9SAl Viro m = next_group(m, dest_mnt)) { 316f2ebb3a9SAl Viro /* everything in that slave group */ 317f2ebb3a9SAl Viro n = m; 318f2ebb3a9SAl Viro do { 319f2ebb3a9SAl Viro ret = propagate_one(n); 320f2ebb3a9SAl Viro if (ret) 321f2ebb3a9SAl Viro goto out; 322f2ebb3a9SAl Viro n = next_peer(n); 323f2ebb3a9SAl Viro } while (n != m); 324b90fa9aeSRam Pai } 325b90fa9aeSRam Pai out: 326f2ebb3a9SAl Viro read_seqlock_excl(&mount_lock); 327f2ebb3a9SAl Viro hlist_for_each_entry(n, tree_list, mnt_hash) { 328f2ebb3a9SAl Viro m = n->mnt_parent; 329f2ebb3a9SAl Viro if (m->mnt_master != dest_mnt->mnt_master) 330f2ebb3a9SAl Viro CLEAR_MNT_MARK(m->mnt_master); 331b90fa9aeSRam Pai } 332f2ebb3a9SAl Viro read_sequnlock_excl(&mount_lock); 333b90fa9aeSRam Pai return ret; 334b90fa9aeSRam Pai } 335a05964f3SRam Pai 3361064f874SEric W. Biederman static struct mount *find_topper(struct mount *mnt) 3371064f874SEric W. Biederman { 3381064f874SEric W. Biederman /* If there is exactly one mount covering mnt completely return it. */ 3391064f874SEric W. Biederman struct mount *child; 3401064f874SEric W. Biederman 3411064f874SEric W. Biederman if (!list_is_singular(&mnt->mnt_mounts)) 3421064f874SEric W. Biederman return NULL; 3431064f874SEric W. Biederman 3441064f874SEric W. Biederman child = list_first_entry(&mnt->mnt_mounts, struct mount, mnt_child); 3451064f874SEric W. Biederman if (child->mnt_mountpoint != mnt->mnt.mnt_root) 3461064f874SEric W. Biederman return NULL; 3471064f874SEric W. Biederman 3481064f874SEric W. Biederman return child; 3491064f874SEric W. Biederman } 3501064f874SEric W. Biederman 351a05964f3SRam Pai /* 352a05964f3SRam Pai * return true if the refcount is greater than count 353a05964f3SRam Pai */ 3541ab59738SAl Viro static inline int do_refcount_check(struct mount *mnt, int count) 355a05964f3SRam Pai { 356aba809cfSAl Viro return mnt_get_count(mnt) > count; 357a05964f3SRam Pai } 358a05964f3SRam Pai 359a05964f3SRam Pai /* 360a05964f3SRam Pai * check if the mount 'mnt' can be unmounted successfully. 361a05964f3SRam Pai * @mnt: the mount to be checked for unmount 362a05964f3SRam Pai * NOTE: unmounting 'mnt' would naturally propagate to all 363a05964f3SRam Pai * other mounts its parent propagates to. 364a05964f3SRam Pai * Check if any of these mounts that **do not have submounts** 365a05964f3SRam Pai * have more references than 'refcnt'. If so return busy. 36699b7db7bSNick Piggin * 367b3e19d92SNick Piggin * vfsmount lock must be held for write 368a05964f3SRam Pai */ 3691ab59738SAl Viro int propagate_mount_busy(struct mount *mnt, int refcnt) 370a05964f3SRam Pai { 3711064f874SEric W. Biederman struct mount *m, *child, *topper; 3720714a533SAl Viro struct mount *parent = mnt->mnt_parent; 373a05964f3SRam Pai 3740714a533SAl Viro if (mnt == parent) 375a05964f3SRam Pai return do_refcount_check(mnt, refcnt); 376a05964f3SRam Pai 377a05964f3SRam Pai /* 378a05964f3SRam Pai * quickly check if the current mount can be unmounted. 379a05964f3SRam Pai * If not, we don't have to go checking for all other 380a05964f3SRam Pai * mounts 381a05964f3SRam Pai */ 3826b41d536SAl Viro if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt)) 383a05964f3SRam Pai return 1; 384a05964f3SRam Pai 385c937135dSAl Viro for (m = propagation_next(parent, parent); m; 386c937135dSAl Viro m = propagation_next(m, parent)) { 3871064f874SEric W. Biederman int count = 1; 3881064f874SEric W. Biederman child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); 3891064f874SEric W. Biederman if (!child) 3901064f874SEric W. Biederman continue; 3911064f874SEric W. Biederman 3921064f874SEric W. Biederman /* Is there exactly one mount on the child that covers 3931064f874SEric W. Biederman * it completely whose reference should be ignored? 3941064f874SEric W. Biederman */ 3951064f874SEric W. Biederman topper = find_topper(child); 3961064f874SEric W. Biederman if (topper) 3971064f874SEric W. Biederman count += 1; 3981064f874SEric W. Biederman else if (!list_empty(&child->mnt_mounts)) 3991064f874SEric W. Biederman continue; 4001064f874SEric W. Biederman 4011064f874SEric W. Biederman if (do_refcount_check(child, count)) 4021064f874SEric W. Biederman return 1; 403a05964f3SRam Pai } 4041064f874SEric W. Biederman return 0; 405a05964f3SRam Pai } 406a05964f3SRam Pai 407a05964f3SRam Pai /* 4085d88457eSEric W. Biederman * Clear MNT_LOCKED when it can be shown to be safe. 4095d88457eSEric W. Biederman * 4105d88457eSEric W. Biederman * mount_lock lock must be held for write 4115d88457eSEric W. Biederman */ 4125d88457eSEric W. Biederman void propagate_mount_unlock(struct mount *mnt) 4135d88457eSEric W. Biederman { 4145d88457eSEric W. Biederman struct mount *parent = mnt->mnt_parent; 4155d88457eSEric W. Biederman struct mount *m, *child; 4165d88457eSEric W. Biederman 4175d88457eSEric W. Biederman BUG_ON(parent == mnt); 4185d88457eSEric W. Biederman 4195d88457eSEric W. Biederman for (m = propagation_next(parent, parent); m; 4205d88457eSEric W. Biederman m = propagation_next(m, parent)) { 4211064f874SEric W. Biederman child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint); 4225d88457eSEric W. Biederman if (child) 4235d88457eSEric W. Biederman child->mnt.mnt_flags &= ~MNT_LOCKED; 4245d88457eSEric W. Biederman } 4255d88457eSEric W. Biederman } 4265d88457eSEric W. Biederman 42799b19d16SEric W. Biederman static void umount_one(struct mount *mnt, struct list_head *to_umount) 4280c56fe31SEric W. Biederman { 42999b19d16SEric W. Biederman CLEAR_MNT_MARK(mnt); 43099b19d16SEric W. Biederman mnt->mnt.mnt_flags |= MNT_UMOUNT; 43199b19d16SEric W. Biederman list_del_init(&mnt->mnt_child); 43299b19d16SEric W. Biederman list_del_init(&mnt->mnt_umounting); 43399b19d16SEric W. Biederman list_move_tail(&mnt->mnt_list, to_umount); 4340c56fe31SEric W. Biederman } 4350c56fe31SEric W. Biederman 4360c56fe31SEric W. Biederman /* 437a05964f3SRam Pai * NOTE: unmounting 'mnt' naturally propagates to all other mounts its 438a05964f3SRam Pai * parent propagates to. 439a05964f3SRam Pai */ 44099b19d16SEric W. Biederman static bool __propagate_umount(struct mount *mnt, 44199b19d16SEric W. Biederman struct list_head *to_umount, 44299b19d16SEric W. Biederman struct list_head *to_restore) 443a05964f3SRam Pai { 44499b19d16SEric W. Biederman bool progress = false; 44599b19d16SEric W. Biederman struct mount *child; 446a05964f3SRam Pai 447a05964f3SRam Pai /* 44899b19d16SEric W. Biederman * The state of the parent won't change if this mount is 44999b19d16SEric W. Biederman * already unmounted or marked as without children. 450a05964f3SRam Pai */ 45199b19d16SEric W. Biederman if (mnt->mnt.mnt_flags & (MNT_UMOUNT | MNT_MARKED)) 45299b19d16SEric W. Biederman goto out; 45399b19d16SEric W. Biederman 45499b19d16SEric W. Biederman /* Verify topper is the only grandchild that has not been 45599b19d16SEric W. Biederman * speculatively unmounted. 45699b19d16SEric W. Biederman */ 45799b19d16SEric W. Biederman list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { 45899b19d16SEric W. Biederman if (child->mnt_mountpoint == mnt->mnt.mnt_root) 4590c56fe31SEric W. Biederman continue; 46099b19d16SEric W. Biederman if (!list_empty(&child->mnt_umounting) && IS_MNT_MARKED(child)) 46199b19d16SEric W. Biederman continue; 46299b19d16SEric W. Biederman /* Found a mounted child */ 46399b19d16SEric W. Biederman goto children; 464a05964f3SRam Pai } 465a05964f3SRam Pai 46699b19d16SEric W. Biederman /* Mark mounts that can be unmounted if not locked */ 46799b19d16SEric W. Biederman SET_MNT_MARK(mnt); 46899b19d16SEric W. Biederman progress = true; 46999b19d16SEric W. Biederman 47099b19d16SEric W. Biederman /* If a mount is without children and not locked umount it. */ 47199b19d16SEric W. Biederman if (!IS_MNT_LOCKED(mnt)) { 47299b19d16SEric W. Biederman umount_one(mnt, to_umount); 47399b19d16SEric W. Biederman } else { 47499b19d16SEric W. Biederman children: 47599b19d16SEric W. Biederman list_move_tail(&mnt->mnt_umounting, to_restore); 47699b19d16SEric W. Biederman } 47799b19d16SEric W. Biederman out: 47899b19d16SEric W. Biederman return progress; 47999b19d16SEric W. Biederman } 48099b19d16SEric W. Biederman 48199b19d16SEric W. Biederman static void umount_list(struct list_head *to_umount, 48299b19d16SEric W. Biederman struct list_head *to_restore) 483570487d3SEric W. Biederman { 48499b19d16SEric W. Biederman struct mount *mnt, *child, *tmp; 48599b19d16SEric W. Biederman list_for_each_entry(mnt, to_umount, mnt_list) { 48699b19d16SEric W. Biederman list_for_each_entry_safe(child, tmp, &mnt->mnt_mounts, mnt_child) { 48799b19d16SEric W. Biederman /* topper? */ 48899b19d16SEric W. Biederman if (child->mnt_mountpoint == mnt->mnt.mnt_root) 48999b19d16SEric W. Biederman list_move_tail(&child->mnt_umounting, to_restore); 49099b19d16SEric W. Biederman else 49199b19d16SEric W. Biederman umount_one(child, to_umount); 49299b19d16SEric W. Biederman } 49399b19d16SEric W. Biederman } 49499b19d16SEric W. Biederman } 49599b19d16SEric W. Biederman 49699b19d16SEric W. Biederman static void restore_mounts(struct list_head *to_restore) 49799b19d16SEric W. Biederman { 49899b19d16SEric W. Biederman /* Restore mounts to a clean working state */ 49999b19d16SEric W. Biederman while (!list_empty(to_restore)) { 500570487d3SEric W. Biederman struct mount *mnt, *parent; 501570487d3SEric W. Biederman struct mountpoint *mp; 502570487d3SEric W. Biederman 50399b19d16SEric W. Biederman mnt = list_first_entry(to_restore, struct mount, mnt_umounting); 50499b19d16SEric W. Biederman CLEAR_MNT_MARK(mnt); 50599b19d16SEric W. Biederman list_del_init(&mnt->mnt_umounting); 506570487d3SEric W. Biederman 50799b19d16SEric W. Biederman /* Should this mount be reparented? */ 508570487d3SEric W. Biederman mp = mnt->mnt_mp; 509570487d3SEric W. Biederman parent = mnt->mnt_parent; 510570487d3SEric W. Biederman while (parent->mnt.mnt_flags & MNT_UMOUNT) { 511570487d3SEric W. Biederman mp = parent->mnt_mp; 512570487d3SEric W. Biederman parent = parent->mnt_parent; 513570487d3SEric W. Biederman } 51499b19d16SEric W. Biederman if (parent != mnt->mnt_parent) 515570487d3SEric W. Biederman mnt_change_mountpoint(parent, mp, mnt); 516570487d3SEric W. Biederman } 517570487d3SEric W. Biederman } 518570487d3SEric W. Biederman 519296990deSEric W. Biederman static void cleanup_umount_visitations(struct list_head *visited) 520296990deSEric W. Biederman { 521296990deSEric W. Biederman while (!list_empty(visited)) { 522296990deSEric W. Biederman struct mount *mnt = 523296990deSEric W. Biederman list_first_entry(visited, struct mount, mnt_umounting); 524296990deSEric W. Biederman list_del_init(&mnt->mnt_umounting); 525296990deSEric W. Biederman } 526296990deSEric W. Biederman } 527296990deSEric W. Biederman 528a05964f3SRam Pai /* 529a05964f3SRam Pai * collect all mounts that receive propagation from the mount in @list, 530a05964f3SRam Pai * and return these additional mounts in the same list. 531a05964f3SRam Pai * @list: the list of mounts to be unmounted. 53299b7db7bSNick Piggin * 53399b7db7bSNick Piggin * vfsmount lock must be held for write 534a05964f3SRam Pai */ 535c003b26fSEric W. Biederman int propagate_umount(struct list_head *list) 536a05964f3SRam Pai { 53761ef47b1SAl Viro struct mount *mnt; 53899b19d16SEric W. Biederman LIST_HEAD(to_restore); 53999b19d16SEric W. Biederman LIST_HEAD(to_umount); 540296990deSEric W. Biederman LIST_HEAD(visited); 541a05964f3SRam Pai 542296990deSEric W. Biederman /* Find candidates for unmounting */ 543296990deSEric W. Biederman list_for_each_entry_reverse(mnt, list, mnt_list) { 54499b19d16SEric W. Biederman struct mount *parent = mnt->mnt_parent; 54599b19d16SEric W. Biederman struct mount *m; 5460c56fe31SEric W. Biederman 547296990deSEric W. Biederman /* 548296990deSEric W. Biederman * If this mount has already been visited it is known that it's 549296990deSEric W. Biederman * entire peer group and all of their slaves in the propagation 550296990deSEric W. Biederman * tree for the mountpoint has already been visited and there is 551296990deSEric W. Biederman * no need to visit them again. 552296990deSEric W. Biederman */ 553296990deSEric W. Biederman if (!list_empty(&mnt->mnt_umounting)) 554296990deSEric W. Biederman continue; 555296990deSEric W. Biederman 556296990deSEric W. Biederman list_add_tail(&mnt->mnt_umounting, &visited); 55799b19d16SEric W. Biederman for (m = propagation_next(parent, parent); m; 55899b19d16SEric W. Biederman m = propagation_next(m, parent)) { 55999b19d16SEric W. Biederman struct mount *child = __lookup_mnt(&m->mnt, 56099b19d16SEric W. Biederman mnt->mnt_mountpoint); 56199b19d16SEric W. Biederman if (!child) 56299b19d16SEric W. Biederman continue; 563570487d3SEric W. Biederman 564296990deSEric W. Biederman if (!list_empty(&child->mnt_umounting)) { 565296990deSEric W. Biederman /* 566296990deSEric W. Biederman * If the child has already been visited it is 567296990deSEric W. Biederman * know that it's entire peer group and all of 568296990deSEric W. Biederman * their slaves in the propgation tree for the 569296990deSEric W. Biederman * mountpoint has already been visited and there 570296990deSEric W. Biederman * is no need to visit this subtree again. 571296990deSEric W. Biederman */ 572296990deSEric W. Biederman m = skip_propagation_subtree(m, parent); 573296990deSEric W. Biederman continue; 574296990deSEric W. Biederman } else if (child->mnt.mnt_flags & MNT_UMOUNT) { 575296990deSEric W. Biederman /* 576296990deSEric W. Biederman * We have come accross an partially unmounted 577296990deSEric W. Biederman * mount in list that has not been visited yet. 578296990deSEric W. Biederman * Remember it has been visited and continue 579296990deSEric W. Biederman * about our merry way. 580296990deSEric W. Biederman */ 581296990deSEric W. Biederman list_add_tail(&child->mnt_umounting, &visited); 582296990deSEric W. Biederman continue; 583296990deSEric W. Biederman } 584296990deSEric W. Biederman 58599b19d16SEric W. Biederman /* Check the child and parents while progress is made */ 58699b19d16SEric W. Biederman while (__propagate_umount(child, 58799b19d16SEric W. Biederman &to_umount, &to_restore)) { 58899b19d16SEric W. Biederman /* Is the parent a umount candidate? */ 58999b19d16SEric W. Biederman child = child->mnt_parent; 59099b19d16SEric W. Biederman if (list_empty(&child->mnt_umounting)) 59199b19d16SEric W. Biederman break; 59299b19d16SEric W. Biederman } 59399b19d16SEric W. Biederman } 59499b19d16SEric W. Biederman } 59599b19d16SEric W. Biederman 59699b19d16SEric W. Biederman umount_list(&to_umount, &to_restore); 59799b19d16SEric W. Biederman restore_mounts(&to_restore); 598296990deSEric W. Biederman cleanup_umount_visitations(&visited); 59999b19d16SEric W. Biederman list_splice_tail(&to_umount, list); 600570487d3SEric W. Biederman 601a05964f3SRam Pai return 0; 602a05964f3SRam Pai } 603