xref: /linux/tools/testing/selftests/bpf/libarena/src/rbtree.bpf.c (revision 6c3e8a4d476521bc33362e90b2569548f1adb7a4)
1*6c3e8a4dSEmil Tsalapatis // SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
2*6c3e8a4dSEmil Tsalapatis /*
3*6c3e8a4dSEmil Tsalapatis  * Copyright (c) 2025-2026 Meta Platforms, Inc. and affiliates.
4*6c3e8a4dSEmil Tsalapatis  * Copyright (c) 2025-2026 Emil Tsalapatis <emil@etsalapatis.com>
5*6c3e8a4dSEmil Tsalapatis  */
6*6c3e8a4dSEmil Tsalapatis 
7*6c3e8a4dSEmil Tsalapatis #include <libarena/common.h>
8*6c3e8a4dSEmil Tsalapatis 
9*6c3e8a4dSEmil Tsalapatis #include <libarena/asan.h>
10*6c3e8a4dSEmil Tsalapatis #include <libarena/rbtree.h>
11*6c3e8a4dSEmil Tsalapatis 
12*6c3e8a4dSEmil Tsalapatis int rb_integrity_check(struct rbtree __arena *rbtree);
13*6c3e8a4dSEmil Tsalapatis void rbnode_print(size_t depth, struct rbnode __arena *rbn);
14*6c3e8a4dSEmil Tsalapatis static int rbnode_replace(struct rbtree __arena *rbtree,
15*6c3e8a4dSEmil Tsalapatis 			  struct rbnode __arena *existing,
16*6c3e8a4dSEmil Tsalapatis 			  struct rbnode __arena *replacement);
17*6c3e8a4dSEmil Tsalapatis 
18*6c3e8a4dSEmil Tsalapatis struct rbtree __arena *rb_create(enum rbtree_alloc alloc,
19*6c3e8a4dSEmil Tsalapatis 				 enum rbtree_insert_mode insert)
20*6c3e8a4dSEmil Tsalapatis {
21*6c3e8a4dSEmil Tsalapatis 	struct rbtree __arena *rbtree;
22*6c3e8a4dSEmil Tsalapatis 
23*6c3e8a4dSEmil Tsalapatis 	rbtree = arena_malloc(sizeof(*rbtree));
24*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
25*6c3e8a4dSEmil Tsalapatis 		return NULL;
26*6c3e8a4dSEmil Tsalapatis 
27*6c3e8a4dSEmil Tsalapatis 	/*
28*6c3e8a4dSEmil Tsalapatis 	 * RB_UPDATE overwrites existing values in the nodes, but RB_NOALLOC
29*6c3e8a4dSEmil Tsalapatis 	 * trees manage the tree nodes directly (including holding pointers
30*6c3e8a4dSEmil Tsalapatis 	 * to them). Disallow mixing the two modes to avoid dealing with
31*6c3e8a4dSEmil Tsalapatis 	 * unintuitive semantics.
32*6c3e8a4dSEmil Tsalapatis 	 */
33*6c3e8a4dSEmil Tsalapatis 	if (alloc == RB_NOALLOC && insert == RB_UPDATE) {
34*6c3e8a4dSEmil Tsalapatis 		arena_stderr("WARNING: Cannot combine RB_NOALLOC and RB_UPDATE");
35*6c3e8a4dSEmil Tsalapatis 		arena_free(rbtree);
36*6c3e8a4dSEmil Tsalapatis 		return NULL;
37*6c3e8a4dSEmil Tsalapatis 	}
38*6c3e8a4dSEmil Tsalapatis 
39*6c3e8a4dSEmil Tsalapatis 	rbtree->alloc = alloc;
40*6c3e8a4dSEmil Tsalapatis 	rbtree->insert = insert;
41*6c3e8a4dSEmil Tsalapatis 	rbtree->root = NULL;
42*6c3e8a4dSEmil Tsalapatis 
43*6c3e8a4dSEmil Tsalapatis 	return rbtree;
44*6c3e8a4dSEmil Tsalapatis }
45*6c3e8a4dSEmil Tsalapatis 
46*6c3e8a4dSEmil Tsalapatis __weak
47*6c3e8a4dSEmil Tsalapatis int rb_destroy(struct rbtree __arena *rbtree)
48*6c3e8a4dSEmil Tsalapatis {
49*6c3e8a4dSEmil Tsalapatis 	int ret = 0;
50*6c3e8a4dSEmil Tsalapatis 
51*6c3e8a4dSEmil Tsalapatis 	arena_subprog_init();
52*6c3e8a4dSEmil Tsalapatis 
53*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
54*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
55*6c3e8a4dSEmil Tsalapatis 
56*6c3e8a4dSEmil Tsalapatis 	if (rbtree->alloc == RB_NOALLOC) {
57*6c3e8a4dSEmil Tsalapatis 		/*
58*6c3e8a4dSEmil Tsalapatis 		 * We cannot do anything about RB_NOALLOC nodes. The whole
59*6c3e8a4dSEmil Tsalapatis 		 * point of RB_NOALLOC is that the nodes are directly owned
60*6c3e8a4dSEmil Tsalapatis 		 * by the caller that allocates and inserts them. We could
61*6c3e8a4dSEmil Tsalapatis 		 * unilaterally grab all nodes and free them anyway, but that
62*6c3e8a4dSEmil Tsalapatis 		 * would almost certainly cause UAF as the callers keep accessing
63*6c3e8a4dSEmil Tsalapatis 		 * the now freed nodes. Throw an error instead.
64*6c3e8a4dSEmil Tsalapatis 		 */
65*6c3e8a4dSEmil Tsalapatis 		if (rbtree->root) {
66*6c3e8a4dSEmil Tsalapatis 			arena_stderr("WARNING: Destroying RB_NOALLOC tree with > 0 nodes");
67*6c3e8a4dSEmil Tsalapatis 			return -EBUSY;
68*6c3e8a4dSEmil Tsalapatis 		}
69*6c3e8a4dSEmil Tsalapatis 
70*6c3e8a4dSEmil Tsalapatis 		goto out;
71*6c3e8a4dSEmil Tsalapatis 	}
72*6c3e8a4dSEmil Tsalapatis 
73*6c3e8a4dSEmil Tsalapatis 	while (rbtree->root && can_loop) {
74*6c3e8a4dSEmil Tsalapatis 		ret = rb_remove(rbtree, rbtree->root->key);
75*6c3e8a4dSEmil Tsalapatis 		if (ret)
76*6c3e8a4dSEmil Tsalapatis 			break;
77*6c3e8a4dSEmil Tsalapatis 	}
78*6c3e8a4dSEmil Tsalapatis 
79*6c3e8a4dSEmil Tsalapatis out:
80*6c3e8a4dSEmil Tsalapatis 	arena_free(rbtree);
81*6c3e8a4dSEmil Tsalapatis 	return ret;
82*6c3e8a4dSEmil Tsalapatis }
83*6c3e8a4dSEmil Tsalapatis 
84*6c3e8a4dSEmil Tsalapatis static inline int rbnode_dir(struct rbnode __arena *node)
85*6c3e8a4dSEmil Tsalapatis {
86*6c3e8a4dSEmil Tsalapatis 	/* Arbitrarily choose a direction for the root. */
87*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!node->parent))
88*6c3e8a4dSEmil Tsalapatis 		return 0;
89*6c3e8a4dSEmil Tsalapatis 
90*6c3e8a4dSEmil Tsalapatis 	return (node->parent->left == node) ? 0 : 1;
91*6c3e8a4dSEmil Tsalapatis }
92*6c3e8a4dSEmil Tsalapatis 
93*6c3e8a4dSEmil Tsalapatis /*
94*6c3e8a4dSEmil Tsalapatis  * The __noinline is to prevent inlining from bloating the add
95*6c3e8a4dSEmil Tsalapatis  * remove calls, in turn causing register splits and increasing
96*6c3e8a4dSEmil Tsalapatis  * stack usage above what is permitted.
97*6c3e8a4dSEmil Tsalapatis  */
98*6c3e8a4dSEmil Tsalapatis __noinline
99*6c3e8a4dSEmil Tsalapatis int rbnode_rotate(struct rbtree __arena *rbtree,
100*6c3e8a4dSEmil Tsalapatis 		  struct rbnode __arena *node, int dir)
101*6c3e8a4dSEmil Tsalapatis {
102*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *tmp, *parent;
103*6c3e8a4dSEmil Tsalapatis 	int parentdir;
104*6c3e8a4dSEmil Tsalapatis 
105*6c3e8a4dSEmil Tsalapatis 	parent = node->parent;
106*6c3e8a4dSEmil Tsalapatis 	if (parent)
107*6c3e8a4dSEmil Tsalapatis 		parentdir = rbnode_dir(node);
108*6c3e8a4dSEmil Tsalapatis 
109*6c3e8a4dSEmil Tsalapatis 	/* If we're doing a root change, are we the root? */
110*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!parent && rbtree->root != node))
111*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
112*6c3e8a4dSEmil Tsalapatis 
113*6c3e8a4dSEmil Tsalapatis 	/*
114*6c3e8a4dSEmil Tsalapatis 	 * Does the node we're turning into the root into exist?
115*6c3e8a4dSEmil Tsalapatis 	 * Note that the new root is on the opposite side of the
116*6c3e8a4dSEmil Tsalapatis 	 * rotation's direction.
117*6c3e8a4dSEmil Tsalapatis 	 */
118*6c3e8a4dSEmil Tsalapatis 	tmp = node->child[1 - dir];
119*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!tmp))
120*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
121*6c3e8a4dSEmil Tsalapatis 
122*6c3e8a4dSEmil Tsalapatis 	/* Steal the closest child of the new root. */
123*6c3e8a4dSEmil Tsalapatis 	node->child[1 - dir] = tmp->child[dir];
124*6c3e8a4dSEmil Tsalapatis 	if (node->child[1 - dir])
125*6c3e8a4dSEmil Tsalapatis 		node->child[1 - dir]->parent = node;
126*6c3e8a4dSEmil Tsalapatis 
127*6c3e8a4dSEmil Tsalapatis 	/* Put the node below the new root.*/
128*6c3e8a4dSEmil Tsalapatis 	tmp->child[dir] = node;
129*6c3e8a4dSEmil Tsalapatis 	node->parent = tmp;
130*6c3e8a4dSEmil Tsalapatis 
131*6c3e8a4dSEmil Tsalapatis 	tmp->parent = parent;
132*6c3e8a4dSEmil Tsalapatis 	if (parent)
133*6c3e8a4dSEmil Tsalapatis 		parent->child[parentdir] = tmp;
134*6c3e8a4dSEmil Tsalapatis 	else
135*6c3e8a4dSEmil Tsalapatis 		rbtree->root = tmp;
136*6c3e8a4dSEmil Tsalapatis 
137*6c3e8a4dSEmil Tsalapatis 	return 0;
138*6c3e8a4dSEmil Tsalapatis }
139*6c3e8a4dSEmil Tsalapatis 
140*6c3e8a4dSEmil Tsalapatis static
141*6c3e8a4dSEmil Tsalapatis struct rbnode __arena *rbnode_find(struct rbnode __arena *subtree, u64 key)
142*6c3e8a4dSEmil Tsalapatis {
143*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *node = subtree;
144*6c3e8a4dSEmil Tsalapatis 	int dir;
145*6c3e8a4dSEmil Tsalapatis 
146*6c3e8a4dSEmil Tsalapatis 	if (!subtree)
147*6c3e8a4dSEmil Tsalapatis 		return NULL;
148*6c3e8a4dSEmil Tsalapatis 
149*6c3e8a4dSEmil Tsalapatis 	while (can_loop) {
150*6c3e8a4dSEmil Tsalapatis 		if (node->key == key)
151*6c3e8a4dSEmil Tsalapatis 			break;
152*6c3e8a4dSEmil Tsalapatis 
153*6c3e8a4dSEmil Tsalapatis 		dir = (key < node->key) ? 0 : 1;
154*6c3e8a4dSEmil Tsalapatis 
155*6c3e8a4dSEmil Tsalapatis 		if (!node->child[dir])
156*6c3e8a4dSEmil Tsalapatis 			break;
157*6c3e8a4dSEmil Tsalapatis 
158*6c3e8a4dSEmil Tsalapatis 		node = node->child[dir];
159*6c3e8a4dSEmil Tsalapatis 	}
160*6c3e8a4dSEmil Tsalapatis 
161*6c3e8a4dSEmil Tsalapatis 	return node;
162*6c3e8a4dSEmil Tsalapatis }
163*6c3e8a4dSEmil Tsalapatis 
164*6c3e8a4dSEmil Tsalapatis static
165*6c3e8a4dSEmil Tsalapatis struct rbnode __arena *rbnode_least_upper_bound(struct rbnode __arena *subtree, uint64_t key)
166*6c3e8a4dSEmil Tsalapatis {
167*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *node = subtree;
168*6c3e8a4dSEmil Tsalapatis 	int dir;
169*6c3e8a4dSEmil Tsalapatis 
170*6c3e8a4dSEmil Tsalapatis 	if (!subtree)
171*6c3e8a4dSEmil Tsalapatis 		return NULL;
172*6c3e8a4dSEmil Tsalapatis 
173*6c3e8a4dSEmil Tsalapatis 	while (can_loop) {
174*6c3e8a4dSEmil Tsalapatis 		dir = (key <= node->key) ? 0 : 1;
175*6c3e8a4dSEmil Tsalapatis 
176*6c3e8a4dSEmil Tsalapatis 		if (!node->child[dir])
177*6c3e8a4dSEmil Tsalapatis 			break;
178*6c3e8a4dSEmil Tsalapatis 
179*6c3e8a4dSEmil Tsalapatis 		node = node->child[dir];
180*6c3e8a4dSEmil Tsalapatis 	}
181*6c3e8a4dSEmil Tsalapatis 
182*6c3e8a4dSEmil Tsalapatis 	return node;
183*6c3e8a4dSEmil Tsalapatis }
184*6c3e8a4dSEmil Tsalapatis 
185*6c3e8a4dSEmil Tsalapatis __weak
186*6c3e8a4dSEmil Tsalapatis int rb_find(struct rbtree __arena *rbtree, u64 key, u64 *value)
187*6c3e8a4dSEmil Tsalapatis {
188*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *node;
189*6c3e8a4dSEmil Tsalapatis 
190*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
191*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
192*6c3e8a4dSEmil Tsalapatis 
193*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!value))
194*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
195*6c3e8a4dSEmil Tsalapatis 
196*6c3e8a4dSEmil Tsalapatis 	node = rbnode_find(rbtree->root, key);
197*6c3e8a4dSEmil Tsalapatis 	if (!node || node->key != key)
198*6c3e8a4dSEmil Tsalapatis 		return -ENOENT;
199*6c3e8a4dSEmil Tsalapatis 
200*6c3e8a4dSEmil Tsalapatis 	*value = node->value;
201*6c3e8a4dSEmil Tsalapatis 
202*6c3e8a4dSEmil Tsalapatis 	return 0;
203*6c3e8a4dSEmil Tsalapatis }
204*6c3e8a4dSEmil Tsalapatis 
205*6c3e8a4dSEmil Tsalapatis __weak
206*6c3e8a4dSEmil Tsalapatis struct rbnode __arena *rb_node_alloc(u64 key, u64 value)
207*6c3e8a4dSEmil Tsalapatis {
208*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *rbnode = NULL;
209*6c3e8a4dSEmil Tsalapatis 
210*6c3e8a4dSEmil Tsalapatis 	rbnode = (struct rbnode __arena *)arena_malloc(sizeof(*rbnode));
211*6c3e8a4dSEmil Tsalapatis 	if (!rbnode)
212*6c3e8a4dSEmil Tsalapatis 		return NULL;
213*6c3e8a4dSEmil Tsalapatis 
214*6c3e8a4dSEmil Tsalapatis 	/*
215*6c3e8a4dSEmil Tsalapatis 	 * WARNING: The order of assignments is weird on purpose.
216*6c3e8a4dSEmil Tsalapatis 	 * See comment in rb_insert_node() for more context.
217*6c3e8a4dSEmil Tsalapatis 	 * TL;DR: Prevent consecutive 0 assignments from being
218*6c3e8a4dSEmil Tsalapatis 	 * promoted into an unverifiable memset by the compiler.
219*6c3e8a4dSEmil Tsalapatis 	 */
220*6c3e8a4dSEmil Tsalapatis 
221*6c3e8a4dSEmil Tsalapatis 	rbnode->key = key;
222*6c3e8a4dSEmil Tsalapatis 	rbnode->parent = NULL;
223*6c3e8a4dSEmil Tsalapatis 	rbnode->value = value;
224*6c3e8a4dSEmil Tsalapatis 	rbnode->left = NULL;
225*6c3e8a4dSEmil Tsalapatis 	rbnode->is_red = true;
226*6c3e8a4dSEmil Tsalapatis 	rbnode->right = NULL;
227*6c3e8a4dSEmil Tsalapatis 
228*6c3e8a4dSEmil Tsalapatis 	return rbnode;
229*6c3e8a4dSEmil Tsalapatis }
230*6c3e8a4dSEmil Tsalapatis 
231*6c3e8a4dSEmil Tsalapatis __weak
232*6c3e8a4dSEmil Tsalapatis void rb_node_free(struct rbnode __arena *rbnode)
233*6c3e8a4dSEmil Tsalapatis {
234*6c3e8a4dSEmil Tsalapatis 	arena_free(rbnode);
235*6c3e8a4dSEmil Tsalapatis }
236*6c3e8a4dSEmil Tsalapatis 
237*6c3e8a4dSEmil Tsalapatis static
238*6c3e8a4dSEmil Tsalapatis int rb_node_insert(struct rbtree __arena *rbtree,
239*6c3e8a4dSEmil Tsalapatis 		   struct rbnode __arena *node)
240*6c3e8a4dSEmil Tsalapatis {
241*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *grandparent, *parent = rbtree->root;
242*6c3e8a4dSEmil Tsalapatis 	u64 key = node->key;
243*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *uncle;
244*6c3e8a4dSEmil Tsalapatis 	int dir;
245*6c3e8a4dSEmil Tsalapatis 	int ret;
246*6c3e8a4dSEmil Tsalapatis 
247*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
248*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
249*6c3e8a4dSEmil Tsalapatis 
250*6c3e8a4dSEmil Tsalapatis 	if (!parent) {
251*6c3e8a4dSEmil Tsalapatis 		rbtree->root = node;
252*6c3e8a4dSEmil Tsalapatis 		return 0;
253*6c3e8a4dSEmil Tsalapatis 	}
254*6c3e8a4dSEmil Tsalapatis 
255*6c3e8a4dSEmil Tsalapatis 	if (rbtree->insert != RB_DUPLICATE)
256*6c3e8a4dSEmil Tsalapatis 		parent = rbnode_find(parent, key);
257*6c3e8a4dSEmil Tsalapatis 	else
258*6c3e8a4dSEmil Tsalapatis 		parent = rbnode_least_upper_bound(parent, key);
259*6c3e8a4dSEmil Tsalapatis 
260*6c3e8a4dSEmil Tsalapatis 	if (key == parent->key && rbtree->insert != RB_DUPLICATE) {
261*6c3e8a4dSEmil Tsalapatis 		if (rbtree->insert == RB_UPDATE) {
262*6c3e8a4dSEmil Tsalapatis 			/*
263*6c3e8a4dSEmil Tsalapatis 			 * Replace the old node with the new one.
264*6c3e8a4dSEmil Tsalapatis 			 * Free up the old node.
265*6c3e8a4dSEmil Tsalapatis 			 */
266*6c3e8a4dSEmil Tsalapatis 			ret = rbnode_replace(rbtree, parent, node);
267*6c3e8a4dSEmil Tsalapatis 			if (ret)
268*6c3e8a4dSEmil Tsalapatis 				return ret;
269*6c3e8a4dSEmil Tsalapatis 
270*6c3e8a4dSEmil Tsalapatis 			if (rbtree->alloc == RB_ALLOC)
271*6c3e8a4dSEmil Tsalapatis 				rb_node_free(parent);
272*6c3e8a4dSEmil Tsalapatis 
273*6c3e8a4dSEmil Tsalapatis 			return 0;
274*6c3e8a4dSEmil Tsalapatis 		}
275*6c3e8a4dSEmil Tsalapatis 
276*6c3e8a4dSEmil Tsalapatis 		/* Otherwise it's RB_DEFAULT. */
277*6c3e8a4dSEmil Tsalapatis 		return -EALREADY;
278*6c3e8a4dSEmil Tsalapatis 	}
279*6c3e8a4dSEmil Tsalapatis 
280*6c3e8a4dSEmil Tsalapatis 	node->parent = parent;
281*6c3e8a4dSEmil Tsalapatis 	/* Also works if key == parent->key. */
282*6c3e8a4dSEmil Tsalapatis 	if (key <= parent->key)
283*6c3e8a4dSEmil Tsalapatis 		parent->left = node;
284*6c3e8a4dSEmil Tsalapatis 	else
285*6c3e8a4dSEmil Tsalapatis 		parent->right = node;
286*6c3e8a4dSEmil Tsalapatis 
287*6c3e8a4dSEmil Tsalapatis 	while (can_loop) {
288*6c3e8a4dSEmil Tsalapatis 		parent = node->parent;
289*6c3e8a4dSEmil Tsalapatis 		if (!parent)
290*6c3e8a4dSEmil Tsalapatis 			return 0;
291*6c3e8a4dSEmil Tsalapatis 
292*6c3e8a4dSEmil Tsalapatis 		if (!parent->is_red)
293*6c3e8a4dSEmil Tsalapatis 			return 0;
294*6c3e8a4dSEmil Tsalapatis 
295*6c3e8a4dSEmil Tsalapatis 		grandparent = parent->parent;
296*6c3e8a4dSEmil Tsalapatis 		if (!grandparent) {
297*6c3e8a4dSEmil Tsalapatis 			parent->is_red = false;
298*6c3e8a4dSEmil Tsalapatis 			return 0;
299*6c3e8a4dSEmil Tsalapatis 		}
300*6c3e8a4dSEmil Tsalapatis 
301*6c3e8a4dSEmil Tsalapatis 		dir = rbnode_dir(parent);
302*6c3e8a4dSEmil Tsalapatis 		uncle = grandparent->child[1 - dir];
303*6c3e8a4dSEmil Tsalapatis 
304*6c3e8a4dSEmil Tsalapatis 		if (!uncle || !uncle->is_red) {
305*6c3e8a4dSEmil Tsalapatis 			if (node == parent->child[1 - dir]) {
306*6c3e8a4dSEmil Tsalapatis 				rbnode_rotate(rbtree, parent, dir);
307*6c3e8a4dSEmil Tsalapatis 				node = parent;
308*6c3e8a4dSEmil Tsalapatis 				parent = grandparent->child[dir];
309*6c3e8a4dSEmil Tsalapatis 			}
310*6c3e8a4dSEmil Tsalapatis 
311*6c3e8a4dSEmil Tsalapatis 			rbnode_rotate(rbtree, grandparent, 1 - dir);
312*6c3e8a4dSEmil Tsalapatis 			parent->is_red = false;
313*6c3e8a4dSEmil Tsalapatis 			grandparent->is_red = true;
314*6c3e8a4dSEmil Tsalapatis 
315*6c3e8a4dSEmil Tsalapatis 			return 0;
316*6c3e8a4dSEmil Tsalapatis 		}
317*6c3e8a4dSEmil Tsalapatis 
318*6c3e8a4dSEmil Tsalapatis 		/* Uncle is red. */
319*6c3e8a4dSEmil Tsalapatis 
320*6c3e8a4dSEmil Tsalapatis 		parent->is_red = false;
321*6c3e8a4dSEmil Tsalapatis 		uncle->is_red = false;
322*6c3e8a4dSEmil Tsalapatis 		grandparent->is_red = true;
323*6c3e8a4dSEmil Tsalapatis 
324*6c3e8a4dSEmil Tsalapatis 		node = grandparent;
325*6c3e8a4dSEmil Tsalapatis 	}
326*6c3e8a4dSEmil Tsalapatis 
327*6c3e8a4dSEmil Tsalapatis 	return 0;
328*6c3e8a4dSEmil Tsalapatis }
329*6c3e8a4dSEmil Tsalapatis 
330*6c3e8a4dSEmil Tsalapatis int rb_insert_node(struct rbtree __arena *rbtree,
331*6c3e8a4dSEmil Tsalapatis 		   struct rbnode __arena *node)
332*6c3e8a4dSEmil Tsalapatis {
333*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
334*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
335*6c3e8a4dSEmil Tsalapatis 
336*6c3e8a4dSEmil Tsalapatis 	if (unlikely(rbtree->alloc == RB_ALLOC))
337*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
338*6c3e8a4dSEmil Tsalapatis 
339*6c3e8a4dSEmil Tsalapatis 	node->left = NULL;
340*6c3e8a4dSEmil Tsalapatis 
341*6c3e8a4dSEmil Tsalapatis 	/*
342*6c3e8a4dSEmil Tsalapatis 	 * Workaround to break an optimization that causes
343*6c3e8a4dSEmil Tsalapatis 	 * verification failures on some compilers. Assignments
344*6c3e8a4dSEmil Tsalapatis 	 * of the kind
345*6c3e8a4dSEmil Tsalapatis 	 *
346*6c3e8a4dSEmil Tsalapatis 	 * *(r0 + 0) = 0;
347*6c3e8a4dSEmil Tsalapatis 	 * *(r0 + 8) = 0;
348*6c3e8a4dSEmil Tsalapatis 	 * *(r0 + 16) = 0;
349*6c3e8a4dSEmil Tsalapatis 	 *
350*6c3e8a4dSEmil Tsalapatis 	 * get promoted into a memset, and that in turn is not
351*6c3e8a4dSEmil Tsalapatis 	 * handled properly for arena memory by LLVM 21 and GCC 15.
352*6c3e8a4dSEmil Tsalapatis 	 * Add a barrier for now to prevent the assignments from being fused.
353*6c3e8a4dSEmil Tsalapatis 	 */
354*6c3e8a4dSEmil Tsalapatis 	barrier();
355*6c3e8a4dSEmil Tsalapatis 
356*6c3e8a4dSEmil Tsalapatis 	node->parent = NULL;
357*6c3e8a4dSEmil Tsalapatis 	node->right = NULL;
358*6c3e8a4dSEmil Tsalapatis 
359*6c3e8a4dSEmil Tsalapatis 	node->is_red = true;
360*6c3e8a4dSEmil Tsalapatis 
361*6c3e8a4dSEmil Tsalapatis 	return rb_node_insert(rbtree, node);
362*6c3e8a4dSEmil Tsalapatis }
363*6c3e8a4dSEmil Tsalapatis 
364*6c3e8a4dSEmil Tsalapatis __weak
365*6c3e8a4dSEmil Tsalapatis int rb_insert(struct rbtree __arena *rbtree, u64 key, u64 value)
366*6c3e8a4dSEmil Tsalapatis {
367*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *node;
368*6c3e8a4dSEmil Tsalapatis 	int ret;
369*6c3e8a4dSEmil Tsalapatis 
370*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
371*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
372*6c3e8a4dSEmil Tsalapatis 
373*6c3e8a4dSEmil Tsalapatis 	if (unlikely(rbtree->alloc != RB_ALLOC))
374*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
375*6c3e8a4dSEmil Tsalapatis 
376*6c3e8a4dSEmil Tsalapatis 	node = rb_node_alloc(key, value);
377*6c3e8a4dSEmil Tsalapatis 	if (!node)
378*6c3e8a4dSEmil Tsalapatis 		return -ENOMEM;
379*6c3e8a4dSEmil Tsalapatis 
380*6c3e8a4dSEmil Tsalapatis 	ret = rb_node_insert(rbtree, node);
381*6c3e8a4dSEmil Tsalapatis 	if (ret) {
382*6c3e8a4dSEmil Tsalapatis 		rb_node_free(node);
383*6c3e8a4dSEmil Tsalapatis 		return ret;
384*6c3e8a4dSEmil Tsalapatis 	}
385*6c3e8a4dSEmil Tsalapatis 
386*6c3e8a4dSEmil Tsalapatis 	return 0;
387*6c3e8a4dSEmil Tsalapatis }
388*6c3e8a4dSEmil Tsalapatis 
389*6c3e8a4dSEmil Tsalapatis static inline struct rbnode __arena *rbnode_least(struct rbnode __arena *subtree)
390*6c3e8a4dSEmil Tsalapatis {
391*6c3e8a4dSEmil Tsalapatis 	while (subtree->left && can_loop)
392*6c3e8a4dSEmil Tsalapatis 		subtree = subtree->left;
393*6c3e8a4dSEmil Tsalapatis 
394*6c3e8a4dSEmil Tsalapatis 	return subtree;
395*6c3e8a4dSEmil Tsalapatis }
396*6c3e8a4dSEmil Tsalapatis 
397*6c3e8a4dSEmil Tsalapatis __weak int rb_least(struct rbtree __arena *rbtree, u64 *key, u64 *value)
398*6c3e8a4dSEmil Tsalapatis {
399*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *least;
400*6c3e8a4dSEmil Tsalapatis 
401*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
402*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
403*6c3e8a4dSEmil Tsalapatis 
404*6c3e8a4dSEmil Tsalapatis 	if (!rbtree->root)
405*6c3e8a4dSEmil Tsalapatis 		return -ENOENT;
406*6c3e8a4dSEmil Tsalapatis 
407*6c3e8a4dSEmil Tsalapatis 	least = rbnode_least(rbtree->root);
408*6c3e8a4dSEmil Tsalapatis 	if (key)
409*6c3e8a4dSEmil Tsalapatis 		*key = least->key;
410*6c3e8a4dSEmil Tsalapatis 	if (value)
411*6c3e8a4dSEmil Tsalapatis 		*value = least->value;
412*6c3e8a4dSEmil Tsalapatis 
413*6c3e8a4dSEmil Tsalapatis 	return 0;
414*6c3e8a4dSEmil Tsalapatis }
415*6c3e8a4dSEmil Tsalapatis 
416*6c3e8a4dSEmil Tsalapatis 
417*6c3e8a4dSEmil Tsalapatis /*
418*6c3e8a4dSEmil Tsalapatis  * If we are referencing ourselves, a and b have a parent-child relation,
419*6c3e8a4dSEmil Tsalapatis  * and we should be pointing at the other node instead.
420*6c3e8a4dSEmil Tsalapatis  */
421*6c3e8a4dSEmil Tsalapatis static inline void rbnode_fixup_pointers(struct rbnode __arena *a,
422*6c3e8a4dSEmil Tsalapatis 					 struct rbnode __arena *b)
423*6c3e8a4dSEmil Tsalapatis {
424*6c3e8a4dSEmil Tsalapatis #define fixup(n1, n2, member) do { if (n1->member == n1) n1->member = n2; } while (0)
425*6c3e8a4dSEmil Tsalapatis 	fixup(a, b, left);
426*6c3e8a4dSEmil Tsalapatis 	fixup(a, b, right);
427*6c3e8a4dSEmil Tsalapatis 	fixup(a, b, parent);
428*6c3e8a4dSEmil Tsalapatis #undef fixup
429*6c3e8a4dSEmil Tsalapatis }
430*6c3e8a4dSEmil Tsalapatis 
431*6c3e8a4dSEmil Tsalapatis static inline void rbnode_swap_values(struct rbnode __arena *a,
432*6c3e8a4dSEmil Tsalapatis 				      struct rbnode __arena *b)
433*6c3e8a4dSEmil Tsalapatis {
434*6c3e8a4dSEmil Tsalapatis #define swap(n1, n2, tmp) do { (tmp) = (n1); (n1) = (n2); (n2) = (tmp); } while (0)
435*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *tmpnode;
436*6c3e8a4dSEmil Tsalapatis 	u64 tmp;
437*6c3e8a4dSEmil Tsalapatis 
438*6c3e8a4dSEmil Tsalapatis 	/* Swap the pointers. */
439*6c3e8a4dSEmil Tsalapatis 	swap(a->is_red, b->is_red, tmp);
440*6c3e8a4dSEmil Tsalapatis 
441*6c3e8a4dSEmil Tsalapatis 	swap(a->left, b->left, tmpnode);
442*6c3e8a4dSEmil Tsalapatis 	swap(a->right, b->right, tmpnode);
443*6c3e8a4dSEmil Tsalapatis 	swap(a->parent, b->parent, tmpnode);
444*6c3e8a4dSEmil Tsalapatis #undef swap
445*6c3e8a4dSEmil Tsalapatis 
446*6c3e8a4dSEmil Tsalapatis 	/* Account for the nodes being parent and child. */
447*6c3e8a4dSEmil Tsalapatis 	rbnode_fixup_pointers(b, a);
448*6c3e8a4dSEmil Tsalapatis 	rbnode_fixup_pointers(a, b);
449*6c3e8a4dSEmil Tsalapatis }
450*6c3e8a4dSEmil Tsalapatis 
451*6c3e8a4dSEmil Tsalapatis static inline void rbnode_adjust_neighbors(struct rbtree __arena *rbtree,
452*6c3e8a4dSEmil Tsalapatis 					   struct rbnode __arena *node, int dir)
453*6c3e8a4dSEmil Tsalapatis {
454*6c3e8a4dSEmil Tsalapatis 	if (node->left)
455*6c3e8a4dSEmil Tsalapatis 		node->left->parent = node;
456*6c3e8a4dSEmil Tsalapatis 	if (node->right)
457*6c3e8a4dSEmil Tsalapatis 		node->right->parent = node;
458*6c3e8a4dSEmil Tsalapatis 
459*6c3e8a4dSEmil Tsalapatis 	if (node->parent) {
460*6c3e8a4dSEmil Tsalapatis 		node->parent->child[dir] = node;
461*6c3e8a4dSEmil Tsalapatis 		return;
462*6c3e8a4dSEmil Tsalapatis 	}
463*6c3e8a4dSEmil Tsalapatis 
464*6c3e8a4dSEmil Tsalapatis 	rbtree->root = node;
465*6c3e8a4dSEmil Tsalapatis }
466*6c3e8a4dSEmil Tsalapatis 
467*6c3e8a4dSEmil Tsalapatis /*
468*6c3e8a4dSEmil Tsalapatis  * Directly replace an existing node with a replacement. The replacement node
469*6c3e8a4dSEmil Tsalapatis  * should not already be in the tree.
470*6c3e8a4dSEmil Tsalapatis  */
471*6c3e8a4dSEmil Tsalapatis static int rbnode_replace(struct rbtree __arena *rbtree,
472*6c3e8a4dSEmil Tsalapatis 			  struct rbnode __arena *existing,
473*6c3e8a4dSEmil Tsalapatis 			  struct rbnode __arena *replacement)
474*6c3e8a4dSEmil Tsalapatis {
475*6c3e8a4dSEmil Tsalapatis 	int dir = 0;
476*6c3e8a4dSEmil Tsalapatis 
477*6c3e8a4dSEmil Tsalapatis 	if (unlikely(replacement->parent || replacement->left || replacement->right))
478*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
479*6c3e8a4dSEmil Tsalapatis 
480*6c3e8a4dSEmil Tsalapatis 	if (existing->parent)
481*6c3e8a4dSEmil Tsalapatis 		dir = rbnode_dir(existing);
482*6c3e8a4dSEmil Tsalapatis 
483*6c3e8a4dSEmil Tsalapatis 	replacement->is_red = existing->is_red;
484*6c3e8a4dSEmil Tsalapatis 	replacement->left = existing->left;
485*6c3e8a4dSEmil Tsalapatis 	replacement->right = existing->right;
486*6c3e8a4dSEmil Tsalapatis 	replacement->parent = existing->parent;
487*6c3e8a4dSEmil Tsalapatis 
488*6c3e8a4dSEmil Tsalapatis 	/* Fix up the new node's neighbors. */
489*6c3e8a4dSEmil Tsalapatis 	rbnode_adjust_neighbors(rbtree, replacement, dir);
490*6c3e8a4dSEmil Tsalapatis 
491*6c3e8a4dSEmil Tsalapatis 	return 0;
492*6c3e8a4dSEmil Tsalapatis }
493*6c3e8a4dSEmil Tsalapatis 
494*6c3e8a4dSEmil Tsalapatis /*
495*6c3e8a4dSEmil Tsalapatis  * Switch two nodes in the tree in place. This is useful during node deletion.
496*6c3e8a4dSEmil Tsalapatis  * This is more involved than switching the values of the two nodes because we
497*6c3e8a4dSEmil Tsalapatis  * must update all tree pointers.
498*6c3e8a4dSEmil Tsalapatis  */
499*6c3e8a4dSEmil Tsalapatis static void rbnode_switch(struct rbtree __arena *rbtree,
500*6c3e8a4dSEmil Tsalapatis 			  struct rbnode __arena *a,
501*6c3e8a4dSEmil Tsalapatis 			  struct rbnode __arena *b)
502*6c3e8a4dSEmil Tsalapatis {
503*6c3e8a4dSEmil Tsalapatis 	int adir = 0, bdir = 0;
504*6c3e8a4dSEmil Tsalapatis 
505*6c3e8a4dSEmil Tsalapatis 	/*
506*6c3e8a4dSEmil Tsalapatis 	 * Store the direction in the parent because we will not
507*6c3e8a4dSEmil Tsalapatis 	 * be able to recompute it once we start swapping values.
508*6c3e8a4dSEmil Tsalapatis 	 */
509*6c3e8a4dSEmil Tsalapatis 	if (a->parent)
510*6c3e8a4dSEmil Tsalapatis 		adir = rbnode_dir(a);
511*6c3e8a4dSEmil Tsalapatis 
512*6c3e8a4dSEmil Tsalapatis 	if (b->parent)
513*6c3e8a4dSEmil Tsalapatis 		bdir = rbnode_dir(b);
514*6c3e8a4dSEmil Tsalapatis 
515*6c3e8a4dSEmil Tsalapatis 	rbnode_swap_values(a, b);
516*6c3e8a4dSEmil Tsalapatis 
517*6c3e8a4dSEmil Tsalapatis 	/*
518*6c3e8a4dSEmil Tsalapatis 	 * Fix up the pointers from the children/parent to the
519*6c3e8a4dSEmil Tsalapatis 	 * new nodes.
520*6c3e8a4dSEmil Tsalapatis 	 */
521*6c3e8a4dSEmil Tsalapatis 	rbnode_adjust_neighbors(rbtree, a, bdir);
522*6c3e8a4dSEmil Tsalapatis 	rbnode_adjust_neighbors(rbtree, b, adir);
523*6c3e8a4dSEmil Tsalapatis }
524*6c3e8a4dSEmil Tsalapatis 
525*6c3e8a4dSEmil Tsalapatis static inline int rbnode_remove_node_single_child(struct rbtree __arena *rbtree,
526*6c3e8a4dSEmil Tsalapatis 						  struct rbnode __arena *node,
527*6c3e8a4dSEmil Tsalapatis 						  bool free)
528*6c3e8a4dSEmil Tsalapatis {
529*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *child;
530*6c3e8a4dSEmil Tsalapatis 	int dir;
531*6c3e8a4dSEmil Tsalapatis 
532*6c3e8a4dSEmil Tsalapatis 	if (unlikely(node->is_red)) {
533*6c3e8a4dSEmil Tsalapatis 		arena_stderr("Node unexpectedly red\n");
534*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
535*6c3e8a4dSEmil Tsalapatis 	}
536*6c3e8a4dSEmil Tsalapatis 
537*6c3e8a4dSEmil Tsalapatis 	child = node->left ? node->left : node->right;
538*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!child->is_red)) {
539*6c3e8a4dSEmil Tsalapatis 		arena_stderr("Only child is black\n");
540*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
541*6c3e8a4dSEmil Tsalapatis 	}
542*6c3e8a4dSEmil Tsalapatis 
543*6c3e8a4dSEmil Tsalapatis 	/*
544*6c3e8a4dSEmil Tsalapatis 	 * Since it's the immediate child, we can just
545*6c3e8a4dSEmil Tsalapatis 	 * remove the parent.
546*6c3e8a4dSEmil Tsalapatis 	 */
547*6c3e8a4dSEmil Tsalapatis 	child->parent = node->parent;
548*6c3e8a4dSEmil Tsalapatis 
549*6c3e8a4dSEmil Tsalapatis 	if (node->parent) {
550*6c3e8a4dSEmil Tsalapatis 		dir = rbnode_dir(node);
551*6c3e8a4dSEmil Tsalapatis 		node->parent->child[dir] = child;
552*6c3e8a4dSEmil Tsalapatis 	} else {
553*6c3e8a4dSEmil Tsalapatis 		rbtree->root = child;
554*6c3e8a4dSEmil Tsalapatis 	}
555*6c3e8a4dSEmil Tsalapatis 
556*6c3e8a4dSEmil Tsalapatis 	/* Color the child black. */
557*6c3e8a4dSEmil Tsalapatis 	child->is_red = false;
558*6c3e8a4dSEmil Tsalapatis 
559*6c3e8a4dSEmil Tsalapatis 	/* Only free if called from rb_remove. */
560*6c3e8a4dSEmil Tsalapatis 	if (free)
561*6c3e8a4dSEmil Tsalapatis 		rb_node_free(node);
562*6c3e8a4dSEmil Tsalapatis 
563*6c3e8a4dSEmil Tsalapatis 	return 0;
564*6c3e8a4dSEmil Tsalapatis }
565*6c3e8a4dSEmil Tsalapatis 
566*6c3e8a4dSEmil Tsalapatis static inline bool rbnode_has_red_children(struct rbnode __arena *node)
567*6c3e8a4dSEmil Tsalapatis {
568*6c3e8a4dSEmil Tsalapatis 	if (node->left && node->left->is_red)
569*6c3e8a4dSEmil Tsalapatis 		return true;
570*6c3e8a4dSEmil Tsalapatis 
571*6c3e8a4dSEmil Tsalapatis 	return node->right && node->right->is_red;
572*6c3e8a4dSEmil Tsalapatis }
573*6c3e8a4dSEmil Tsalapatis 
574*6c3e8a4dSEmil Tsalapatis static
575*6c3e8a4dSEmil Tsalapatis int rb_node_remove(struct rbtree __arena *rbtree,
576*6c3e8a4dSEmil Tsalapatis 		   struct rbnode __arena *node)
577*6c3e8a4dSEmil Tsalapatis {
578*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *parent, *sibling, *close_nephew, *distant_nephew;
579*6c3e8a4dSEmil Tsalapatis 	bool free = (rbtree->alloc == RB_ALLOC);
580*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *replace, *initial;
581*6c3e8a4dSEmil Tsalapatis 	bool is_red;
582*6c3e8a4dSEmil Tsalapatis 	int dir;
583*6c3e8a4dSEmil Tsalapatis 
584*6c3e8a4dSEmil Tsalapatis 	/* Both children present, replace with next largest key. */
585*6c3e8a4dSEmil Tsalapatis 	if (node->left && node->right) {
586*6c3e8a4dSEmil Tsalapatis 		/*
587*6c3e8a4dSEmil Tsalapatis 		 * Swap the node itself instead of just the
588*6c3e8a4dSEmil Tsalapatis 		 * key/value pair to account for nodes embedded
589*6c3e8a4dSEmil Tsalapatis 		 * in other structs.
590*6c3e8a4dSEmil Tsalapatis 		 */
591*6c3e8a4dSEmil Tsalapatis 
592*6c3e8a4dSEmil Tsalapatis 		replace = rbnode_least(node->right);
593*6c3e8a4dSEmil Tsalapatis 		rbnode_switch(rbtree, replace, node);
594*6c3e8a4dSEmil Tsalapatis 
595*6c3e8a4dSEmil Tsalapatis 		/*
596*6c3e8a4dSEmil Tsalapatis 		 * FALLTHROUGH: We moved the node we are removing to
597*6c3e8a4dSEmil Tsalapatis 		 * the leftmost position of the subtree. We can now
598*6c3e8a4dSEmil Tsalapatis 		 * remove it as if it was always where we moved it to.
599*6c3e8a4dSEmil Tsalapatis 		 */
600*6c3e8a4dSEmil Tsalapatis 	}
601*6c3e8a4dSEmil Tsalapatis 
602*6c3e8a4dSEmil Tsalapatis 	initial = node;
603*6c3e8a4dSEmil Tsalapatis 
604*6c3e8a4dSEmil Tsalapatis 	/* Only one child present, replace with child and paint it black. */
605*6c3e8a4dSEmil Tsalapatis 	if (!node->left != !node->right)
606*6c3e8a4dSEmil Tsalapatis 		return rbnode_remove_node_single_child(rbtree, node, free);
607*6c3e8a4dSEmil Tsalapatis 
608*6c3e8a4dSEmil Tsalapatis 	/* (!node->left && !node->right) */
609*6c3e8a4dSEmil Tsalapatis 
610*6c3e8a4dSEmil Tsalapatis 	parent = node->parent;
611*6c3e8a4dSEmil Tsalapatis 	if (!parent) {
612*6c3e8a4dSEmil Tsalapatis 		/* Check that we're _actually_ the root. */
613*6c3e8a4dSEmil Tsalapatis 		if (rbtree->root == node)
614*6c3e8a4dSEmil Tsalapatis 			rbtree->root = NULL;
615*6c3e8a4dSEmil Tsalapatis 		else
616*6c3e8a4dSEmil Tsalapatis 			arena_stderr("WARNING: Attempting to remove detached node from rbtree\n");
617*6c3e8a4dSEmil Tsalapatis 
618*6c3e8a4dSEmil Tsalapatis 		if (free)
619*6c3e8a4dSEmil Tsalapatis 			rb_node_free(node);
620*6c3e8a4dSEmil Tsalapatis 		return 0;
621*6c3e8a4dSEmil Tsalapatis 	}
622*6c3e8a4dSEmil Tsalapatis 
623*6c3e8a4dSEmil Tsalapatis 	dir = rbnode_dir(node);
624*6c3e8a4dSEmil Tsalapatis 	parent->child[dir] = NULL;
625*6c3e8a4dSEmil Tsalapatis 	is_red = node->is_red;
626*6c3e8a4dSEmil Tsalapatis 
627*6c3e8a4dSEmil Tsalapatis 	if (free)
628*6c3e8a4dSEmil Tsalapatis 		rb_node_free(node);
629*6c3e8a4dSEmil Tsalapatis 
630*6c3e8a4dSEmil Tsalapatis 	/* If we removed a red node, we did not unbalance the tree.*/
631*6c3e8a4dSEmil Tsalapatis 	if (is_red)
632*6c3e8a4dSEmil Tsalapatis 		return 0;
633*6c3e8a4dSEmil Tsalapatis 
634*6c3e8a4dSEmil Tsalapatis 	sibling = parent->child[1 - dir];
635*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!sibling)) {
636*6c3e8a4dSEmil Tsalapatis 		arena_stderr("rbtree: removed black node has no sibling\n");
637*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
638*6c3e8a4dSEmil Tsalapatis 	}
639*6c3e8a4dSEmil Tsalapatis 
640*6c3e8a4dSEmil Tsalapatis 	/*
641*6c3e8a4dSEmil Tsalapatis 	 * We removed a black node, causing a change in path
642*6c3e8a4dSEmil Tsalapatis 	 * weight. Start rebalancing. The invariant is that
643*6c3e8a4dSEmil Tsalapatis 	 * all paths going through the node are shortened
644*6c3e8a4dSEmil Tsalapatis 	 * by one, and the current node is black.
645*6c3e8a4dSEmil Tsalapatis 	 */
646*6c3e8a4dSEmil Tsalapatis 	while (can_loop) {
647*6c3e8a4dSEmil Tsalapatis 
648*6c3e8a4dSEmil Tsalapatis 		/* Balancing reached the root, there can be no imbalance. */
649*6c3e8a4dSEmil Tsalapatis 		if (!parent)
650*6c3e8a4dSEmil Tsalapatis 			return 0;
651*6c3e8a4dSEmil Tsalapatis 
652*6c3e8a4dSEmil Tsalapatis 		/*
653*6c3e8a4dSEmil Tsalapatis 		 * We already determined the dir, either above or
654*6c3e8a4dSEmil Tsalapatis 		 * at the end of the loop.
655*6c3e8a4dSEmil Tsalapatis 		 */
656*6c3e8a4dSEmil Tsalapatis 
657*6c3e8a4dSEmil Tsalapatis 		/*
658*6c3e8a4dSEmil Tsalapatis 		 * If we have no sibling, the tree was
659*6c3e8a4dSEmil Tsalapatis 		 * already unbalanced.
660*6c3e8a4dSEmil Tsalapatis 		 */
661*6c3e8a4dSEmil Tsalapatis 		sibling = parent->child[1 - dir];
662*6c3e8a4dSEmil Tsalapatis 		if (unlikely(!sibling)) {
663*6c3e8a4dSEmil Tsalapatis 			arena_stderr("rbtree: removed black node has no sibling\n");
664*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
665*6c3e8a4dSEmil Tsalapatis 		}
666*6c3e8a4dSEmil Tsalapatis 
667*6c3e8a4dSEmil Tsalapatis 		/* Sibling is red, turn it into the grandparent. */
668*6c3e8a4dSEmil Tsalapatis 		if (sibling->is_red) {
669*6c3e8a4dSEmil Tsalapatis 			/*
670*6c3e8a4dSEmil Tsalapatis 			 * Sibling is red. Transform the tree to turn
671*6c3e8a4dSEmil Tsalapatis 			 * the sibling into the parent's position, and
672*6c3e8a4dSEmil Tsalapatis 			 * repaint them. This does not balance the tree
673*6c3e8a4dSEmil Tsalapatis 			 * but makes it so we know the sibling is black
674*6c3e8a4dSEmil Tsalapatis 			 * and so can use the transformations to balance.
675*6c3e8a4dSEmil Tsalapatis 			 */
676*6c3e8a4dSEmil Tsalapatis 			rbnode_rotate(rbtree, parent, dir);
677*6c3e8a4dSEmil Tsalapatis 			parent->is_red = true;
678*6c3e8a4dSEmil Tsalapatis 			sibling->is_red = false;
679*6c3e8a4dSEmil Tsalapatis 
680*6c3e8a4dSEmil Tsalapatis 			/* Our new sibling is now the close nephew. */
681*6c3e8a4dSEmil Tsalapatis 			sibling = parent->child[1 - dir];
682*6c3e8a4dSEmil Tsalapatis 			/* If sibling has any red siblings, break out. */
683*6c3e8a4dSEmil Tsalapatis 			if (rbnode_has_red_children(sibling))
684*6c3e8a4dSEmil Tsalapatis 				break;
685*6c3e8a4dSEmil Tsalapatis 
686*6c3e8a4dSEmil Tsalapatis 			/* We can repaint the sibling and parent, we're done. */
687*6c3e8a4dSEmil Tsalapatis 			sibling->is_red = true;
688*6c3e8a4dSEmil Tsalapatis 			parent->is_red = false;
689*6c3e8a4dSEmil Tsalapatis 
690*6c3e8a4dSEmil Tsalapatis 			return 0;
691*6c3e8a4dSEmil Tsalapatis 		}
692*6c3e8a4dSEmil Tsalapatis 
693*6c3e8a4dSEmil Tsalapatis 		/* Sibling guaranteed to be black. If it has red children, break out. */
694*6c3e8a4dSEmil Tsalapatis 		if (rbnode_has_red_children(sibling))
695*6c3e8a4dSEmil Tsalapatis 			break;
696*6c3e8a4dSEmil Tsalapatis 
697*6c3e8a4dSEmil Tsalapatis 		/*
698*6c3e8a4dSEmil Tsalapatis 		 * Both sibling and children are black. If parent is red, swap
699*6c3e8a4dSEmil Tsalapatis 		 * colors with the sibling. Otherwise
700*6c3e8a4dSEmil Tsalapatis 		 */
701*6c3e8a4dSEmil Tsalapatis 		if (parent->is_red) {
702*6c3e8a4dSEmil Tsalapatis 			parent->is_red = false;
703*6c3e8a4dSEmil Tsalapatis 			sibling->is_red = true;
704*6c3e8a4dSEmil Tsalapatis 			return 0;
705*6c3e8a4dSEmil Tsalapatis 		}
706*6c3e8a4dSEmil Tsalapatis 
707*6c3e8a4dSEmil Tsalapatis 		/*
708*6c3e8a4dSEmil Tsalapatis 		 * Parent, sibling, and all its children are black. Repaint the sibling.
709*6c3e8a4dSEmil Tsalapatis 		 * This shortens the paths through it, so pop up a level in the
710*6c3e8a4dSEmil Tsalapatis 		 * tree and repeat the balancing.
711*6c3e8a4dSEmil Tsalapatis 		 */
712*6c3e8a4dSEmil Tsalapatis 		sibling->is_red = true;
713*6c3e8a4dSEmil Tsalapatis 		node = parent;
714*6c3e8a4dSEmil Tsalapatis 		parent = node->parent;
715*6c3e8a4dSEmil Tsalapatis 		dir = rbnode_dir(node);
716*6c3e8a4dSEmil Tsalapatis 	}
717*6c3e8a4dSEmil Tsalapatis 
718*6c3e8a4dSEmil Tsalapatis 	if (node != initial) {
719*6c3e8a4dSEmil Tsalapatis 		dir = rbnode_dir(node);
720*6c3e8a4dSEmil Tsalapatis 		parent = node->parent;
721*6c3e8a4dSEmil Tsalapatis 		sibling = parent->child[1-dir];
722*6c3e8a4dSEmil Tsalapatis 	}
723*6c3e8a4dSEmil Tsalapatis 	/*
724*6c3e8a4dSEmil Tsalapatis 	 * Almost there. We know between the parent, sibling,
725*6c3e8a4dSEmil Tsalapatis 	 * and nephews only one or two of the nephews are red. If
726*6c3e8a4dSEmil Tsalapatis 	 * it is the close one, rotate it to the sibling position,
727*6c3e8a4dSEmil Tsalapatis 	 * paint it black, and paint the previous sibling red.
728*6c3e8a4dSEmil Tsalapatis 	 */
729*6c3e8a4dSEmil Tsalapatis 
730*6c3e8a4dSEmil Tsalapatis 	close_nephew = sibling->child[dir];
731*6c3e8a4dSEmil Tsalapatis 	distant_nephew = sibling->child[1 - dir];
732*6c3e8a4dSEmil Tsalapatis 
733*6c3e8a4dSEmil Tsalapatis 	/*
734*6c3e8a4dSEmil Tsalapatis 	 * If the distant red nephew is not red, rotate
735*6c3e8a4dSEmil Tsalapatis 	 * and repaint. We need the distant nephew
736*6c3e8a4dSEmil Tsalapatis 	 * to be red. We know the close nephew is red
737*6c3e8a4dSEmil Tsalapatis 	 * because at least one of them are, so the
738*6c3e8a4dSEmil Tsalapatis 	 * distant one is black if it exists.
739*6c3e8a4dSEmil Tsalapatis 	 */
740*6c3e8a4dSEmil Tsalapatis 	if (!distant_nephew || !distant_nephew->is_red) {
741*6c3e8a4dSEmil Tsalapatis 		rbnode_rotate(rbtree, sibling, 1 - dir);
742*6c3e8a4dSEmil Tsalapatis 		sibling->is_red = true;
743*6c3e8a4dSEmil Tsalapatis 		close_nephew->is_red = false;
744*6c3e8a4dSEmil Tsalapatis 		distant_nephew = sibling;
745*6c3e8a4dSEmil Tsalapatis 		sibling = close_nephew;
746*6c3e8a4dSEmil Tsalapatis 	}
747*6c3e8a4dSEmil Tsalapatis 
748*6c3e8a4dSEmil Tsalapatis 	/*
749*6c3e8a4dSEmil Tsalapatis 	 * We now know it's the distant nephew that's red.
750*6c3e8a4dSEmil Tsalapatis 	 * Rotate the sibling into our parent's position
751*6c3e8a4dSEmil Tsalapatis 	 * and paint both black.
752*6c3e8a4dSEmil Tsalapatis 	 */
753*6c3e8a4dSEmil Tsalapatis 
754*6c3e8a4dSEmil Tsalapatis 	rbnode_rotate(rbtree, parent, dir);
755*6c3e8a4dSEmil Tsalapatis 	sibling->is_red = parent->is_red;
756*6c3e8a4dSEmil Tsalapatis 	parent->is_red = false;
757*6c3e8a4dSEmil Tsalapatis 	distant_nephew->is_red = false;
758*6c3e8a4dSEmil Tsalapatis 
759*6c3e8a4dSEmil Tsalapatis 	return 0;
760*6c3e8a4dSEmil Tsalapatis }
761*6c3e8a4dSEmil Tsalapatis 
762*6c3e8a4dSEmil Tsalapatis __weak
763*6c3e8a4dSEmil Tsalapatis int rb_remove_node(struct rbtree __arena *rbtree,
764*6c3e8a4dSEmil Tsalapatis 		   struct rbnode __arena *node)
765*6c3e8a4dSEmil Tsalapatis {
766*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
767*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
768*6c3e8a4dSEmil Tsalapatis 
769*6c3e8a4dSEmil Tsalapatis 	if (unlikely(rbtree->alloc == RB_ALLOC))
770*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
771*6c3e8a4dSEmil Tsalapatis 
772*6c3e8a4dSEmil Tsalapatis 	return rb_node_remove(rbtree, node);
773*6c3e8a4dSEmil Tsalapatis }
774*6c3e8a4dSEmil Tsalapatis 
775*6c3e8a4dSEmil Tsalapatis __weak
776*6c3e8a4dSEmil Tsalapatis int rb_remove(struct rbtree __arena *rbtree, u64 key)
777*6c3e8a4dSEmil Tsalapatis {
778*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *node;
779*6c3e8a4dSEmil Tsalapatis 
780*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
781*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
782*6c3e8a4dSEmil Tsalapatis 
783*6c3e8a4dSEmil Tsalapatis 	if (unlikely(rbtree->alloc != RB_ALLOC))
784*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
785*6c3e8a4dSEmil Tsalapatis 
786*6c3e8a4dSEmil Tsalapatis 	if (!rbtree->root)
787*6c3e8a4dSEmil Tsalapatis 		return -ENOENT;
788*6c3e8a4dSEmil Tsalapatis 
789*6c3e8a4dSEmil Tsalapatis 	node = rbnode_find(rbtree->root, key);
790*6c3e8a4dSEmil Tsalapatis 	if (!node || node->key != key)
791*6c3e8a4dSEmil Tsalapatis 		return -ENOENT;
792*6c3e8a4dSEmil Tsalapatis 
793*6c3e8a4dSEmil Tsalapatis 	return rb_node_remove(rbtree, node);
794*6c3e8a4dSEmil Tsalapatis }
795*6c3e8a4dSEmil Tsalapatis 
796*6c3e8a4dSEmil Tsalapatis __weak
797*6c3e8a4dSEmil Tsalapatis int rb_pop(struct rbtree __arena *rbtree, u64 *key, u64 *value)
798*6c3e8a4dSEmil Tsalapatis {
799*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *node;
800*6c3e8a4dSEmil Tsalapatis 
801*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
802*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
803*6c3e8a4dSEmil Tsalapatis 
804*6c3e8a4dSEmil Tsalapatis 	if (!rbtree->root)
805*6c3e8a4dSEmil Tsalapatis 		return -ENOENT;
806*6c3e8a4dSEmil Tsalapatis 
807*6c3e8a4dSEmil Tsalapatis 	if (rbtree->alloc != RB_ALLOC)
808*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
809*6c3e8a4dSEmil Tsalapatis 
810*6c3e8a4dSEmil Tsalapatis 	node = rbnode_least(rbtree->root);
811*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!node))
812*6c3e8a4dSEmil Tsalapatis 		return -ENOENT;
813*6c3e8a4dSEmil Tsalapatis 
814*6c3e8a4dSEmil Tsalapatis 	if (key)
815*6c3e8a4dSEmil Tsalapatis 		*key = node->key;
816*6c3e8a4dSEmil Tsalapatis 	if (value)
817*6c3e8a4dSEmil Tsalapatis 		*value = node->value;
818*6c3e8a4dSEmil Tsalapatis 
819*6c3e8a4dSEmil Tsalapatis 	return rb_node_remove(rbtree, node);
820*6c3e8a4dSEmil Tsalapatis }
821*6c3e8a4dSEmil Tsalapatis 
822*6c3e8a4dSEmil Tsalapatis inline void rbnode_print(size_t depth, struct rbnode __arena *rbn)
823*6c3e8a4dSEmil Tsalapatis {
824*6c3e8a4dSEmil Tsalapatis 	arena_stderr("[DEPTH %d] %p (%s)\n PARENT %p", depth, rbn, rbn->is_red ? "red" : "black", rbn->parent);
825*6c3e8a4dSEmil Tsalapatis 	arena_stderr("\tKV (%ld, %ld)\n LEFT %p RIGHT %p]\n", rbn->key, rbn->value, rbn->left, rbn->right);
826*6c3e8a4dSEmil Tsalapatis }
827*6c3e8a4dSEmil Tsalapatis 
828*6c3e8a4dSEmil Tsalapatis enum rb_print_state {
829*6c3e8a4dSEmil Tsalapatis 	RB_NONE_VISITED,
830*6c3e8a4dSEmil Tsalapatis 	RB_LEFT_VISITED,
831*6c3e8a4dSEmil Tsalapatis 	RB_RIGHT_VISITED,
832*6c3e8a4dSEmil Tsalapatis };
833*6c3e8a4dSEmil Tsalapatis 
834*6c3e8a4dSEmil Tsalapatis __weak
835*6c3e8a4dSEmil Tsalapatis enum rb_print_state rb_print_next_state(struct rbnode __arena *rbnode,
836*6c3e8a4dSEmil Tsalapatis 					enum rb_print_state state, u64 *next)
837*6c3e8a4dSEmil Tsalapatis {
838*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!next))
839*6c3e8a4dSEmil Tsalapatis 		return RB_NONE_VISITED;
840*6c3e8a4dSEmil Tsalapatis 
841*6c3e8a4dSEmil Tsalapatis 	switch (state) {
842*6c3e8a4dSEmil Tsalapatis 	case RB_NONE_VISITED:
843*6c3e8a4dSEmil Tsalapatis 		if (rbnode->left) {
844*6c3e8a4dSEmil Tsalapatis 			*next = (u64)rbnode->left;
845*6c3e8a4dSEmil Tsalapatis 			state = RB_LEFT_VISITED;
846*6c3e8a4dSEmil Tsalapatis 			break;
847*6c3e8a4dSEmil Tsalapatis 		}
848*6c3e8a4dSEmil Tsalapatis 
849*6c3e8a4dSEmil Tsalapatis 		/* FALLTHROUGH */
850*6c3e8a4dSEmil Tsalapatis 
851*6c3e8a4dSEmil Tsalapatis 	case RB_LEFT_VISITED:
852*6c3e8a4dSEmil Tsalapatis 		if (rbnode->right) {
853*6c3e8a4dSEmil Tsalapatis 			*next = (u64)rbnode->right;
854*6c3e8a4dSEmil Tsalapatis 			state = RB_RIGHT_VISITED;
855*6c3e8a4dSEmil Tsalapatis 			break;
856*6c3e8a4dSEmil Tsalapatis 		}
857*6c3e8a4dSEmil Tsalapatis 
858*6c3e8a4dSEmil Tsalapatis 		/* FALLTHROUGH */
859*6c3e8a4dSEmil Tsalapatis 
860*6c3e8a4dSEmil Tsalapatis 	default:
861*6c3e8a4dSEmil Tsalapatis 		*next = 0;
862*6c3e8a4dSEmil Tsalapatis 		state = RB_RIGHT_VISITED;
863*6c3e8a4dSEmil Tsalapatis 	}
864*6c3e8a4dSEmil Tsalapatis 
865*6c3e8a4dSEmil Tsalapatis 	return state;
866*6c3e8a4dSEmil Tsalapatis }
867*6c3e8a4dSEmil Tsalapatis 
868*6c3e8a4dSEmil Tsalapatis __weak
869*6c3e8a4dSEmil Tsalapatis int rb_print_pop_up(struct rbnode __arena **rbnodep, u8 *depthp, enum rb_print_state (*stack)[RB_MAXLVL_PRINT], enum rb_print_state *state)
870*6c3e8a4dSEmil Tsalapatis {
871*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *rbnode;
872*6c3e8a4dSEmil Tsalapatis 	volatile u8 depth;
873*6c3e8a4dSEmil Tsalapatis 	int j;
874*6c3e8a4dSEmil Tsalapatis 
875*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbnodep || !depthp || !stack || !state))
876*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
877*6c3e8a4dSEmil Tsalapatis 
878*6c3e8a4dSEmil Tsalapatis 	rbnode = *rbnodep;
879*6c3e8a4dSEmil Tsalapatis 	depth = *depthp;
880*6c3e8a4dSEmil Tsalapatis 
881*6c3e8a4dSEmil Tsalapatis 	for (j = 0; j < RB_MAXLVL_PRINT && can_loop; j++) {
882*6c3e8a4dSEmil Tsalapatis 		if (*state != RB_RIGHT_VISITED)
883*6c3e8a4dSEmil Tsalapatis 			break;
884*6c3e8a4dSEmil Tsalapatis 
885*6c3e8a4dSEmil Tsalapatis 		depth -= 1;
886*6c3e8a4dSEmil Tsalapatis 		if (depth < 0 || depth >= RB_MAXLVL_PRINT)
887*6c3e8a4dSEmil Tsalapatis 			break;
888*6c3e8a4dSEmil Tsalapatis 
889*6c3e8a4dSEmil Tsalapatis 		*state = (*stack)[depth % RB_MAXLVL_PRINT];
890*6c3e8a4dSEmil Tsalapatis 		rbnode = rbnode->parent;
891*6c3e8a4dSEmil Tsalapatis 	}
892*6c3e8a4dSEmil Tsalapatis 
893*6c3e8a4dSEmil Tsalapatis 	*rbnodep = rbnode;
894*6c3e8a4dSEmil Tsalapatis 	*depthp = depth;
895*6c3e8a4dSEmil Tsalapatis 
896*6c3e8a4dSEmil Tsalapatis 	return 0;
897*6c3e8a4dSEmil Tsalapatis }
898*6c3e8a4dSEmil Tsalapatis 
899*6c3e8a4dSEmil Tsalapatis __weak
900*6c3e8a4dSEmil Tsalapatis int rb_print(struct rbtree __arena *rbtree)
901*6c3e8a4dSEmil Tsalapatis {
902*6c3e8a4dSEmil Tsalapatis 	enum rb_print_state stack[RB_MAXLVL_PRINT];
903*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *rbnode = rbtree->root;
904*6c3e8a4dSEmil Tsalapatis 	enum rb_print_state state;
905*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *next;
906*6c3e8a4dSEmil Tsalapatis 	u64 next_addr;
907*6c3e8a4dSEmil Tsalapatis 	u8 depth;
908*6c3e8a4dSEmil Tsalapatis 	int ret;
909*6c3e8a4dSEmil Tsalapatis 
910*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
911*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
912*6c3e8a4dSEmil Tsalapatis 
913*6c3e8a4dSEmil Tsalapatis 	depth = 0;
914*6c3e8a4dSEmil Tsalapatis 	state = RB_NONE_VISITED;
915*6c3e8a4dSEmil Tsalapatis 
916*6c3e8a4dSEmil Tsalapatis 	arena_stderr("=== RB TREE START ===\n");
917*6c3e8a4dSEmil Tsalapatis 
918*6c3e8a4dSEmil Tsalapatis 	if (!rbtree->root)
919*6c3e8a4dSEmil Tsalapatis 		goto out;
920*6c3e8a4dSEmil Tsalapatis 
921*6c3e8a4dSEmil Tsalapatis 	/* Even with can_loop, the verifier doesn't like infinite loops. */
922*6c3e8a4dSEmil Tsalapatis 	while (can_loop) {
923*6c3e8a4dSEmil Tsalapatis 		if (state == RB_NONE_VISITED)
924*6c3e8a4dSEmil Tsalapatis 			rbnode_print(depth, rbnode);
925*6c3e8a4dSEmil Tsalapatis 
926*6c3e8a4dSEmil Tsalapatis 		/* Find which child to traverse next. */
927*6c3e8a4dSEmil Tsalapatis 		state = rb_print_next_state(rbnode, state, &next_addr);
928*6c3e8a4dSEmil Tsalapatis 		next = (struct rbnode __arena *)next_addr;
929*6c3e8a4dSEmil Tsalapatis 
930*6c3e8a4dSEmil Tsalapatis 		/* Child found. Store the node state and go on. */
931*6c3e8a4dSEmil Tsalapatis 		if (next) {
932*6c3e8a4dSEmil Tsalapatis 			if (depth < 0 || depth >= RB_MAXLVL_PRINT)
933*6c3e8a4dSEmil Tsalapatis 				return 0;
934*6c3e8a4dSEmil Tsalapatis 
935*6c3e8a4dSEmil Tsalapatis 			stack[depth++] = state;
936*6c3e8a4dSEmil Tsalapatis 
937*6c3e8a4dSEmil Tsalapatis 			rbnode = next;
938*6c3e8a4dSEmil Tsalapatis 			state = RB_NONE_VISITED;
939*6c3e8a4dSEmil Tsalapatis 
940*6c3e8a4dSEmil Tsalapatis 			continue;
941*6c3e8a4dSEmil Tsalapatis 		}
942*6c3e8a4dSEmil Tsalapatis 
943*6c3e8a4dSEmil Tsalapatis 		/* Otherwise, go as far up as possible. */
944*6c3e8a4dSEmil Tsalapatis 		ret = rb_print_pop_up(&rbnode, &depth, &stack, &state);
945*6c3e8a4dSEmil Tsalapatis 		if (ret)
946*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
947*6c3e8a4dSEmil Tsalapatis 
948*6c3e8a4dSEmil Tsalapatis 		if (depth < 0 || depth >= RB_MAXLVL_PRINT) {
949*6c3e8a4dSEmil Tsalapatis 			arena_stderr("=== RB TREE END (depth %d\n)===", depth);
950*6c3e8a4dSEmil Tsalapatis 			return 0;
951*6c3e8a4dSEmil Tsalapatis 		}
952*6c3e8a4dSEmil Tsalapatis 
953*6c3e8a4dSEmil Tsalapatis 	}
954*6c3e8a4dSEmil Tsalapatis 
955*6c3e8a4dSEmil Tsalapatis out:
956*6c3e8a4dSEmil Tsalapatis 	arena_stderr("=== RB TREE END ===\n");
957*6c3e8a4dSEmil Tsalapatis 
958*6c3e8a4dSEmil Tsalapatis 	return 0;
959*6c3e8a4dSEmil Tsalapatis }
960*6c3e8a4dSEmil Tsalapatis 
961*6c3e8a4dSEmil Tsalapatis __weak
962*6c3e8a4dSEmil Tsalapatis int rb_integrity_check(struct rbtree __arena *rbtree)
963*6c3e8a4dSEmil Tsalapatis {
964*6c3e8a4dSEmil Tsalapatis 	enum rb_print_state stack[RB_MAXLVL_PRINT];
965*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *rbnode = rbtree->root;
966*6c3e8a4dSEmil Tsalapatis 	enum rb_print_state state;
967*6c3e8a4dSEmil Tsalapatis 	struct rbnode __arena *next;
968*6c3e8a4dSEmil Tsalapatis 	u64 next_addr;
969*6c3e8a4dSEmil Tsalapatis 	u8 depth;
970*6c3e8a4dSEmil Tsalapatis 	int ret;
971*6c3e8a4dSEmil Tsalapatis 
972*6c3e8a4dSEmil Tsalapatis 	if (unlikely(!rbtree))
973*6c3e8a4dSEmil Tsalapatis 		return -EINVAL;
974*6c3e8a4dSEmil Tsalapatis 
975*6c3e8a4dSEmil Tsalapatis 	if (!rbtree->root)
976*6c3e8a4dSEmil Tsalapatis 		return 0;
977*6c3e8a4dSEmil Tsalapatis 
978*6c3e8a4dSEmil Tsalapatis 	depth = 0;
979*6c3e8a4dSEmil Tsalapatis 	state = RB_NONE_VISITED;
980*6c3e8a4dSEmil Tsalapatis 
981*6c3e8a4dSEmil Tsalapatis 	/* Even with can_loop, the verifier doesn't like infinite loops. */
982*6c3e8a4dSEmil Tsalapatis 	while (can_loop) {
983*6c3e8a4dSEmil Tsalapatis 		if (rbnode->parent && rbnode->parent->left != rbnode
984*6c3e8a4dSEmil Tsalapatis 			&& rbnode->parent->right != rbnode) {
985*6c3e8a4dSEmil Tsalapatis 			arena_stderr("WARNING: Inconsistent tree. Parent %p has no child %p\n", rbnode->parent, rbnode);
986*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
987*6c3e8a4dSEmil Tsalapatis 		}
988*6c3e8a4dSEmil Tsalapatis 
989*6c3e8a4dSEmil Tsalapatis 		if (rbnode->parent == rbnode) {
990*6c3e8a4dSEmil Tsalapatis 			arena_stderr("WARNING: Inconsistent tree, node %p is its own parent\n", rbnode);
991*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
992*6c3e8a4dSEmil Tsalapatis 		}
993*6c3e8a4dSEmil Tsalapatis 
994*6c3e8a4dSEmil Tsalapatis 		if (rbnode->left == rbnode) {
995*6c3e8a4dSEmil Tsalapatis 			arena_stderr("WARNING: Inconsistent tree, node %p is its own left child\n", rbnode);
996*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
997*6c3e8a4dSEmil Tsalapatis 		}
998*6c3e8a4dSEmil Tsalapatis 
999*6c3e8a4dSEmil Tsalapatis 		if (rbnode->right == rbnode) {
1000*6c3e8a4dSEmil Tsalapatis 			arena_stderr("WARNING: Inconsistent tree, node %p is its own right child\n", rbnode);
1001*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
1002*6c3e8a4dSEmil Tsalapatis 		}
1003*6c3e8a4dSEmil Tsalapatis 
1004*6c3e8a4dSEmil Tsalapatis 		if (rbnode->is_red) {
1005*6c3e8a4dSEmil Tsalapatis 			if (rbnode->left && rbnode->left->is_red) {
1006*6c3e8a4dSEmil Tsalapatis 				arena_stderr("WARNING: Inconsistent tree. Parent has %p has red child %p\n", rbnode, rbnode->left);
1007*6c3e8a4dSEmil Tsalapatis 				return -EINVAL;
1008*6c3e8a4dSEmil Tsalapatis 			}
1009*6c3e8a4dSEmil Tsalapatis 			if (rbnode->right && rbnode->right->is_red) {
1010*6c3e8a4dSEmil Tsalapatis 				arena_stderr("WARNING: Inconsistent tree. Parent has %p has red child %p\n", rbnode, rbnode->right);
1011*6c3e8a4dSEmil Tsalapatis 				return -EINVAL;
1012*6c3e8a4dSEmil Tsalapatis 			}
1013*6c3e8a4dSEmil Tsalapatis 		} else if (rbnode->parent && rbnode->parent->child[1 - rbnode_dir(rbnode)] == NULL) {
1014*6c3e8a4dSEmil Tsalapatis 			arena_stderr("WARNING: Inconsistent tree. Black node %p has no sibling\n", rbnode);
1015*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
1016*6c3e8a4dSEmil Tsalapatis 		}
1017*6c3e8a4dSEmil Tsalapatis 
1018*6c3e8a4dSEmil Tsalapatis 		/* Find which child to traverse next. */
1019*6c3e8a4dSEmil Tsalapatis 		state = rb_print_next_state(rbnode, state, &next_addr);
1020*6c3e8a4dSEmil Tsalapatis 		next = (struct rbnode __arena *)next_addr;
1021*6c3e8a4dSEmil Tsalapatis 
1022*6c3e8a4dSEmil Tsalapatis 		/* Child found. Store the node state and go on. */
1023*6c3e8a4dSEmil Tsalapatis 		if (next) {
1024*6c3e8a4dSEmil Tsalapatis 			if (depth < 0 || depth >= RB_MAXLVL_PRINT)
1025*6c3e8a4dSEmil Tsalapatis 				return 0;
1026*6c3e8a4dSEmil Tsalapatis 
1027*6c3e8a4dSEmil Tsalapatis 			stack[depth++] = state;
1028*6c3e8a4dSEmil Tsalapatis 
1029*6c3e8a4dSEmil Tsalapatis 			rbnode = next;
1030*6c3e8a4dSEmil Tsalapatis 			state = RB_NONE_VISITED;
1031*6c3e8a4dSEmil Tsalapatis 
1032*6c3e8a4dSEmil Tsalapatis 			continue;
1033*6c3e8a4dSEmil Tsalapatis 		}
1034*6c3e8a4dSEmil Tsalapatis 
1035*6c3e8a4dSEmil Tsalapatis 		/* Otherwise, go as far up as possible. */
1036*6c3e8a4dSEmil Tsalapatis 		ret = rb_print_pop_up(&rbnode, &depth, &stack, &state);
1037*6c3e8a4dSEmil Tsalapatis 		if (ret)
1038*6c3e8a4dSEmil Tsalapatis 			return -EINVAL;
1039*6c3e8a4dSEmil Tsalapatis 
1040*6c3e8a4dSEmil Tsalapatis 		if (depth < 0 || depth >= RB_MAXLVL_PRINT) {
1041*6c3e8a4dSEmil Tsalapatis 			return 0;
1042*6c3e8a4dSEmil Tsalapatis 		}
1043*6c3e8a4dSEmil Tsalapatis 
1044*6c3e8a4dSEmil Tsalapatis 	}
1045*6c3e8a4dSEmil Tsalapatis 
1046*6c3e8a4dSEmil Tsalapatis 	return 0;
1047*6c3e8a4dSEmil Tsalapatis }
1048