summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2025-04-25 22:40:48 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2025-06-29 18:13:41 -0400
commit96f5d2e051653f2cfe9137c5d3c7794c358ffb03 (patch)
treefaf8e6e42038ccbbe43bdb48dee728d656ad5921
parent7c6fb47b2b6c1ffcb1cae9372b9fcf269444487a (diff)
attach_recursive_mnt(): unify the mnt_change_mountpoint() logics
The logics used for tucking under existing mount differs for original and copies; copies do a mount hash lookup to see if mountpoint to be is already overmounted, while the original is told explicitly. But the same logics that is used for copies works for the original, at which point the only place where we get very close to eliminating the need of passing 'beneath' flag to attach_recursive_mnt(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namespace.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 937c2a1825f2..9b8d07df4aa5 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2643,7 +2643,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
HLIST_HEAD(tree_list);
struct mnt_namespace *ns = top_mnt->mnt_ns;
struct mountpoint *smp;
- struct mountpoint *secondary = NULL;
+ struct mountpoint *shorter = NULL;
struct mount *child, *dest_mnt, *p;
struct mount *top;
struct hlist_node *n;
@@ -2655,14 +2655,12 @@ static int attach_recursive_mnt(struct mount *source_mnt,
* mounted beneath mounts on the same mountpoint.
*/
for (top = source_mnt; unlikely(top->overmount); top = top->overmount) {
- if (!secondary && is_mnt_ns_file(top->mnt.mnt_root))
- secondary = top->mnt_mp;
+ if (!shorter && is_mnt_ns_file(top->mnt.mnt_root))
+ shorter = top->mnt_mp;
}
smp = get_mountpoint(top->mnt.mnt_root);
if (IS_ERR(smp))
return PTR_ERR(smp);
- if (!secondary)
- secondary = smp;
/* Is there space to add these mounts to the mount namespace? */
if (!moving) {
@@ -2706,9 +2704,14 @@ static int attach_recursive_mnt(struct mount *source_mnt,
}
mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt);
- if (beneath)
- mnt_change_mountpoint(top, smp, top_mnt);
- commit_tree(source_mnt);
+ /*
+ * Now the original copy is in the same state as the secondaries -
+ * its root attached to mountpoint, but not hashed and all mounts
+ * in it are either in our namespace or in no namespace at all.
+ * Add the original to the list of copies and deal with the
+ * rest of work for all of them uniformly.
+ */
+ hlist_add_head(&source_mnt->mnt_hash, &tree_list);
hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) {
struct mount *q;
@@ -2719,10 +2722,13 @@ static int attach_recursive_mnt(struct mount *source_mnt,
q = __lookup_mnt(&child->mnt_parent->mnt,
child->mnt_mountpoint);
if (q) {
+ struct mountpoint *mp = smp;
struct mount *r = child;
while (unlikely(r->overmount))
r = r->overmount;
- mnt_change_mountpoint(r, secondary, q);
+ if (unlikely(shorter) && child != source_mnt)
+ mp = shorter;
+ mnt_change_mountpoint(r, mp, q);
}
commit_tree(child);
}