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