]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
namespace: record fully visible mounts in list
authorChristian Brauner <brauner@kernel.org>
Mon, 27 Apr 2026 08:26:02 +0000 (10:26 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 11 May 2026 21:13:01 +0000 (23:13 +0200)
Instead of wading through all the mounts in the mount namespace rbtree
to find fully visible procfs and sysfs mounts, be honest about them
being special cruft and record them in a separate per-mount namespace
list.

Link: https://patch.msgid.link/684859a8e0ac929cb89c1fbe16ce15b30c70eb1f.1777278334.git.legion@kernel.org
Reviewed-by: Aleksa Sarai <aleksa@amutable.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/mount.h
fs/namespace.c

index e0816c11a1989fdd2aa1c31056032e9e46e3e528..5df134d56d475f6336cb968224a4c893d8469606 100644 (file)
@@ -25,6 +25,7 @@ struct mnt_namespace {
        __u32                   n_fsnotify_mask;
        struct fsnotify_mark_connector __rcu *n_fsnotify_marks;
 #endif
+       struct hlist_head       mnt_visible_mounts; /* SB_I_USERNS_VISIBLE mounts */
        unsigned int            nr_mounts; /* # of mounts in the namespace */
        unsigned int            pending_mounts;
        refcount_t              passive; /* number references not pinning @mounts */
@@ -90,6 +91,7 @@ struct mount {
        int mnt_expiry_mark;            /* true if marked for expiry */
        struct hlist_head mnt_pins;
        struct hlist_head mnt_stuck_children;
+       struct hlist_node mnt_ns_visible; /* link in ns->mnt_visible_mounts */
        struct mount *overmount;        /* mounted on ->mnt_root */
 } __randomize_layout;
 
@@ -207,6 +209,8 @@ static inline void move_from_ns(struct mount *mnt)
                ns->mnt_first_node = rb_next(&mnt->mnt_node);
        rb_erase(&mnt->mnt_node, &ns->mounts);
        RB_CLEAR_NODE(&mnt->mnt_node);
+       if (!hlist_unhashed(&mnt->mnt_ns_visible))
+               hlist_del_init(&mnt->mnt_ns_visible);
 }
 
 bool has_locked_children(struct mount *mnt, struct dentry *dentry);
index fe919abd2f0118594a4ab7e593648c7c629a6544..047efa737ef92f7662cce4547f837343f75c39b4 100644 (file)
@@ -321,6 +321,7 @@ static struct mount *alloc_vfsmnt(const char *name)
                INIT_HLIST_NODE(&mnt->mnt_slave);
                INIT_HLIST_NODE(&mnt->mnt_mp_list);
                INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
+               INIT_HLIST_NODE(&mnt->mnt_ns_visible);
                RB_CLEAR_NODE(&mnt->mnt_node);
                mnt->mnt.mnt_idmap = &nop_mnt_idmap;
        }
@@ -1098,6 +1099,10 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
        rb_link_node(&mnt->mnt_node, parent, link);
        rb_insert_color(&mnt->mnt_node, &ns->mounts);
 
+       if ((mnt->mnt.mnt_sb->s_iflags & SB_I_USERNS_VISIBLE) &&
+           mnt->mnt.mnt_root == mnt->mnt.mnt_sb->s_root)
+               hlist_add_head(&mnt->mnt_ns_visible, &ns->mnt_visible_mounts);
+
        mnt_notify_add(mnt);
 }
 
@@ -6340,22 +6345,20 @@ static bool mnt_already_visible(struct mnt_namespace *ns,
                                int *new_mnt_flags)
 {
        int new_flags = *new_mnt_flags;
-       struct mount *mnt, *n;
+       struct mount *mnt;
+
+       /* Don't acquire namespace semaphore without a good reason. */
+       if (hlist_empty(&ns->mnt_visible_mounts))
+               return false;
 
        guard(namespace_shared)();
-       rbtree_postorder_for_each_entry_safe(mnt, n, &ns->mounts, mnt_node) {
+       hlist_for_each_entry(mnt, &ns->mnt_visible_mounts, mnt_ns_visible) {
                struct mount *child;
                int mnt_flags;
 
                if (mnt->mnt.mnt_sb->s_type != sb->s_type)
                        continue;
 
-               /* This mount is not fully visible if it's root directory
-                * is not the root directory of the filesystem.
-                */
-               if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
-                       continue;
-
                /* A local view of the mount flags */
                mnt_flags = mnt->mnt.mnt_flags;