]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nstree: add helper to operate on struct ns_tree_{node,root}
authorChristian Brauner <brauner@kernel.org>
Mon, 10 Nov 2025 15:08:16 +0000 (16:08 +0100)
committerChristian Brauner <brauner@kernel.org>
Tue, 11 Nov 2025 09:01:30 +0000 (10:01 +0100)
Add helpers that work on the combined rbtree and rculist combined.
This will make the code a lot more managable and legible.

Link: https://patch.msgid.link/20251110-work-namespace-nstree-fixes-v1-4-e8a9264e0fb9@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
include/linux/nstree.h
kernel/nstree.c

index 0e275df7e99a031db398abb078be0c6e19178928..98b848cf2f1ce77d160d2775d1952a18a292cdad 100644 (file)
@@ -22,6 +22,14 @@ extern struct ns_tree time_ns_tree;
 extern struct ns_tree user_ns_tree;
 extern struct ns_tree uts_ns_tree;
 
+void ns_tree_node_init(struct ns_tree_node *node);
+void ns_tree_root_init(struct ns_tree_root *root);
+bool ns_tree_node_empty(const struct ns_tree_node *node);
+struct rb_node *ns_tree_node_add(struct ns_tree_node *node,
+                                 struct ns_tree_root *root,
+                                 int (*cmp)(struct rb_node *, const struct rb_node *));
+void ns_tree_node_del(struct ns_tree_node *node, struct ns_tree_root *root);
+
 #define to_ns_tree(__ns)                                       \
        _Generic((__ns),                                        \
                struct cgroup_namespace *: &(cgroup_ns_tree),   \
index 97404fb90749dba783d206bf5477bf7f1c2b1cc3..fe71ff943f703a55190e7b20a817135d4a6b85e8 100644 (file)
@@ -73,6 +73,91 @@ struct ns_tree time_ns_tree = {
        .type = CLONE_NEWTIME,
 };
 
+/**
+ * ns_tree_node_init - Initialize a namespace tree node
+ * @node: The node to initialize
+ *
+ * Initializes both the rbtree node and list entry.
+ */
+void ns_tree_node_init(struct ns_tree_node *node)
+{
+       RB_CLEAR_NODE(&node->ns_node);
+       INIT_LIST_HEAD(&node->ns_list_entry);
+}
+
+/**
+ * ns_tree_root_init - Initialize a namespace tree root
+ * @root: The root to initialize
+ *
+ * Initializes both the rbtree root and list head.
+ */
+void ns_tree_root_init(struct ns_tree_root *root)
+{
+       root->ns_rb = RB_ROOT;
+       INIT_LIST_HEAD(&root->ns_list_head);
+}
+
+/**
+ * ns_tree_node_empty - Check if a namespace tree node is empty
+ * @node: The node to check
+ *
+ * Returns true if the node is not in any tree.
+ */
+bool ns_tree_node_empty(const struct ns_tree_node *node)
+{
+       return RB_EMPTY_NODE(&node->ns_node);
+}
+
+/**
+ * ns_tree_node_add - Add a node to a namespace tree
+ * @node: The node to add
+ * @root: The tree root to add to
+ * @cmp: Comparison function for rbtree insertion
+ *
+ * Adds the node to both the rbtree and the list, maintaining sorted order.
+ * The list is maintained in the same order as the rbtree to enable efficient
+ * iteration.
+ *
+ * Returns: NULL if insertion succeeded, existing node if duplicate found
+ */
+struct rb_node *ns_tree_node_add(struct ns_tree_node *node,
+                                 struct ns_tree_root *root,
+                                 int (*cmp)(struct rb_node *, const struct rb_node *))
+{
+       struct rb_node *ret, *prev;
+
+       /* Add to rbtree */
+       ret = rb_find_add_rcu(&node->ns_node, &root->ns_rb, cmp);
+
+       /* Add to list in sorted order */
+       prev = rb_prev(&node->ns_node);
+       if (!prev) {
+               /* No previous node, add at head */
+               list_add_rcu(&node->ns_list_entry, &root->ns_list_head);
+       } else {
+               /* Add after previous node */
+               struct ns_tree_node *prev_node;
+               prev_node = rb_entry(prev, struct ns_tree_node, ns_node);
+               list_add_rcu(&node->ns_list_entry, &prev_node->ns_list_entry);
+       }
+
+       return ret;
+}
+
+/**
+ * ns_tree_node_del - Remove a node from a namespace tree
+ * @node: The node to remove
+ * @root: The tree root to remove from
+ *
+ * Removes the node from both the rbtree and the list atomically.
+ */
+void ns_tree_node_del(struct ns_tree_node *node, struct ns_tree_root *root)
+{
+       rb_erase(&node->ns_node, &root->ns_rb);
+       RB_CLEAR_NODE(&node->ns_node);
+       list_bidir_del_rcu(&node->ns_list_entry);
+}
+
 static inline struct ns_common *node_to_ns(const struct rb_node *node)
 {
        if (!node)