From: Al Viro Date: Sat, 26 Apr 2025 02:34:33 +0000 (-0400) Subject: make commit_tree() usable in same-namespace move case X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7c6fb47b2b6c1ffcb1cae9372b9fcf269444487a;p=thirdparty%2Fkernel%2Fstable.git make commit_tree() usable in same-namespace move case Once attach_recursive_mnt() has created all copies of original subtree, it needs to put them in place(s). Steps needed for those are slightly different: 1) in 'move' case, original copy doesn't need any rbtree manipulations (everything's already in the same namespace where it will be), but it needs to be detached from the current location 2) in 'attach' case, original may be in anon namespace; if it is, all those mounts need to removed from their current namespace before insertion into the target one 3) additional copies have a couple of extra twists - in case of cross-userns propagation we need to lock everything other the root of subtree and in case when we end up inserting under an existing mount, that mount needs to be found (for original copy we have it explicitly passed by the caller). Quite a bit of that can be unified; as the first step, make commit_tree() helper (inserting mounts into namespace, hashing the root of subtree and marking the namespace as updated) usable in all cases; (2) and (3) are already using it and for (1) we only need to make the insertion of mounts into namespace conditional. Signed-off-by: Al Viro --- diff --git a/fs/namespace.c b/fs/namespace.c index f64895d47d705..937c2a1825f2f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1172,15 +1172,17 @@ static void commit_tree(struct mount *mnt) BUG_ON(parent == mnt); - list_add_tail(&head, &mnt->mnt_list); - while (!list_empty(&head)) { - m = list_first_entry(&head, typeof(*m), mnt_list); - list_del(&m->mnt_list); + if (!mnt_ns_attached(mnt)) { + list_add_tail(&head, &mnt->mnt_list); + while (!list_empty(&head)) { + m = list_first_entry(&head, typeof(*m), mnt_list); + list_del(&m->mnt_list); - mnt_add_to_ns(n, m); + mnt_add_to_ns(n, m); + } + n->nr_mounts += n->pending_mounts; + n->pending_mounts = 0; } - n->nr_mounts += n->pending_mounts; - n->pending_mounts = 0; make_visible(mnt); touch_mnt_namespace(n); @@ -2691,12 +2693,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, if (moving) { unhash_mnt(source_mnt); - mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); - if (beneath) - mnt_change_mountpoint(top, smp, top_mnt); - make_visible(source_mnt); mnt_notify_add(source_mnt); - touch_mnt_namespace(source_mnt->mnt_ns); } else { if (source_mnt->mnt_ns) { LIST_HEAD(head); @@ -2706,12 +2703,13 @@ static int attach_recursive_mnt(struct mount *source_mnt, move_from_ns(p, &head); list_del_init(&head); } - mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); - if (beneath) - mnt_change_mountpoint(top, smp, top_mnt); - commit_tree(source_mnt); } + mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); + if (beneath) + mnt_change_mountpoint(top, smp, top_mnt); + commit_tree(source_mnt); + hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) { struct mount *q; hlist_del_init(&child->mnt_hash);