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