]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nstree: add unified namespace list
authorChristian Brauner <brauner@kernel.org>
Wed, 29 Oct 2025 12:20:31 +0000 (13:20 +0100)
committerChristian Brauner <brauner@kernel.org>
Mon, 3 Nov 2025 16:41:18 +0000 (17:41 +0100)
Allow to walk the unified namespace list completely locklessly.

Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-18-2e6f823ebdc0@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
include/linux/ns_common.h
kernel/nscommon.c
kernel/nstree.c

index 698aa2f7f4867345c68ef7bed38d3d750f1a95c6..3f05dd7d40c783c7dddc0cc3d2147d494e6c629a 100644 (file)
@@ -111,6 +111,7 @@ struct ns_common {
                        u64 ns_id;
                        struct /* global namespace rbtree and list */ {
                                struct rb_node ns_unified_tree_node;
+                               struct list_head ns_unified_list_node;
                        };
                        struct /* per type rbtree and list */ {
                                struct rb_node ns_tree_node;
@@ -224,6 +225,7 @@ static __always_inline bool is_initial_namespace(struct ns_common *ns)
        .ns_list_node           = LIST_HEAD_INIT(nsname.ns.ns_list_node),               \
        .ns_owner_entry         = LIST_HEAD_INIT(nsname.ns.ns_owner_entry),             \
        .ns_owner               = LIST_HEAD_INIT(nsname.ns.ns_owner),                   \
+       .ns_unified_list_node   = LIST_HEAD_INIT(nsname.ns.ns_unified_list_node),       \
 }
 
 #define ns_common_init(__ns)                     \
index f0b7971392d2ed3434cc99318d5f35224cb5fbbb..4cbe1ecc8df06cdc9e5c27f33e8919649b713681 100644 (file)
@@ -65,6 +65,7 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
        RB_CLEAR_NODE(&ns->ns_unified_tree_node);
        RB_CLEAR_NODE(&ns->ns_owner_tree_node);
        INIT_LIST_HEAD(&ns->ns_list_node);
+       INIT_LIST_HEAD(&ns->ns_unified_list_node);
        ns->ns_owner_tree = RB_ROOT;
        INIT_LIST_HEAD(&ns->ns_owner);
        INIT_LIST_HEAD(&ns->ns_owner_entry);
index 419d500d09dfd2940e9c35da142fc817c9d22fe7..dcad6a308547f90195364cde3928884ffea8df82 100644 (file)
@@ -9,6 +9,7 @@
 
 static __cacheline_aligned_in_smp DEFINE_SEQLOCK(ns_tree_lock);
 static struct rb_root ns_unified_tree = RB_ROOT; /* protected by ns_tree_lock */
+static LIST_HEAD(ns_unified_list); /* protected by ns_tree_lock */
 
 /**
  * struct ns_tree - Namespace tree
@@ -137,7 +138,13 @@ void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree *ns_tree)
        else
                list_add_rcu(&ns->ns_list_node, &node_to_ns(prev)->ns_list_node);
 
+       /* Add to unified tree and list */
        rb_find_add_rcu(&ns->ns_unified_tree_node, &ns_unified_tree, ns_cmp_unified);
+       prev = rb_prev(&ns->ns_unified_tree_node);
+       if (!prev)
+               list_add_rcu(&ns->ns_unified_list_node, &ns_unified_list);
+       else
+               list_add_rcu(&ns->ns_unified_list_node, &node_to_ns_unified(prev)->ns_unified_list_node);
 
        if (ops) {
                struct user_namespace *user_ns;
@@ -186,11 +193,15 @@ void __ns_tree_remove(struct ns_common *ns, struct ns_tree *ns_tree)
 
        write_seqlock(&ns_tree_lock);
        rb_erase(&ns->ns_tree_node, &ns_tree->ns_tree);
-       rb_erase(&ns->ns_unified_tree_node, &ns_unified_tree);
        RB_CLEAR_NODE(&ns->ns_tree_node);
 
        list_bidir_del_rcu(&ns->ns_list_node);
 
+       rb_erase(&ns->ns_unified_tree_node, &ns_unified_tree);
+       RB_CLEAR_NODE(&ns->ns_unified_tree_node);
+
+       list_bidir_del_rcu(&ns->ns_unified_list_node);
+
        /* Remove from owner's rbtree if this namespace has an owner */
        if (ops) {
                user_ns = ops->owner(ns);