umount_tree builds a list of mounts that need to be unmounted. Utilize mnt_list for this purpose instead of mnt_hash as mnt_list is an ordianry list_head, allowing the use of list_splice and list_move instead of rolling our own. This also begins to allow keeping a mount on the mnt_hash after it is unmounted. Which is necessary for a properly functioning MNT_LOCKED implementation. Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> --- fs/namespace.c | 45 +++++++++++++++++++-------------------------- fs/pnode.c | 6 +++--- fs/pnode.h | 2 +- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 07d0562290a5..44478b6e3719 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1285,23 +1285,22 @@ int may_umount(struct vfsmount *mnt) EXPORT_SYMBOL(may_umount); -static HLIST_HEAD(unmounted); /* protected by namespace_sem */ +static LIST_HEAD(unmounted); /* protected by namespace_sem */ static void namespace_unlock(void) { struct mount *mnt; - struct hlist_head head = unmounted; + LIST_HEAD(head); - if (likely(hlist_empty(&head))) { + if (likely(list_empty(&unmounted))) { up_write(&namespace_sem); return; } - head.first->pprev = &head.first; - INIT_HLIST_HEAD(&unmounted); + list_splice_init(&unmounted, &head); /* undo decrements we'd done in umount_tree() */ - hlist_for_each_entry(mnt, &head, mnt_hash) + list_for_each_entry(mnt, &head, mnt_list) if (mnt->mnt_ex_mountpoint.mnt) mntget(mnt->mnt_ex_mountpoint.mnt); @@ -1309,9 +1308,9 @@ static void namespace_unlock(void) synchronize_rcu(); - while (!hlist_empty(&head)) { - mnt = hlist_entry(head.first, struct mount, mnt_hash); - hlist_del_init(&mnt->mnt_hash); + while (!list_empty(&head)) { + mnt = list_first_entry(&head, struct mount, mnt_list); + list_del_init(&mnt->mnt_list); if (mnt->mnt_ex_mountpoint.mnt) path_put(&mnt->mnt_ex_mountpoint); mntput(&mnt->mnt); @@ -1333,24 +1332,25 @@ enum umount_tree_flags { */ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) { - HLIST_HEAD(tmp_list); + LIST_HEAD(tmp_list); struct mount *p; - struct mount *last = NULL; - for (p = mnt; p; p = next_mnt(p, mnt)) { - hlist_del_init_rcu(&p->mnt_hash); - hlist_add_head(&p->mnt_hash, &tmp_list); - } + /* Gather the mounts to umount */ + for (p = mnt; p; p = next_mnt(p, mnt)) + list_move(&p->mnt_list, &tmp_list); - hlist_for_each_entry(p, &tmp_list, mnt_hash) + /* Hide the mounts from lookup_mnt and mnt_mounts */ + list_for_each_entry(p, &tmp_list, mnt_list) { + hlist_del_init_rcu(&p->mnt_hash); list_del_init(&p->mnt_child); + } + /* Add propogated mounts to the tmp_list */ if (how & UMOUNT_PROPAGATE) propagate_umount(&tmp_list); - hlist_for_each_entry(p, &tmp_list, mnt_hash) { + list_for_each_entry(p, &tmp_list, mnt_list) { list_del_init(&p->mnt_expire); - list_del_init(&p->mnt_list); __touch_mnt_namespace(p->mnt_ns); p->mnt_ns = NULL; if (how & UMOUNT_SYNC) @@ -1367,15 +1367,8 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) p->mnt_mp = NULL; } change_mnt_propagation(p, MS_PRIVATE); - last = p; - } - if (last) { - last->mnt_hash.next = unmounted.first; - if (unmounted.first) - unmounted.first->pprev = &last->mnt_hash.next; - unmounted.first = tmp_list.first; - unmounted.first->pprev = &unmounted.first; } + list_splice(&tmp_list, &unmounted); } static void shrink_submounts(struct mount *mnt); diff --git a/fs/pnode.c b/fs/pnode.c index 260ac8f898a4..bf012af709dd 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -384,7 +384,7 @@ static void __propagate_umount(struct mount *mnt) if (child && list_empty(&child->mnt_mounts)) { list_del_init(&child->mnt_child); hlist_del_init_rcu(&child->mnt_hash); - hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash); + list_move_tail(&child->mnt_list, &mnt->mnt_list); } } } @@ -396,11 +396,11 @@ static void __propagate_umount(struct mount *mnt) * * vfsmount lock must be held for write */ -int propagate_umount(struct hlist_head *list) +int propagate_umount(struct list_head *list) { struct mount *mnt; - hlist_for_each_entry(mnt, list, mnt_hash) + list_for_each_entry(mnt, list, mnt_list) __propagate_umount(mnt); return 0; } diff --git a/fs/pnode.h b/fs/pnode.h index 16afc3d6d2f2..aa6d65df7204 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -40,7 +40,7 @@ static inline void set_mnt_shared(struct mount *mnt) void change_mnt_propagation(struct mount *, int); int propagate_mnt(struct mount *, struct mountpoint *, struct mount *, struct hlist_head *); -int propagate_umount(struct hlist_head *); +int propagate_umount(struct list_head *); int propagate_mount_busy(struct mount *, int); void mnt_release_group_id(struct mount *); int get_dominating_id(struct mount *mnt, const struct path *root); -- 2.2.1 _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linuxfoundation.org/mailman/listinfo/containers