]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
copy_tree(): don't link the mounts via mnt_list
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 18 Jun 2025 01:35:22 +0000 (21:35 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 29 Jun 2025 23:03:37 +0000 (19:03 -0400)
The only place that really needs to be adjusted is commit_tree() -
there we need to iterate through the copy and we might as well
use next_mnt() for that.  However, in case when our tree has been
slid under something already mounted (propagation to a mountpoint
that already has something mounted on it or a 'beneath' move_mount)
we need to take care not to walk into the overmounting tree.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/mount.h
fs/namespace.c
fs/pnode.c

index 08583428b10b552a95190e82fb35c1c81d0e88e1..97737051a8b9df274413922229339dfd8c8e1b56 100644 (file)
@@ -193,7 +193,7 @@ static inline bool mnt_ns_empty(const struct mnt_namespace *ns)
        return RB_EMPTY_ROOT(&ns->mounts);
 }
 
-static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
+static inline void move_from_ns(struct mount *mnt)
 {
        struct mnt_namespace *ns = mnt->mnt_ns;
        WARN_ON(!mnt_ns_attached(mnt));
@@ -203,7 +203,6 @@ static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
                ns->mnt_first_node = rb_next(&mnt->mnt_node);
        rb_erase(&mnt->mnt_node, &ns->mounts);
        RB_CLEAR_NODE(&mnt->mnt_node);
-       list_add_tail(&mnt->mnt_list, dt_list);
 }
 
 bool has_locked_children(struct mount *mnt, struct dentry *dentry);
index 38a46b32413d02c186ae0b7398c9c6555910b53a..bd6c7da901fcab2a6ba7140ce266bbddedf41d0b 100644 (file)
@@ -1161,34 +1161,6 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
        mnt_notify_add(mnt);
 }
 
-/*
- * vfsmount lock must be held for write
- */
-static void commit_tree(struct mount *mnt)
-{
-       struct mount *parent = mnt->mnt_parent;
-       struct mount *m;
-       LIST_HEAD(head);
-       struct mnt_namespace *n = parent->mnt_ns;
-
-       BUG_ON(parent == mnt);
-
-       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);
-               }
-               n->nr_mounts += n->pending_mounts;
-               n->pending_mounts = 0;
-       }
-
-       make_visible(mnt);
-       touch_mnt_namespace(n);
-}
-
 static struct mount *next_mnt(struct mount *p, struct mount *root)
 {
        struct list_head *next = p->mnt_mounts.next;
@@ -1215,6 +1187,27 @@ static struct mount *skip_mnt_tree(struct mount *p)
        return p;
 }
 
+/*
+ * vfsmount lock must be held for write
+ */
+static void commit_tree(struct mount *mnt)
+{
+       struct mnt_namespace *n = mnt->mnt_parent->mnt_ns;
+
+       if (!mnt_ns_attached(mnt)) {
+               for (struct mount *m = mnt; m; m = next_mnt(m, mnt))
+                       if (unlikely(mnt_ns_attached(m)))
+                               m = skip_mnt_tree(m);
+                       else
+                               mnt_add_to_ns(n, m);
+               n->nr_mounts += n->pending_mounts;
+               n->pending_mounts = 0;
+       }
+
+       make_visible(mnt);
+       touch_mnt_namespace(n);
+}
+
 /**
  * vfs_create_mount - Create a mount for a configured superblock
  * @fc: The configuration context with the superblock attached
@@ -1831,9 +1824,8 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
        for (p = mnt; p; p = next_mnt(p, mnt)) {
                p->mnt.mnt_flags |= MNT_UMOUNT;
                if (mnt_ns_attached(p))
-                       move_from_ns(p, &tmp_list);
-               else
-                       list_move(&p->mnt_list, &tmp_list);
+                       move_from_ns(p);
+               list_add_tail(&p->mnt_list, &tmp_list);
        }
 
        /* Hide the mounts from mnt_mounts */
@@ -2270,7 +2262,6 @@ struct mount *copy_tree(struct mount *src_root, struct dentry *dentry,
                                        list_add(&dst_mnt->mnt_expire,
                                                 &src_mnt->mnt_expire);
                        }
-                       list_add_tail(&dst_mnt->mnt_list, &res->mnt_list);
                        attach_mnt(dst_mnt, dst_parent, src_parent->mnt_mp);
                        unlock_mount_hash();
                }
@@ -2686,12 +2677,9 @@ static int attach_recursive_mnt(struct mount *source_mnt,
                list_del_init(&source_mnt->mnt_expire);
        } else {
                if (source_mnt->mnt_ns) {
-                       LIST_HEAD(head);
-
                        /* move from anon - the caller will destroy */
                        for (p = source_mnt; p; p = next_mnt(p, source_mnt))
-                               move_from_ns(p, &head);
-                       list_del_init(&head);
+                               move_from_ns(p);
                }
        }
 
index cbf5f5746252d625d4430d058d3b50e3e54cc062..81f7599bdac4fcf14ebbde8dfaa5ef872b5ac56b 100644 (file)
@@ -449,7 +449,8 @@ static void umount_one(struct mount *m, struct list_head *to_umount)
 {
        m->mnt.mnt_flags |= MNT_UMOUNT;
        list_del_init(&m->mnt_child);
-       move_from_ns(m, to_umount);
+       move_from_ns(m);
+       list_add_tail(&m->mnt_list, to_umount);
 }
 
 static void remove_from_candidate_list(struct mount *m)