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