nstree: add helper to operate on struct ns_tree_{node,root}

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>
This commit is contained in:
Christian Brauner
2025-11-10 16:08:16 +01:00
parent 1c64fb02ac
commit d12ea8062f
2 changed files with 93 additions and 0 deletions

View 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), \

View 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)