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 * Return the position in the array for a given level. 97 */ 98 static __inline int 99 pctrie_slot(uint64_t index, uint16_t level) 100 { 101 return ((index >> (level * PCTRIE_WIDTH)) & PCTRIE_MASK); 102 } 103 104 /* Computes the key (index) with the low-order 'level' radix-digits zeroed. */ 105 static __inline uint64_t 106 pctrie_trimkey(uint64_t index, uint16_t level) 107 { 108 return (index & -PCTRIE_UNITLEVEL(level)); 109 } 110 111 /* 112 * Allocate a node. Pre-allocation should ensure that the request 113 * will always be satisfied. 114 */ 115 static struct pctrie_node * 116 pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t index, 117 uint16_t clevel) 118 { 119 struct pctrie_node *node; 120 121 node = allocfn(ptree); 122 if (node == NULL) 123 return (NULL); 124 125 /* 126 * We want to clear the last child pointer after the final section 127 * has exited so lookup can not return false negatives. It is done 128 * here because it will be cache-cold in the dtor callback. 129 */ 130 if (node->pn_last != 0) { 131 pctrie_node_store(&node->pn_child[node->pn_last - 1], NULL, 132 PCTRIE_UNSERIALIZED); 133 node->pn_last = 0; 134 } 135 node->pn_owner = pctrie_trimkey(index, clevel + 1); 136 node->pn_count = 2; 137 node->pn_clev = clevel; 138 return (node); 139 } 140 141 /* 142 * Free radix node. 143 */ 144 static __inline void 145 pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node, 146 pctrie_free_t freefn, int8_t last) 147 { 148 #ifdef INVARIANTS 149 int slot; 150 151 KASSERT(node->pn_count == 0, 152 ("pctrie_node_put: node %p has %d children", node, 153 node->pn_count)); 154 for (slot = 0; slot < PCTRIE_COUNT; slot++) { 155 if (slot == last) 156 continue; 157 KASSERT(smr_unserialized_load(&node->pn_child[slot], true) == 158 NULL, ("pctrie_node_put: node %p has a child", node)); 159 } 160 #endif 161 node->pn_last = last + 1; 162 freefn(ptree, node); 163 } 164 165 /* 166 * Fetch a node pointer from a slot. 167 */ 168 static __inline struct pctrie_node * 169 pctrie_node_load(smr_pctnode_t *p, smr_t smr, enum pctrie_access access) 170 { 171 switch (access) { 172 case PCTRIE_UNSERIALIZED: 173 return (smr_unserialized_load(p, true)); 174 case PCTRIE_LOCKED: 175 return (smr_serialized_load(p, true)); 176 case PCTRIE_SMR: 177 return (smr_entered_load(p, smr)); 178 } 179 __assert_unreachable(); 180 } 181 182 static __inline void 183 pctrie_node_store(smr_pctnode_t *p, void *v, enum pctrie_access access) 184 { 185 switch (access) { 186 case PCTRIE_UNSERIALIZED: 187 smr_unserialized_store(p, v, true); 188 break; 189 case PCTRIE_LOCKED: 190 smr_serialized_store(p, v, true); 191 break; 192 case PCTRIE_SMR: 193 panic("%s: Not supported in SMR section.", __func__); 194 break; 195 default: 196 __assert_unreachable(); 197 break; 198 } 199 } 200 201 /* 202 * Get the root node for a tree. 203 */ 204 static __inline struct pctrie_node * 205 pctrie_root_load(struct pctrie *ptree, smr_t smr, enum pctrie_access access) 206 { 207 return (pctrie_node_load((smr_pctnode_t *)&ptree->pt_root, smr, access)); 208 } 209 210 /* 211 * Set the root node for a tree. 212 */ 213 static __inline void 214 pctrie_root_store(struct pctrie *ptree, struct pctrie_node *node, 215 enum pctrie_access access) 216 { 217 pctrie_node_store((smr_pctnode_t *)&ptree->pt_root, node, access); 218 } 219 220 /* 221 * Returns TRUE if the specified node is a leaf and FALSE otherwise. 222 */ 223 static __inline bool 224 pctrie_isleaf(struct pctrie_node *node) 225 { 226 227 return (((uintptr_t)node & PCTRIE_ISLEAF) != 0); 228 } 229 230 /* 231 * Returns val with leaf bit set. 232 */ 233 static __inline void * 234 pctrie_toleaf(uint64_t *val) 235 { 236 return ((void *)((uintptr_t)val | PCTRIE_ISLEAF)); 237 } 238 239 /* 240 * Returns the associated val extracted from node. 241 */ 242 static __inline uint64_t * 243 pctrie_toval(struct pctrie_node *node) 244 { 245 246 return ((uint64_t *)((uintptr_t)node & ~PCTRIE_FLAGS)); 247 } 248 249 /* 250 * Adds the val as a child of the provided node. 251 */ 252 static __inline void 253 pctrie_addval(struct pctrie_node *node, uint64_t index, uint16_t clev, 254 uint64_t *val, enum pctrie_access access) 255 { 256 int slot; 257 258 slot = pctrie_slot(index, clev); 259 pctrie_node_store(&node->pn_child[slot], 260 pctrie_toleaf(val), access); 261 } 262 263 /* 264 * Returns the level where two keys differ. 265 * It cannot accept 2 equal keys. 266 */ 267 static __inline uint16_t 268 pctrie_keydiff(uint64_t index1, uint64_t index2) 269 { 270 271 KASSERT(index1 != index2, ("%s: passing the same key value %jx", 272 __func__, (uintmax_t)index1)); 273 CTASSERT(sizeof(long long) >= sizeof(uint64_t)); 274 275 /* 276 * From the highest-order bit where the indexes differ, 277 * compute the highest level in the trie where they differ. 278 */ 279 return ((flsll(index1 ^ index2) - 1) / PCTRIE_WIDTH); 280 } 281 282 /* 283 * Returns TRUE if it can be determined that key does not belong to the 284 * specified node. Otherwise, returns FALSE. 285 */ 286 static __inline bool 287 pctrie_keybarr(struct pctrie_node *node, uint64_t idx) 288 { 289 290 if (node->pn_clev < PCTRIE_LIMIT) { 291 idx = pctrie_trimkey(idx, node->pn_clev + 1); 292 return (idx != node->pn_owner); 293 } 294 return (false); 295 } 296 297 /* 298 * Internal helper for pctrie_reclaim_allnodes(). 299 * This function is recursive. 300 */ 301 static void 302 pctrie_reclaim_allnodes_int(struct pctrie *ptree, struct pctrie_node *node, 303 pctrie_free_t freefn) 304 { 305 struct pctrie_node *child; 306 int slot; 307 308 KASSERT(node->pn_count <= PCTRIE_COUNT, 309 ("pctrie_reclaim_allnodes_int: bad count in node %p", node)); 310 for (slot = 0; node->pn_count != 0; slot++) { 311 child = pctrie_node_load(&node->pn_child[slot], NULL, 312 PCTRIE_UNSERIALIZED); 313 if (child == NULL) 314 continue; 315 if (!pctrie_isleaf(child)) 316 pctrie_reclaim_allnodes_int(ptree, child, freefn); 317 pctrie_node_store(&node->pn_child[slot], NULL, 318 PCTRIE_UNSERIALIZED); 319 node->pn_count--; 320 } 321 pctrie_node_put(ptree, node, freefn, -1); 322 } 323 324 /* 325 * pctrie node zone initializer. 326 */ 327 int 328 pctrie_zone_init(void *mem, int size __unused, int flags __unused) 329 { 330 struct pctrie_node *node; 331 332 node = mem; 333 node->pn_last = 0; 334 memset(node->pn_child, 0, sizeof(node->pn_child)); 335 return (0); 336 } 337 338 size_t 339 pctrie_node_size(void) 340 { 341 342 return (sizeof(struct pctrie_node)); 343 } 344 345 /* 346 * Inserts the key-value pair into the trie. 347 * Panics if the key already exists. 348 */ 349 int 350 pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) 351 { 352 uint64_t index, newind; 353 struct pctrie_node *node, *tmp; 354 smr_pctnode_t *parentp; 355 uint64_t *m; 356 int slot; 357 uint16_t clev; 358 359 index = *val; 360 361 /* 362 * The owner of record for root is not really important because it 363 * will never be used. 364 */ 365 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 366 if (node == NULL) { 367 ptree->pt_root = (uintptr_t)pctrie_toleaf(val); 368 return (0); 369 } 370 parentp = (smr_pctnode_t *)&ptree->pt_root; 371 for (;;) { 372 if (pctrie_isleaf(node)) { 373 m = pctrie_toval(node); 374 if (*m == index) 375 panic("%s: key %jx is already present", 376 __func__, (uintmax_t)index); 377 clev = pctrie_keydiff(*m, index); 378 tmp = pctrie_node_get(ptree, allocfn, index, clev); 379 if (tmp == NULL) 380 return (ENOMEM); 381 /* These writes are not yet visible due to ordering. */ 382 pctrie_addval(tmp, index, clev, val, 383 PCTRIE_UNSERIALIZED); 384 pctrie_addval(tmp, *m, clev, m, PCTRIE_UNSERIALIZED); 385 /* Synchronize to make leaf visible. */ 386 pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); 387 return (0); 388 } else if (pctrie_keybarr(node, index)) 389 break; 390 slot = pctrie_slot(index, node->pn_clev); 391 parentp = &node->pn_child[slot]; 392 tmp = pctrie_node_load(parentp, NULL, PCTRIE_LOCKED); 393 if (tmp == NULL) { 394 node->pn_count++; 395 pctrie_addval(node, index, node->pn_clev, val, 396 PCTRIE_LOCKED); 397 return (0); 398 } 399 node = tmp; 400 } 401 402 /* 403 * A new node is needed because the right insertion level is reached. 404 * Setup the new intermediate node and add the 2 children: the 405 * new object and the older edge. 406 */ 407 newind = node->pn_owner; 408 clev = pctrie_keydiff(newind, index); 409 tmp = pctrie_node_get(ptree, allocfn, index, clev); 410 if (tmp == NULL) 411 return (ENOMEM); 412 slot = pctrie_slot(newind, clev); 413 /* These writes are not yet visible due to ordering. */ 414 pctrie_addval(tmp, index, clev, val, PCTRIE_UNSERIALIZED); 415 pctrie_node_store(&tmp->pn_child[slot], node, PCTRIE_UNSERIALIZED); 416 /* Synchronize to make the above visible. */ 417 pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); 418 419 return (0); 420 } 421 422 /* 423 * Returns the value stored at the index. If the index is not present, 424 * NULL is returned. 425 */ 426 static __always_inline uint64_t * 427 _pctrie_lookup(struct pctrie *ptree, uint64_t index, smr_t smr, 428 enum pctrie_access access) 429 { 430 struct pctrie_node *node; 431 uint64_t *m; 432 int slot; 433 434 node = pctrie_root_load(ptree, smr, access); 435 while (node != NULL) { 436 if (pctrie_isleaf(node)) { 437 m = pctrie_toval(node); 438 if (*m == index) 439 return (m); 440 break; 441 } 442 if (pctrie_keybarr(node, index)) 443 break; 444 slot = pctrie_slot(index, node->pn_clev); 445 node = pctrie_node_load(&node->pn_child[slot], smr, access); 446 } 447 return (NULL); 448 } 449 450 /* 451 * Returns the value stored at the index, assuming access is externally 452 * synchronized by a lock. 453 * 454 * If the index is not present, NULL is returned. 455 */ 456 uint64_t * 457 pctrie_lookup(struct pctrie *ptree, uint64_t index) 458 { 459 return (_pctrie_lookup(ptree, index, NULL, PCTRIE_LOCKED)); 460 } 461 462 /* 463 * Returns the value stored at the index without requiring an external lock. 464 * 465 * If the index is not present, NULL is returned. 466 */ 467 uint64_t * 468 pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t index, smr_t smr) 469 { 470 uint64_t *res; 471 472 smr_enter(smr); 473 res = _pctrie_lookup(ptree, index, smr, PCTRIE_SMR); 474 smr_exit(smr); 475 return (res); 476 } 477 478 /* 479 * Look up the nearest entry at a position bigger than or equal to index, 480 * assuming access is externally synchronized by a lock. 481 */ 482 uint64_t * 483 pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) 484 { 485 struct pctrie_node *stack[PCTRIE_LIMIT]; 486 uint64_t inc; 487 uint64_t *m; 488 struct pctrie_node *child, *node; 489 #ifdef INVARIANTS 490 int loops = 0; 491 #endif 492 unsigned tos; 493 int slot; 494 495 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 496 if (node == NULL) 497 return (NULL); 498 else if (pctrie_isleaf(node)) { 499 m = pctrie_toval(node); 500 if (*m >= index) 501 return (m); 502 else 503 return (NULL); 504 } 505 tos = 0; 506 for (;;) { 507 /* 508 * If the keys differ before the current bisection node, 509 * then the search key might rollback to the earliest 510 * available bisection node or to the smallest key 511 * in the current node (if the owner is greater than the 512 * search key). 513 */ 514 if (pctrie_keybarr(node, index)) { 515 if (index > node->pn_owner) { 516 ascend: 517 KASSERT(++loops < 1000, 518 ("pctrie_lookup_ge: too many loops")); 519 520 /* 521 * Pop nodes from the stack until either the 522 * stack is empty or a node that could have a 523 * matching descendant is found. 524 */ 525 do { 526 if (tos == 0) 527 return (NULL); 528 node = stack[--tos]; 529 } while (pctrie_slot(index, 530 node->pn_clev) == (PCTRIE_COUNT - 1)); 531 532 /* 533 * The following computation cannot overflow 534 * because index's slot at the current level 535 * is less than PCTRIE_COUNT - 1. 536 */ 537 index = pctrie_trimkey(index, 538 node->pn_clev); 539 index += PCTRIE_UNITLEVEL(node->pn_clev); 540 } else 541 index = node->pn_owner; 542 KASSERT(!pctrie_keybarr(node, index), 543 ("pctrie_lookup_ge: keybarr failed")); 544 } 545 slot = pctrie_slot(index, node->pn_clev); 546 child = pctrie_node_load(&node->pn_child[slot], NULL, 547 PCTRIE_LOCKED); 548 if (pctrie_isleaf(child)) { 549 m = pctrie_toval(child); 550 if (*m >= index) 551 return (m); 552 } else if (child != NULL) 553 goto descend; 554 555 /* 556 * Look for an available edge or val within the current 557 * bisection node. 558 */ 559 if (slot < (PCTRIE_COUNT - 1)) { 560 inc = PCTRIE_UNITLEVEL(node->pn_clev); 561 index = pctrie_trimkey(index, node->pn_clev); 562 do { 563 index += inc; 564 slot++; 565 child = pctrie_node_load(&node->pn_child[slot], 566 NULL, PCTRIE_LOCKED); 567 if (pctrie_isleaf(child)) { 568 m = pctrie_toval(child); 569 KASSERT(*m >= index, 570 ("pctrie_lookup_ge: leaf < index")); 571 return (m); 572 } else if (child != NULL) 573 goto descend; 574 } while (slot < (PCTRIE_COUNT - 1)); 575 } 576 KASSERT(child == NULL || pctrie_isleaf(child), 577 ("pctrie_lookup_ge: child is radix node")); 578 579 /* 580 * If a value or edge greater than the search slot is not found 581 * in the current node, ascend to the next higher-level node. 582 */ 583 goto ascend; 584 descend: 585 KASSERT(node->pn_clev > 0, 586 ("pctrie_lookup_ge: pushing leaf's parent")); 587 KASSERT(tos < PCTRIE_LIMIT, 588 ("pctrie_lookup_ge: stack overflow")); 589 stack[tos++] = node; 590 node = child; 591 } 592 } 593 594 /* 595 * Look up the nearest entry at a position less than or equal to index, 596 * assuming access is externally synchronized by a lock. 597 */ 598 uint64_t * 599 pctrie_lookup_le(struct pctrie *ptree, uint64_t index) 600 { 601 struct pctrie_node *stack[PCTRIE_LIMIT]; 602 uint64_t inc; 603 uint64_t *m; 604 struct pctrie_node *child, *node; 605 #ifdef INVARIANTS 606 int loops = 0; 607 #endif 608 unsigned tos; 609 int slot; 610 611 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 612 if (node == NULL) 613 return (NULL); 614 else if (pctrie_isleaf(node)) { 615 m = pctrie_toval(node); 616 if (*m <= index) 617 return (m); 618 else 619 return (NULL); 620 } 621 tos = 0; 622 for (;;) { 623 /* 624 * If the keys differ before the current bisection node, 625 * then the search key might rollback to the earliest 626 * available bisection node or to the largest key 627 * in the current node (if the owner is smaller than the 628 * search key). 629 */ 630 if (pctrie_keybarr(node, index)) { 631 if (index > node->pn_owner) { 632 index = node->pn_owner + PCTRIE_COUNT * 633 PCTRIE_UNITLEVEL(node->pn_clev); 634 } else { 635 ascend: 636 KASSERT(++loops < 1000, 637 ("pctrie_lookup_le: too many loops")); 638 639 /* 640 * Pop nodes from the stack until either the 641 * stack is empty or a node that could have a 642 * matching descendant is found. 643 */ 644 do { 645 if (tos == 0) 646 return (NULL); 647 node = stack[--tos]; 648 } while (pctrie_slot(index, 649 node->pn_clev) == 0); 650 651 /* 652 * The following computation cannot overflow 653 * because index's slot at the current level 654 * is greater than 0. 655 */ 656 index = pctrie_trimkey(index, 657 node->pn_clev); 658 } 659 index--; 660 KASSERT(!pctrie_keybarr(node, index), 661 ("pctrie_lookup_le: keybarr failed")); 662 } 663 slot = pctrie_slot(index, node->pn_clev); 664 child = pctrie_node_load(&node->pn_child[slot], NULL, 665 PCTRIE_LOCKED); 666 if (pctrie_isleaf(child)) { 667 m = pctrie_toval(child); 668 if (*m <= index) 669 return (m); 670 } else if (child != NULL) 671 goto descend; 672 673 /* 674 * Look for an available edge or value within the current 675 * bisection node. 676 */ 677 if (slot > 0) { 678 inc = PCTRIE_UNITLEVEL(node->pn_clev); 679 index |= inc - 1; 680 do { 681 index -= inc; 682 slot--; 683 child = pctrie_node_load(&node->pn_child[slot], 684 NULL, PCTRIE_LOCKED); 685 if (pctrie_isleaf(child)) { 686 m = pctrie_toval(child); 687 KASSERT(*m <= index, 688 ("pctrie_lookup_le: leaf > index")); 689 return (m); 690 } else if (child != NULL) 691 goto descend; 692 } while (slot > 0); 693 } 694 KASSERT(child == NULL || pctrie_isleaf(child), 695 ("pctrie_lookup_le: child is radix node")); 696 697 /* 698 * If a value or edge smaller than the search slot is not found 699 * in the current node, ascend to the next higher-level node. 700 */ 701 goto ascend; 702 descend: 703 KASSERT(node->pn_clev > 0, 704 ("pctrie_lookup_le: pushing leaf's parent")); 705 KASSERT(tos < PCTRIE_LIMIT, 706 ("pctrie_lookup_le: stack overflow")); 707 stack[tos++] = node; 708 node = child; 709 } 710 } 711 712 /* 713 * Remove the specified index from the tree. 714 * Panics if the key is not present. 715 */ 716 void 717 pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn) 718 { 719 struct pctrie_node *node, *parent, *tmp; 720 uint64_t *m; 721 int i, slot; 722 723 node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 724 if (pctrie_isleaf(node)) { 725 m = pctrie_toval(node); 726 if (*m != index) 727 panic("%s: invalid key found", __func__); 728 pctrie_root_store(ptree, NULL, PCTRIE_LOCKED); 729 return; 730 } 731 parent = NULL; 732 for (;;) { 733 if (node == NULL) 734 panic("pctrie_remove: impossible to locate the key"); 735 slot = pctrie_slot(index, node->pn_clev); 736 tmp = pctrie_node_load(&node->pn_child[slot], NULL, 737 PCTRIE_LOCKED); 738 if (pctrie_isleaf(tmp)) { 739 m = pctrie_toval(tmp); 740 if (*m != index) 741 panic("%s: invalid key found", __func__); 742 pctrie_node_store(&node->pn_child[slot], NULL, 743 PCTRIE_LOCKED); 744 node->pn_count--; 745 if (node->pn_count > 1) 746 break; 747 for (i = 0; i < PCTRIE_COUNT; i++) { 748 tmp = pctrie_node_load(&node->pn_child[i], 749 NULL, PCTRIE_LOCKED); 750 if (tmp != NULL) 751 break; 752 } 753 KASSERT(tmp != NULL, 754 ("%s: invalid node configuration", __func__)); 755 if (parent == NULL) 756 pctrie_root_store(ptree, tmp, PCTRIE_LOCKED); 757 else { 758 slot = pctrie_slot(index, parent->pn_clev); 759 KASSERT(pctrie_node_load( 760 &parent->pn_child[slot], NULL, 761 PCTRIE_LOCKED) == node, 762 ("%s: invalid child value", __func__)); 763 pctrie_node_store(&parent->pn_child[slot], tmp, 764 PCTRIE_LOCKED); 765 } 766 /* 767 * The child is still valid and we can not zero the 768 * pointer until all SMR references are gone. 769 */ 770 node->pn_count--; 771 pctrie_node_put(ptree, node, freefn, i); 772 break; 773 } 774 parent = node; 775 node = tmp; 776 } 777 } 778 779 /* 780 * Remove and free all the nodes from the tree. 781 * This function is recursive but there is a tight control on it as the 782 * maximum depth of the tree is fixed. 783 */ 784 void 785 pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn) 786 { 787 struct pctrie_node *root; 788 789 root = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 790 if (root == NULL) 791 return; 792 pctrie_root_store(ptree, NULL, PCTRIE_UNSERIALIZED); 793 if (!pctrie_isleaf(root)) 794 pctrie_reclaim_allnodes_int(ptree, root, freefn); 795 } 796 797 #ifdef DDB 798 /* 799 * Show details about the given node. 800 */ 801 DB_SHOW_COMMAND(pctrienode, db_show_pctrienode) 802 { 803 struct pctrie_node *node, *tmp; 804 int i; 805 806 if (!have_addr) 807 return; 808 node = (struct pctrie_node *)addr; 809 db_printf("node %p, owner %jx, children count %u, level %u:\n", 810 (void *)node, (uintmax_t)node->pn_owner, node->pn_count, 811 node->pn_clev); 812 for (i = 0; i < PCTRIE_COUNT; i++) { 813 tmp = pctrie_node_load(&node->pn_child[i], NULL, 814 PCTRIE_UNSERIALIZED); 815 if (tmp != NULL) 816 db_printf("slot: %d, val: %p, value: %p, clev: %d\n", 817 i, (void *)tmp, 818 pctrie_isleaf(tmp) ? pctrie_toval(tmp) : NULL, 819 node->pn_clev); 820 } 821 } 822 #endif /* DDB */ 823