1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2013 EMC Corp. 5 * Copyright (c) 2011 Jeffrey Roberson <jeff@freebsd.org> 6 * Copyright (c) 2008 Mayur Shardul <mayur.shardul@gmail.com> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 /* 33 * Path-compressed radix trie implementation. 34 * 35 * The implementation takes into account the following rationale: 36 * - Size of the nodes should be as small as possible but still big enough 37 * to avoid a large maximum depth for the trie. This is a balance 38 * between the necessity to not wire too much physical memory for the nodes 39 * and the necessity to avoid too much cache pollution during the trie 40 * operations. 41 * - There is not a huge bias toward the number of lookup operations over 42 * the number of insert and remove operations. This basically implies 43 * that optimizations supposedly helping one operation but hurting the 44 * other might be carefully evaluated. 45 * - On average not many nodes are expected to be fully populated, hence 46 * level compression may just complicate things. 47 */ 48 49 #include <sys/cdefs.h> 50 __FBSDID("$FreeBSD$"); 51 52 #include "opt_ddb.h" 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/kernel.h> 57 #include <sys/libkern.h> 58 #include <sys/pctrie.h> 59 #include <sys/proc.h> /* smr.h depends on struct thread. */ 60 #include <sys/smr.h> 61 #include <sys/smr_types.h> 62 63 #ifdef DDB 64 #include <ddb/ddb.h> 65 #endif 66 67 #define PCTRIE_MASK (PCTRIE_COUNT - 1) 68 #define PCTRIE_LIMIT (howmany(sizeof(uint64_t) * NBBY, PCTRIE_WIDTH) - 1) 69 70 /* Flag bits stored in node pointers. */ 71 #define PCTRIE_ISLEAF 0x1 72 #define PCTRIE_FLAGS 0x1 73 #define PCTRIE_PAD PCTRIE_FLAGS 74 75 /* Returns one unit associated with specified level. */ 76 #define PCTRIE_UNITLEVEL(lev) \ 77 ((uint64_t)1 << ((lev) * PCTRIE_WIDTH)) 78 79 struct pctrie_node; 80 typedef SMR_POINTER(struct pctrie_node *) smr_pctnode_t; 81 82 struct pctrie_node { 83 uint64_t pn_owner; /* Owner of record. */ 84 uint16_t pn_count; /* Valid children. */ 85 uint8_t pn_clev; /* Current level. */ 86 int8_t pn_last; /* Zero last ptr. */ 87 smr_pctnode_t pn_child[PCTRIE_COUNT]; /* Child nodes. */ 88 }; 89 90 enum pctrie_access { PCTRIE_SMR, PCTRIE_LOCKED, PCTRIE_UNSERIALIZED }; 91 92 static __inline void pctrie_node_store(smr_pctnode_t *p, void *val, 93 enum pctrie_access access); 94 95 /* 96 * Allocate a node. Pre-allocation should ensure that the request 97 * will always be satisfied. 98 */ 99 static struct pctrie_node * 100 pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t owner, 101 uint16_t count, uint16_t clevel) 102 { 103 struct pctrie_node *node; 104 105 node = allocfn(ptree); 106 if (node == NULL) 107 return (NULL); 108 109 /* 110 * We want to clear the last child pointer after the final section 111 * has exited so lookup can not return false negatives. It is done 112 * here because it will be cache-cold in the dtor callback. 113 */ 114 if (node->pn_last != 0) { 115 pctrie_node_store(&node->pn_child[node->pn_last - 1], NULL, 116 PCTRIE_UNSERIALIZED); 117 node->pn_last = 0; 118 } 119 node->pn_owner = owner; 120 node->pn_count = count; 121 node->pn_clev = clevel; 122 return (node); 123 } 124 125 /* 126 * Free radix node. 127 */ 128 static __inline void 129 pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node, 130 pctrie_free_t freefn, int8_t last) 131 { 132 #ifdef INVARIANTS 133 int slot; 134 135 KASSERT(node->pn_count == 0, 136 ("pctrie_node_put: node %p has %d children", node, 137 node->pn_count)); 138 for (slot = 0; slot < PCTRIE_COUNT; slot++) { 139 if (slot == last) 140 continue; 141 KASSERT(smr_unserialized_load(&node->pn_child[slot], true) == 142 NULL, ("pctrie_node_put: node %p has a child", node)); 143 } 144 #endif 145 node->pn_last = last + 1; 146 freefn(ptree, node); 147 } 148 149 /* 150 * Return the position in the array for a given level. 151 */ 152 static __inline int 153 pctrie_slot(uint64_t index, uint16_t level) 154 { 155 156 return ((index >> (level * PCTRIE_WIDTH)) & PCTRIE_MASK); 157 } 158 159 /* Computes the key (index) with the low-order 'level' radix-digits zeroed. */ 160 static __inline uint64_t 161 pctrie_trimkey(uint64_t index, uint16_t level) 162 { 163 return (index & -PCTRIE_UNITLEVEL(level)); 164 } 165 166 /* 167 * Fetch a node pointer from a slot. 168 */ 169 static __inline struct pctrie_node * 170 pctrie_node_load(smr_pctnode_t *p, smr_t smr, enum pctrie_access access) 171 { 172 switch (access) { 173 case PCTRIE_UNSERIALIZED: 174 return (smr_unserialized_load(p, true)); 175 case PCTRIE_LOCKED: 176 return (smr_serialized_load(p, true)); 177 case PCTRIE_SMR: 178 return (smr_entered_load(p, smr)); 179 } 180 __assert_unreachable(); 181 } 182 183 static __inline void 184 pctrie_node_store(smr_pctnode_t *p, void *v, enum pctrie_access access) 185 { 186 switch (access) { 187 case PCTRIE_UNSERIALIZED: 188 smr_unserialized_store(p, v, true); 189 break; 190 case PCTRIE_LOCKED: 191 smr_serialized_store(p, v, true); 192 break; 193 case PCTRIE_SMR: 194 panic("%s: Not supported in SMR section.", __func__); 195 break; 196 default: 197 __assert_unreachable(); 198 break; 199 } 200 } 201 202 /* 203 * Get the root node for a tree. 204 */ 205 static __inline struct pctrie_node * 206 pctrie_root_load(struct pctrie *ptree, smr_t smr, enum pctrie_access access) 207 { 208 return (pctrie_node_load((smr_pctnode_t *)&ptree->pt_root, smr, access)); 209 } 210 211 /* 212 * Set the root node for a tree. 213 */ 214 static __inline void 215 pctrie_root_store(struct pctrie *ptree, struct pctrie_node *node, 216 enum pctrie_access access) 217 { 218 pctrie_node_store((smr_pctnode_t *)&ptree->pt_root, node, access); 219 } 220 221 /* 222 * Returns TRUE if the specified node is a leaf and FALSE otherwise. 223 */ 224 static __inline bool 225 pctrie_isleaf(struct pctrie_node *node) 226 { 227 228 return (((uintptr_t)node & PCTRIE_ISLEAF) != 0); 229 } 230 231 /* 232 * Returns the associated val extracted from node. 233 */ 234 static __inline uint64_t * 235 pctrie_toval(struct pctrie_node *node) 236 { 237 238 return ((uint64_t *)((uintptr_t)node & ~PCTRIE_FLAGS)); 239 } 240 241 /* 242 * Adds the val as a child of the provided node. 243 */ 244 static __inline void 245 pctrie_addval(struct pctrie_node *node, uint64_t index, uint16_t clev, 246 uint64_t *val, enum pctrie_access access) 247 { 248 int slot; 249 250 slot = pctrie_slot(index, clev); 251 pctrie_node_store(&node->pn_child[slot], 252 (void *)((uintptr_t)val | PCTRIE_ISLEAF), access); 253 } 254 255 /* 256 * Returns the level where two keys differ. 257 * It cannot accept 2 equal keys. 258 */ 259 static __inline uint16_t 260 pctrie_keydiff(uint64_t index1, uint64_t index2) 261 { 262 263 KASSERT(index1 != index2, ("%s: passing the same key value %jx", 264 __func__, (uintmax_t)index1)); 265 CTASSERT(sizeof(long long) >= sizeof(uint64_t)); 266 267 /* 268 * From the highest-order bit where the indexes differ, 269 * compute the highest level in the trie where they differ. 270 */ 271 return ((flsll(index1 ^ index2) - 1) / PCTRIE_WIDTH); 272 } 273 274 /* 275 * Returns TRUE if it can be determined that key does not belong to the 276 * specified node. Otherwise, returns FALSE. 277 */ 278 static __inline bool 279 pctrie_keybarr(struct pctrie_node *node, uint64_t idx) 280 { 281 282 if (node->pn_clev < PCTRIE_LIMIT) { 283 idx = pctrie_trimkey(idx, node->pn_clev + 1); 284 return (idx != node->pn_owner); 285 } 286 return (false); 287 } 288 289 /* 290 * Internal helper for pctrie_reclaim_allnodes(). 291 * This function is recursive. 292 */ 293 static void 294 pctrie_reclaim_allnodes_int(struct pctrie *ptree, struct pctrie_node *node, 295 pctrie_free_t freefn) 296 { 297 struct pctrie_node *child; 298 int slot; 299 300 KASSERT(node->pn_count <= PCTRIE_COUNT, 301 ("pctrie_reclaim_allnodes_int: bad count in node %p", node)); 302 for (slot = 0; node->pn_count != 0; slot++) { 303 child = pctrie_node_load(&node->pn_child[slot], NULL, 304 PCTRIE_UNSERIALIZED); 305 if (child == NULL) 306 continue; 307 if (!pctrie_isleaf(child)) 308 pctrie_reclaim_allnodes_int(ptree, child, freefn); 309 pctrie_node_store(&node->pn_child[slot], NULL, 310 PCTRIE_UNSERIALIZED); 311 node->pn_count--; 312 } 313 pctrie_node_put(ptree, node, freefn, -1); 314 } 315 316 /* 317 * pctrie node zone initializer. 318 */ 319 int 320 pctrie_zone_init(void *mem, int size __unused, int flags __unused) 321 { 322 struct pctrie_node *node; 323 324 node = mem; 325 node->pn_last = 0; 326 memset(node->pn_child, 0, sizeof(node->pn_child)); 327 return (0); 328 } 329 330 size_t 331 pctrie_node_size(void) 332 { 333 334 return (sizeof(struct pctrie_node)); 335 } 336 337 /* 338 * Inserts the key-value pair into the trie. 339 * Panics if the key already exists. 340 */ 341 int 342 pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) 343 { 344 uint64_t index, newind; 345 struct pctrie_node *node, *tmp; 346 smr_pctnode_t *parentp; 347 uint64_t *m; 348 int slot; 349 uint16_t clev; 350 351 index = *val; 352 353 /* 354 * The owner of record for root is not really important because it 355 * will never be used. 356 */ 357 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 358 if (node == NULL) { 359 ptree->pt_root = (uintptr_t)val | PCTRIE_ISLEAF; 360 return (0); 361 } 362 parentp = (smr_pctnode_t *)&ptree->pt_root; 363 for (;;) { 364 if (pctrie_isleaf(node)) { 365 m = pctrie_toval(node); 366 if (*m == index) 367 panic("%s: key %jx is already present", 368 __func__, (uintmax_t)index); 369 clev = pctrie_keydiff(*m, index); 370 tmp = pctrie_node_get(ptree, allocfn, 371 pctrie_trimkey(index, clev + 1), 2, clev); 372 if (tmp == NULL) 373 return (ENOMEM); 374 /* These writes are not yet visible due to ordering. */ 375 pctrie_addval(tmp, index, clev, val, 376 PCTRIE_UNSERIALIZED); 377 pctrie_addval(tmp, *m, clev, m, PCTRIE_UNSERIALIZED); 378 /* Synchronize to make leaf visible. */ 379 pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); 380 return (0); 381 } else if (pctrie_keybarr(node, index)) 382 break; 383 slot = pctrie_slot(index, node->pn_clev); 384 parentp = &node->pn_child[slot]; 385 tmp = pctrie_node_load(parentp, NULL, PCTRIE_LOCKED); 386 if (tmp == NULL) { 387 node->pn_count++; 388 pctrie_addval(node, index, node->pn_clev, val, 389 PCTRIE_LOCKED); 390 return (0); 391 } 392 node = tmp; 393 } 394 395 /* 396 * A new node is needed because the right insertion level is reached. 397 * Setup the new intermediate node and add the 2 children: the 398 * new object and the older edge. 399 */ 400 newind = node->pn_owner; 401 clev = pctrie_keydiff(newind, index); 402 tmp = pctrie_node_get(ptree, allocfn, 403 pctrie_trimkey(index, clev + 1), 2, clev); 404 if (tmp == NULL) 405 return (ENOMEM); 406 slot = pctrie_slot(newind, clev); 407 /* These writes are not yet visible due to ordering. */ 408 pctrie_addval(tmp, index, clev, val, PCTRIE_UNSERIALIZED); 409 pctrie_node_store(&tmp->pn_child[slot], node, PCTRIE_UNSERIALIZED); 410 /* Synchronize to make the above visible. */ 411 pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); 412 413 return (0); 414 } 415 416 /* 417 * Returns the value stored at the index. If the index is not present, 418 * NULL is returned. 419 */ 420 static __always_inline uint64_t * 421 _pctrie_lookup(struct pctrie *ptree, uint64_t index, smr_t smr, 422 enum pctrie_access access) 423 { 424 struct pctrie_node *node; 425 uint64_t *m; 426 int slot; 427 428 node = pctrie_root_load(ptree, smr, access); 429 while (node != NULL) { 430 if (pctrie_isleaf(node)) { 431 m = pctrie_toval(node); 432 if (*m == index) 433 return (m); 434 break; 435 } 436 if (pctrie_keybarr(node, index)) 437 break; 438 slot = pctrie_slot(index, node->pn_clev); 439 node = pctrie_node_load(&node->pn_child[slot], smr, access); 440 } 441 return (NULL); 442 } 443 444 /* 445 * Returns the value stored at the index, assuming access is externally 446 * synchronized by a lock. 447 * 448 * If the index is not present, NULL is returned. 449 */ 450 uint64_t * 451 pctrie_lookup(struct pctrie *ptree, uint64_t index) 452 { 453 return (_pctrie_lookup(ptree, index, NULL, PCTRIE_LOCKED)); 454 } 455 456 /* 457 * Returns the value stored at the index without requiring an external lock. 458 * 459 * If the index is not present, NULL is returned. 460 */ 461 uint64_t * 462 pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t index, smr_t smr) 463 { 464 uint64_t *res; 465 466 smr_enter(smr); 467 res = _pctrie_lookup(ptree, index, smr, PCTRIE_SMR); 468 smr_exit(smr); 469 return (res); 470 } 471 472 /* 473 * Look up the nearest entry at a position bigger than or equal to index, 474 * assuming access is externally synchronized by a lock. 475 */ 476 uint64_t * 477 pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) 478 { 479 struct pctrie_node *stack[PCTRIE_LIMIT]; 480 uint64_t inc; 481 uint64_t *m; 482 struct pctrie_node *child, *node; 483 #ifdef INVARIANTS 484 int loops = 0; 485 #endif 486 unsigned tos; 487 int slot; 488 489 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 490 if (node == NULL) 491 return (NULL); 492 else if (pctrie_isleaf(node)) { 493 m = pctrie_toval(node); 494 if (*m >= index) 495 return (m); 496 else 497 return (NULL); 498 } 499 tos = 0; 500 for (;;) { 501 /* 502 * If the keys differ before the current bisection node, 503 * then the search key might rollback to the earliest 504 * available bisection node or to the smallest key 505 * in the current node (if the owner is greater than the 506 * search key). 507 */ 508 if (pctrie_keybarr(node, index)) { 509 if (index > node->pn_owner) { 510 ascend: 511 KASSERT(++loops < 1000, 512 ("pctrie_lookup_ge: too many loops")); 513 514 /* 515 * Pop nodes from the stack until either the 516 * stack is empty or a node that could have a 517 * matching descendant is found. 518 */ 519 do { 520 if (tos == 0) 521 return (NULL); 522 node = stack[--tos]; 523 } while (pctrie_slot(index, 524 node->pn_clev) == (PCTRIE_COUNT - 1)); 525 526 /* 527 * The following computation cannot overflow 528 * because index's slot at the current level 529 * is less than PCTRIE_COUNT - 1. 530 */ 531 index = pctrie_trimkey(index, 532 node->pn_clev); 533 index += PCTRIE_UNITLEVEL(node->pn_clev); 534 } else 535 index = node->pn_owner; 536 KASSERT(!pctrie_keybarr(node, index), 537 ("pctrie_lookup_ge: keybarr failed")); 538 } 539 slot = pctrie_slot(index, node->pn_clev); 540 child = pctrie_node_load(&node->pn_child[slot], NULL, 541 PCTRIE_LOCKED); 542 if (pctrie_isleaf(child)) { 543 m = pctrie_toval(child); 544 if (*m >= index) 545 return (m); 546 } else if (child != NULL) 547 goto descend; 548 549 /* 550 * Look for an available edge or val within the current 551 * bisection node. 552 */ 553 if (slot < (PCTRIE_COUNT - 1)) { 554 inc = PCTRIE_UNITLEVEL(node->pn_clev); 555 index = pctrie_trimkey(index, node->pn_clev); 556 do { 557 index += inc; 558 slot++; 559 child = pctrie_node_load(&node->pn_child[slot], 560 NULL, PCTRIE_LOCKED); 561 if (pctrie_isleaf(child)) { 562 m = pctrie_toval(child); 563 if (*m >= index) 564 return (m); 565 } else if (child != NULL) 566 goto descend; 567 } while (slot < (PCTRIE_COUNT - 1)); 568 } 569 KASSERT(child == NULL || pctrie_isleaf(child), 570 ("pctrie_lookup_ge: child is radix node")); 571 572 /* 573 * If a value or edge greater than the search slot is not found 574 * in the current node, ascend to the next higher-level node. 575 */ 576 goto ascend; 577 descend: 578 KASSERT(node->pn_clev > 0, 579 ("pctrie_lookup_ge: pushing leaf's parent")); 580 KASSERT(tos < PCTRIE_LIMIT, 581 ("pctrie_lookup_ge: stack overflow")); 582 stack[tos++] = node; 583 node = child; 584 } 585 } 586 587 /* 588 * Look up the nearest entry at a position less than or equal to index, 589 * assuming access is externally synchronized by a lock. 590 */ 591 uint64_t * 592 pctrie_lookup_le(struct pctrie *ptree, uint64_t index) 593 { 594 struct pctrie_node *stack[PCTRIE_LIMIT]; 595 uint64_t inc; 596 uint64_t *m; 597 struct pctrie_node *child, *node; 598 #ifdef INVARIANTS 599 int loops = 0; 600 #endif 601 unsigned tos; 602 int slot; 603 604 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 605 if (node == NULL) 606 return (NULL); 607 else if (pctrie_isleaf(node)) { 608 m = pctrie_toval(node); 609 if (*m <= index) 610 return (m); 611 else 612 return (NULL); 613 } 614 tos = 0; 615 for (;;) { 616 /* 617 * If the keys differ before the current bisection node, 618 * then the search key might rollback to the earliest 619 * available bisection node or to the largest key 620 * in the current node (if the owner is smaller than the 621 * search key). 622 */ 623 if (pctrie_keybarr(node, index)) { 624 if (index > node->pn_owner) { 625 index = node->pn_owner + PCTRIE_COUNT * 626 PCTRIE_UNITLEVEL(node->pn_clev); 627 } else { 628 ascend: 629 KASSERT(++loops < 1000, 630 ("pctrie_lookup_le: too many loops")); 631 632 /* 633 * Pop nodes from the stack until either the 634 * stack is empty or a node that could have a 635 * matching descendant is found. 636 */ 637 do { 638 if (tos == 0) 639 return (NULL); 640 node = stack[--tos]; 641 } while (pctrie_slot(index, 642 node->pn_clev) == 0); 643 644 /* 645 * The following computation cannot overflow 646 * because index's slot at the current level 647 * is greater than 0. 648 */ 649 index = pctrie_trimkey(index, 650 node->pn_clev); 651 } 652 index--; 653 KASSERT(!pctrie_keybarr(node, index), 654 ("pctrie_lookup_le: keybarr failed")); 655 } 656 slot = pctrie_slot(index, node->pn_clev); 657 child = pctrie_node_load(&node->pn_child[slot], NULL, 658 PCTRIE_LOCKED); 659 if (pctrie_isleaf(child)) { 660 m = pctrie_toval(child); 661 if (*m <= index) 662 return (m); 663 } else if (child != NULL) 664 goto descend; 665 666 /* 667 * Look for an available edge or value within the current 668 * bisection node. 669 */ 670 if (slot > 0) { 671 inc = PCTRIE_UNITLEVEL(node->pn_clev); 672 index |= inc - 1; 673 do { 674 index -= inc; 675 slot--; 676 child = pctrie_node_load(&node->pn_child[slot], 677 NULL, PCTRIE_LOCKED); 678 if (pctrie_isleaf(child)) { 679 m = pctrie_toval(child); 680 if (*m <= index) 681 return (m); 682 } else if (child != NULL) 683 goto descend; 684 } while (slot > 0); 685 } 686 KASSERT(child == NULL || pctrie_isleaf(child), 687 ("pctrie_lookup_le: child is radix node")); 688 689 /* 690 * If a value or edge smaller than the search slot is not found 691 * in the current node, ascend to the next higher-level node. 692 */ 693 goto ascend; 694 descend: 695 KASSERT(node->pn_clev > 0, 696 ("pctrie_lookup_le: pushing leaf's parent")); 697 KASSERT(tos < PCTRIE_LIMIT, 698 ("pctrie_lookup_le: stack overflow")); 699 stack[tos++] = node; 700 node = child; 701 } 702 } 703 704 /* 705 * Remove the specified index from the tree. 706 * Panics if the key is not present. 707 */ 708 void 709 pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn) 710 { 711 struct pctrie_node *node, *parent, *tmp; 712 uint64_t *m; 713 int i, slot; 714 715 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 716 if (pctrie_isleaf(node)) { 717 m = pctrie_toval(node); 718 if (*m != index) 719 panic("%s: invalid key found", __func__); 720 pctrie_root_store(ptree, NULL, PCTRIE_LOCKED); 721 return; 722 } 723 parent = NULL; 724 for (;;) { 725 if (node == NULL) 726 panic("pctrie_remove: impossible to locate the key"); 727 slot = pctrie_slot(index, node->pn_clev); 728 tmp = pctrie_node_load(&node->pn_child[slot], NULL, 729 PCTRIE_LOCKED); 730 if (pctrie_isleaf(tmp)) { 731 m = pctrie_toval(tmp); 732 if (*m != index) 733 panic("%s: invalid key found", __func__); 734 pctrie_node_store(&node->pn_child[slot], NULL, 735 PCTRIE_LOCKED); 736 node->pn_count--; 737 if (node->pn_count > 1) 738 break; 739 for (i = 0; i < PCTRIE_COUNT; i++) { 740 tmp = pctrie_node_load(&node->pn_child[i], 741 NULL, PCTRIE_LOCKED); 742 if (tmp != NULL) 743 break; 744 } 745 KASSERT(tmp != NULL, 746 ("%s: invalid node configuration", __func__)); 747 if (parent == NULL) 748 pctrie_root_store(ptree, tmp, PCTRIE_LOCKED); 749 else { 750 slot = pctrie_slot(index, parent->pn_clev); 751 KASSERT(pctrie_node_load( 752 &parent->pn_child[slot], NULL, 753 PCTRIE_LOCKED) == node, 754 ("%s: invalid child value", __func__)); 755 pctrie_node_store(&parent->pn_child[slot], tmp, 756 PCTRIE_LOCKED); 757 } 758 /* 759 * The child is still valid and we can not zero the 760 * pointer until all SMR references are gone. 761 */ 762 node->pn_count--; 763 pctrie_node_put(ptree, node, freefn, i); 764 break; 765 } 766 parent = node; 767 node = tmp; 768 } 769 } 770 771 /* 772 * Remove and free all the nodes from the tree. 773 * This function is recursive but there is a tight control on it as the 774 * maximum depth of the tree is fixed. 775 */ 776 void 777 pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn) 778 { 779 struct pctrie_node *root; 780 781 root = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 782 if (root == NULL) 783 return; 784 pctrie_root_store(ptree, NULL, PCTRIE_UNSERIALIZED); 785 if (!pctrie_isleaf(root)) 786 pctrie_reclaim_allnodes_int(ptree, root, freefn); 787 } 788 789 #ifdef DDB 790 /* 791 * Show details about the given node. 792 */ 793 DB_SHOW_COMMAND(pctrienode, db_show_pctrienode) 794 { 795 struct pctrie_node *node, *tmp; 796 int i; 797 798 if (!have_addr) 799 return; 800 node = (struct pctrie_node *)addr; 801 db_printf("node %p, owner %jx, children count %u, level %u:\n", 802 (void *)node, (uintmax_t)node->pn_owner, node->pn_count, 803 node->pn_clev); 804 for (i = 0; i < PCTRIE_COUNT; i++) { 805 tmp = pctrie_node_load(&node->pn_child[i], NULL, 806 PCTRIE_UNSERIALIZED); 807 if (tmp != NULL) 808 db_printf("slot: %d, val: %p, value: %p, clev: %d\n", 809 i, (void *)tmp, 810 pctrie_isleaf(tmp) ? pctrie_toval(tmp) : NULL, 811 node->pn_clev); 812 } 813 } 814 #endif /* DDB */ 815