18a36da99SPedro F. Giffuni /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 4f2cc1285SJeff Roberson * Copyright (c) 2013 EMC Corp. 5f2cc1285SJeff Roberson * Copyright (c) 2011 Jeffrey Roberson <jeff@freebsd.org> 6f2cc1285SJeff Roberson * Copyright (c) 2008 Mayur Shardul <mayur.shardul@gmail.com> 7f2cc1285SJeff Roberson * All rights reserved. 8f2cc1285SJeff Roberson * 9f2cc1285SJeff Roberson * Redistribution and use in source and binary forms, with or without 10f2cc1285SJeff Roberson * modification, are permitted provided that the following conditions 11f2cc1285SJeff Roberson * are met: 12f2cc1285SJeff Roberson * 1. Redistributions of source code must retain the above copyright 13f2cc1285SJeff Roberson * notice, this list of conditions and the following disclaimer. 14f2cc1285SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 15f2cc1285SJeff Roberson * notice, this list of conditions and the following disclaimer in the 16f2cc1285SJeff Roberson * documentation and/or other materials provided with the distribution. 17f2cc1285SJeff Roberson * 18f2cc1285SJeff Roberson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19f2cc1285SJeff Roberson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20f2cc1285SJeff Roberson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21f2cc1285SJeff Roberson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22f2cc1285SJeff Roberson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23f2cc1285SJeff Roberson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24f2cc1285SJeff Roberson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25f2cc1285SJeff Roberson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26f2cc1285SJeff Roberson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27f2cc1285SJeff Roberson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28f2cc1285SJeff Roberson * SUCH DAMAGE. 29f2cc1285SJeff Roberson * 30f2cc1285SJeff Roberson */ 31f2cc1285SJeff Roberson 32f2cc1285SJeff Roberson /* 33f2cc1285SJeff Roberson * Path-compressed radix trie implementation. 34f2cc1285SJeff Roberson * 35f2cc1285SJeff Roberson * The implementation takes into account the following rationale: 36f2cc1285SJeff Roberson * - Size of the nodes should be as small as possible but still big enough 37f2cc1285SJeff Roberson * to avoid a large maximum depth for the trie. This is a balance 38f2cc1285SJeff Roberson * between the necessity to not wire too much physical memory for the nodes 39f2cc1285SJeff Roberson * and the necessity to avoid too much cache pollution during the trie 40f2cc1285SJeff Roberson * operations. 41f2cc1285SJeff Roberson * - There is not a huge bias toward the number of lookup operations over 42f2cc1285SJeff Roberson * the number of insert and remove operations. This basically implies 43f2cc1285SJeff Roberson * that optimizations supposedly helping one operation but hurting the 44f2cc1285SJeff Roberson * other might be carefully evaluated. 45f2cc1285SJeff Roberson * - On average not many nodes are expected to be fully populated, hence 46f2cc1285SJeff Roberson * level compression may just complicate things. 47f2cc1285SJeff Roberson */ 48f2cc1285SJeff Roberson 49f2cc1285SJeff Roberson #include <sys/cdefs.h> 50f2cc1285SJeff Roberson __FBSDID("$FreeBSD$"); 51f2cc1285SJeff Roberson 52f2cc1285SJeff Roberson #include "opt_ddb.h" 53f2cc1285SJeff Roberson 54f2cc1285SJeff Roberson #include <sys/param.h> 55f2cc1285SJeff Roberson #include <sys/systm.h> 56f2cc1285SJeff Roberson #include <sys/kernel.h> 5705963ea4SDoug Moore #include <sys/libkern.h> 58f2cc1285SJeff Roberson #include <sys/pctrie.h> 593c30b235SConrad Meyer #include <sys/proc.h> /* smr.h depends on struct thread. */ 603c30b235SConrad Meyer #include <sys/smr.h> 613c30b235SConrad Meyer #include <sys/smr_types.h> 62f2cc1285SJeff Roberson 63f2cc1285SJeff Roberson #ifdef DDB 64f2cc1285SJeff Roberson #include <ddb/ddb.h> 65f2cc1285SJeff Roberson #endif 66f2cc1285SJeff Roberson 67f2cc1285SJeff Roberson #define PCTRIE_MASK (PCTRIE_COUNT - 1) 6855e0987aSPedro F. Giffuni #define PCTRIE_LIMIT (howmany(sizeof(uint64_t) * NBBY, PCTRIE_WIDTH) - 1) 69f2cc1285SJeff Roberson 708df38859SDoug Moore #if PCTRIE_WIDTH == 3 718df38859SDoug Moore typedef uint8_t pn_popmap_t; 728df38859SDoug Moore #elif PCTRIE_WIDTH == 4 738df38859SDoug Moore typedef uint16_t pn_popmap_t; 748df38859SDoug Moore #elif PCTRIE_WIDTH == 5 758df38859SDoug Moore typedef uint32_t pn_popmap_t; 768df38859SDoug Moore #else 778df38859SDoug Moore #error Unsupported width 788df38859SDoug Moore #endif 798df38859SDoug Moore _Static_assert(sizeof(pn_popmap_t) <= sizeof(int), 808df38859SDoug Moore "pn_popmap_t too wide"); 818df38859SDoug Moore 82f2cc1285SJeff Roberson /* Flag bits stored in node pointers. */ 83f2cc1285SJeff Roberson #define PCTRIE_ISLEAF 0x1 84f2cc1285SJeff Roberson #define PCTRIE_FLAGS 0x1 85f2cc1285SJeff Roberson #define PCTRIE_PAD PCTRIE_FLAGS 86f2cc1285SJeff Roberson 87f2cc1285SJeff Roberson /* Returns one unit associated with specified level. */ 88f2cc1285SJeff Roberson #define PCTRIE_UNITLEVEL(lev) \ 89f2cc1285SJeff Roberson ((uint64_t)1 << ((lev) * PCTRIE_WIDTH)) 90f2cc1285SJeff Roberson 913c30b235SConrad Meyer struct pctrie_node; 923c30b235SConrad Meyer typedef SMR_POINTER(struct pctrie_node *) smr_pctnode_t; 933c30b235SConrad Meyer 94f2cc1285SJeff Roberson struct pctrie_node { 95f2cc1285SJeff Roberson uint64_t pn_owner; /* Owner of record. */ 968df38859SDoug Moore pn_popmap_t pn_popmap; /* Valid children. */ 973c30b235SConrad Meyer uint8_t pn_clev; /* Current level. */ 983c30b235SConrad Meyer smr_pctnode_t pn_child[PCTRIE_COUNT]; /* Child nodes. */ 99f2cc1285SJeff Roberson }; 100f2cc1285SJeff Roberson 1013c30b235SConrad Meyer enum pctrie_access { PCTRIE_SMR, PCTRIE_LOCKED, PCTRIE_UNSERIALIZED }; 1023c30b235SConrad Meyer 1033c30b235SConrad Meyer static __inline void pctrie_node_store(smr_pctnode_t *p, void *val, 1043c30b235SConrad Meyer enum pctrie_access access); 1053c30b235SConrad Meyer 106f2cc1285SJeff Roberson /* 107da72505fSDoug Moore * Return the position in the array for a given level. 108da72505fSDoug Moore */ 109da72505fSDoug Moore static __inline int 110da72505fSDoug Moore pctrie_slot(uint64_t index, uint16_t level) 111da72505fSDoug Moore { 112da72505fSDoug Moore return ((index >> (level * PCTRIE_WIDTH)) & PCTRIE_MASK); 113da72505fSDoug Moore } 114da72505fSDoug Moore 115da72505fSDoug Moore /* Computes the key (index) with the low-order 'level' radix-digits zeroed. */ 116da72505fSDoug Moore static __inline uint64_t 117da72505fSDoug Moore pctrie_trimkey(uint64_t index, uint16_t level) 118da72505fSDoug Moore { 119da72505fSDoug Moore return (index & -PCTRIE_UNITLEVEL(level)); 120da72505fSDoug Moore } 121da72505fSDoug Moore 122da72505fSDoug Moore /* 123f2cc1285SJeff Roberson * Allocate a node. Pre-allocation should ensure that the request 124f2cc1285SJeff Roberson * will always be satisfied. 125f2cc1285SJeff Roberson */ 1263c30b235SConrad Meyer static struct pctrie_node * 127da72505fSDoug Moore pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t index, 128da72505fSDoug Moore uint16_t clevel) 129f2cc1285SJeff Roberson { 130f2cc1285SJeff Roberson struct pctrie_node *node; 131f2cc1285SJeff Roberson 132f2cc1285SJeff Roberson node = allocfn(ptree); 133f2cc1285SJeff Roberson if (node == NULL) 134f2cc1285SJeff Roberson return (NULL); 1353c30b235SConrad Meyer 1363c30b235SConrad Meyer /* 1373c30b235SConrad Meyer * We want to clear the last child pointer after the final section 1383c30b235SConrad Meyer * has exited so lookup can not return false negatives. It is done 1393c30b235SConrad Meyer * here because it will be cache-cold in the dtor callback. 1403c30b235SConrad Meyer */ 1418df38859SDoug Moore if (node->pn_popmap != 0) { 1428df38859SDoug Moore pctrie_node_store(&node->pn_child[ffs(node->pn_popmap) - 1], 1438df38859SDoug Moore NULL, PCTRIE_UNSERIALIZED); 1448df38859SDoug Moore node->pn_popmap = 0; 1453c30b235SConrad Meyer } 146da72505fSDoug Moore node->pn_owner = pctrie_trimkey(index, clevel + 1); 147f2cc1285SJeff Roberson node->pn_clev = clevel; 148f2cc1285SJeff Roberson return (node); 149f2cc1285SJeff Roberson } 150f2cc1285SJeff Roberson 151f2cc1285SJeff Roberson /* 152f2cc1285SJeff Roberson * Free radix node. 153f2cc1285SJeff Roberson */ 154f2cc1285SJeff Roberson static __inline void 155f2cc1285SJeff Roberson pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node, 1568df38859SDoug Moore pctrie_free_t freefn) 157f2cc1285SJeff Roberson { 158f2cc1285SJeff Roberson #ifdef INVARIANTS 159f2cc1285SJeff Roberson int slot; 160f2cc1285SJeff Roberson 1618df38859SDoug Moore KASSERT(powerof2(node->pn_popmap), 1628df38859SDoug Moore ("pctrie_node_put: node %p has too many children %04x", node, 1638df38859SDoug Moore node->pn_popmap)); 1643c30b235SConrad Meyer for (slot = 0; slot < PCTRIE_COUNT; slot++) { 1658df38859SDoug Moore if ((node->pn_popmap & (1 << slot)) != 0) 1663c30b235SConrad Meyer continue; 1673c30b235SConrad Meyer KASSERT(smr_unserialized_load(&node->pn_child[slot], true) == 1683c30b235SConrad Meyer NULL, ("pctrie_node_put: node %p has a child", node)); 1693c30b235SConrad Meyer } 170f2cc1285SJeff Roberson #endif 171f2cc1285SJeff Roberson freefn(ptree, node); 172f2cc1285SJeff Roberson } 173f2cc1285SJeff Roberson 174f2cc1285SJeff Roberson /* 1753c30b235SConrad Meyer * Fetch a node pointer from a slot. 1763c30b235SConrad Meyer */ 1773c30b235SConrad Meyer static __inline struct pctrie_node * 1783c30b235SConrad Meyer pctrie_node_load(smr_pctnode_t *p, smr_t smr, enum pctrie_access access) 1793c30b235SConrad Meyer { 1803c30b235SConrad Meyer switch (access) { 1813c30b235SConrad Meyer case PCTRIE_UNSERIALIZED: 1823c30b235SConrad Meyer return (smr_unserialized_load(p, true)); 1833c30b235SConrad Meyer case PCTRIE_LOCKED: 1843c30b235SConrad Meyer return (smr_serialized_load(p, true)); 1853c30b235SConrad Meyer case PCTRIE_SMR: 1863c30b235SConrad Meyer return (smr_entered_load(p, smr)); 1873c30b235SConrad Meyer } 1883c30b235SConrad Meyer __assert_unreachable(); 1893c30b235SConrad Meyer } 1903c30b235SConrad Meyer 1913c30b235SConrad Meyer static __inline void 1923c30b235SConrad Meyer pctrie_node_store(smr_pctnode_t *p, void *v, enum pctrie_access access) 1933c30b235SConrad Meyer { 1943c30b235SConrad Meyer switch (access) { 1953c30b235SConrad Meyer case PCTRIE_UNSERIALIZED: 1963c30b235SConrad Meyer smr_unserialized_store(p, v, true); 1973c30b235SConrad Meyer break; 1983c30b235SConrad Meyer case PCTRIE_LOCKED: 1993c30b235SConrad Meyer smr_serialized_store(p, v, true); 2003c30b235SConrad Meyer break; 2013c30b235SConrad Meyer case PCTRIE_SMR: 2023c30b235SConrad Meyer panic("%s: Not supported in SMR section.", __func__); 2033c30b235SConrad Meyer break; 2043c30b235SConrad Meyer default: 2053c30b235SConrad Meyer __assert_unreachable(); 2063c30b235SConrad Meyer break; 2073c30b235SConrad Meyer } 2083c30b235SConrad Meyer } 2093c30b235SConrad Meyer 2103c30b235SConrad Meyer /* 211f2cc1285SJeff Roberson * Get the root node for a tree. 212f2cc1285SJeff Roberson */ 213f2cc1285SJeff Roberson static __inline struct pctrie_node * 2143c30b235SConrad Meyer pctrie_root_load(struct pctrie *ptree, smr_t smr, enum pctrie_access access) 215f2cc1285SJeff Roberson { 2163c30b235SConrad Meyer return (pctrie_node_load((smr_pctnode_t *)&ptree->pt_root, smr, access)); 217f2cc1285SJeff Roberson } 218f2cc1285SJeff Roberson 219f2cc1285SJeff Roberson /* 220f2cc1285SJeff Roberson * Set the root node for a tree. 221f2cc1285SJeff Roberson */ 222f2cc1285SJeff Roberson static __inline void 2233c30b235SConrad Meyer pctrie_root_store(struct pctrie *ptree, struct pctrie_node *node, 2243c30b235SConrad Meyer enum pctrie_access access) 225f2cc1285SJeff Roberson { 2263c30b235SConrad Meyer pctrie_node_store((smr_pctnode_t *)&ptree->pt_root, node, access); 227f2cc1285SJeff Roberson } 228f2cc1285SJeff Roberson 229f2cc1285SJeff Roberson /* 230f2cc1285SJeff Roberson * Returns TRUE if the specified node is a leaf and FALSE otherwise. 231f2cc1285SJeff Roberson */ 23204f9afaeSConrad Meyer static __inline bool 233f2cc1285SJeff Roberson pctrie_isleaf(struct pctrie_node *node) 234f2cc1285SJeff Roberson { 235f2cc1285SJeff Roberson 236f2cc1285SJeff Roberson return (((uintptr_t)node & PCTRIE_ISLEAF) != 0); 237f2cc1285SJeff Roberson } 238f2cc1285SJeff Roberson 239f2cc1285SJeff Roberson /* 2409cfed089SDoug Moore * Returns val with leaf bit set. 2419cfed089SDoug Moore */ 2429cfed089SDoug Moore static __inline void * 2439cfed089SDoug Moore pctrie_toleaf(uint64_t *val) 2449cfed089SDoug Moore { 2459cfed089SDoug Moore return ((void *)((uintptr_t)val | PCTRIE_ISLEAF)); 2469cfed089SDoug Moore } 2479cfed089SDoug Moore 2489cfed089SDoug Moore /* 249f2cc1285SJeff Roberson * Returns the associated val extracted from node. 250f2cc1285SJeff Roberson */ 251f2cc1285SJeff Roberson static __inline uint64_t * 252f2cc1285SJeff Roberson pctrie_toval(struct pctrie_node *node) 253f2cc1285SJeff Roberson { 254f2cc1285SJeff Roberson 255f2cc1285SJeff Roberson return ((uint64_t *)((uintptr_t)node & ~PCTRIE_FLAGS)); 256f2cc1285SJeff Roberson } 257f2cc1285SJeff Roberson 258f2cc1285SJeff Roberson /* 259*16e01c05SDoug Moore * Make 'child' a child of 'node'. 260f2cc1285SJeff Roberson */ 261f2cc1285SJeff Roberson static __inline void 262*16e01c05SDoug Moore pctrie_addnode(struct pctrie_node *node, uint64_t index, uint16_t clev, 263*16e01c05SDoug Moore struct pctrie_node *child, enum pctrie_access access) 264f2cc1285SJeff Roberson { 265f2cc1285SJeff Roberson int slot; 266f2cc1285SJeff Roberson 267f2cc1285SJeff Roberson slot = pctrie_slot(index, clev); 268*16e01c05SDoug Moore pctrie_node_store(&node->pn_child[slot], child, access); 2698df38859SDoug Moore node->pn_popmap ^= 1 << slot; 2708df38859SDoug Moore KASSERT((node->pn_popmap & (1 << slot)) != 0, 2718df38859SDoug Moore ("%s: bad popmap slot %d in node %p", __func__, slot, node)); 272f2cc1285SJeff Roberson } 273f2cc1285SJeff Roberson 274f2cc1285SJeff Roberson /* 27505963ea4SDoug Moore * Returns the level where two keys differ. 276f2cc1285SJeff Roberson * It cannot accept 2 equal keys. 277f2cc1285SJeff Roberson */ 278f2cc1285SJeff Roberson static __inline uint16_t 279f2cc1285SJeff Roberson pctrie_keydiff(uint64_t index1, uint64_t index2) 280f2cc1285SJeff Roberson { 281f2cc1285SJeff Roberson 282f2cc1285SJeff Roberson KASSERT(index1 != index2, ("%s: passing the same key value %jx", 283f2cc1285SJeff Roberson __func__, (uintmax_t)index1)); 28405963ea4SDoug Moore CTASSERT(sizeof(long long) >= sizeof(uint64_t)); 285f2cc1285SJeff Roberson 28605963ea4SDoug Moore /* 28705963ea4SDoug Moore * From the highest-order bit where the indexes differ, 28805963ea4SDoug Moore * compute the highest level in the trie where they differ. 28905963ea4SDoug Moore */ 29005963ea4SDoug Moore return ((flsll(index1 ^ index2) - 1) / PCTRIE_WIDTH); 291f2cc1285SJeff Roberson } 292f2cc1285SJeff Roberson 293f2cc1285SJeff Roberson /* 294f2cc1285SJeff Roberson * Returns TRUE if it can be determined that key does not belong to the 295f2cc1285SJeff Roberson * specified node. Otherwise, returns FALSE. 296f2cc1285SJeff Roberson */ 29704f9afaeSConrad Meyer static __inline bool 298f2cc1285SJeff Roberson pctrie_keybarr(struct pctrie_node *node, uint64_t idx) 299f2cc1285SJeff Roberson { 300f2cc1285SJeff Roberson 301f2cc1285SJeff Roberson if (node->pn_clev < PCTRIE_LIMIT) { 302f2cc1285SJeff Roberson idx = pctrie_trimkey(idx, node->pn_clev + 1); 303f2cc1285SJeff Roberson return (idx != node->pn_owner); 304f2cc1285SJeff Roberson } 30504f9afaeSConrad Meyer return (false); 306f2cc1285SJeff Roberson } 307f2cc1285SJeff Roberson 308f2cc1285SJeff Roberson /* 309f2cc1285SJeff Roberson * Internal helper for pctrie_reclaim_allnodes(). 310f2cc1285SJeff Roberson * This function is recursive. 311f2cc1285SJeff Roberson */ 312f2cc1285SJeff Roberson static void 313f2cc1285SJeff Roberson pctrie_reclaim_allnodes_int(struct pctrie *ptree, struct pctrie_node *node, 314f2cc1285SJeff Roberson pctrie_free_t freefn) 315f2cc1285SJeff Roberson { 3163c30b235SConrad Meyer struct pctrie_node *child; 317f2cc1285SJeff Roberson int slot; 318f2cc1285SJeff Roberson 3198df38859SDoug Moore while (node->pn_popmap != 0) { 3208df38859SDoug Moore slot = ffs(node->pn_popmap) - 1; 3213c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], NULL, 3223c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 3238df38859SDoug Moore KASSERT(child != NULL, ("%s: bad popmap slot %d in node %p", 3248df38859SDoug Moore __func__, slot, node)); 3253c30b235SConrad Meyer if (!pctrie_isleaf(child)) 3263c30b235SConrad Meyer pctrie_reclaim_allnodes_int(ptree, child, freefn); 3278df38859SDoug Moore node->pn_popmap ^= 1 << slot; 3283c30b235SConrad Meyer pctrie_node_store(&node->pn_child[slot], NULL, 3293c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 330f2cc1285SJeff Roberson } 3318df38859SDoug Moore pctrie_node_put(ptree, node, freefn); 332f2cc1285SJeff Roberson } 333f2cc1285SJeff Roberson 334f2cc1285SJeff Roberson /* 335f2cc1285SJeff Roberson * pctrie node zone initializer. 336f2cc1285SJeff Roberson */ 337f2cc1285SJeff Roberson int 338f2cc1285SJeff Roberson pctrie_zone_init(void *mem, int size __unused, int flags __unused) 339f2cc1285SJeff Roberson { 340f2cc1285SJeff Roberson struct pctrie_node *node; 341f2cc1285SJeff Roberson 342f2cc1285SJeff Roberson node = mem; 3438df38859SDoug Moore node->pn_popmap = 0; 344f2cc1285SJeff Roberson memset(node->pn_child, 0, sizeof(node->pn_child)); 345f2cc1285SJeff Roberson return (0); 346f2cc1285SJeff Roberson } 347f2cc1285SJeff Roberson 348f2cc1285SJeff Roberson size_t 349f2cc1285SJeff Roberson pctrie_node_size(void) 350f2cc1285SJeff Roberson { 351f2cc1285SJeff Roberson 352f2cc1285SJeff Roberson return (sizeof(struct pctrie_node)); 353f2cc1285SJeff Roberson } 354f2cc1285SJeff Roberson 355f2cc1285SJeff Roberson /* 356f2cc1285SJeff Roberson * Inserts the key-value pair into the trie. 357f2cc1285SJeff Roberson * Panics if the key already exists. 358f2cc1285SJeff Roberson */ 359f2cc1285SJeff Roberson int 360f2cc1285SJeff Roberson pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) 361f2cc1285SJeff Roberson { 362f2cc1285SJeff Roberson uint64_t index, newind; 363*16e01c05SDoug Moore struct pctrie_node *leaf, *node, *tmp; 3643c30b235SConrad Meyer smr_pctnode_t *parentp; 365f2cc1285SJeff Roberson int slot; 366f2cc1285SJeff Roberson uint16_t clev; 367f2cc1285SJeff Roberson 368f2cc1285SJeff Roberson index = *val; 369*16e01c05SDoug Moore leaf = pctrie_toleaf(val); 370f2cc1285SJeff Roberson 371f2cc1285SJeff Roberson /* 372f2cc1285SJeff Roberson * The owner of record for root is not really important because it 373f2cc1285SJeff Roberson * will never be used. 374f2cc1285SJeff Roberson */ 3753c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 376f2cc1285SJeff Roberson if (node == NULL) { 377*16e01c05SDoug Moore ptree->pt_root = (uintptr_t)leaf; 378f2cc1285SJeff Roberson return (0); 379f2cc1285SJeff Roberson } 380*16e01c05SDoug Moore for (parentp = (smr_pctnode_t *)&ptree->pt_root;; node = tmp) { 381f2cc1285SJeff Roberson if (pctrie_isleaf(node)) { 382*16e01c05SDoug Moore newind = *pctrie_toval(node); 383*16e01c05SDoug Moore if (newind == index) 384f2cc1285SJeff Roberson panic("%s: key %jx is already present", 385f2cc1285SJeff Roberson __func__, (uintmax_t)index); 386f2cc1285SJeff Roberson break; 387*16e01c05SDoug Moore } else if (pctrie_keybarr(node, index)) { 388*16e01c05SDoug Moore newind = node->pn_owner; 389*16e01c05SDoug Moore break; 390*16e01c05SDoug Moore } 391f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 3923c30b235SConrad Meyer parentp = &node->pn_child[slot]; 3933c30b235SConrad Meyer tmp = pctrie_node_load(parentp, NULL, PCTRIE_LOCKED); 3943c30b235SConrad Meyer if (tmp == NULL) { 395*16e01c05SDoug Moore pctrie_addnode(node, index, node->pn_clev, leaf, 3963c30b235SConrad Meyer PCTRIE_LOCKED); 397f2cc1285SJeff Roberson return (0); 398f2cc1285SJeff Roberson } 399f2cc1285SJeff Roberson } 400f2cc1285SJeff Roberson 401f2cc1285SJeff Roberson /* 402f2cc1285SJeff Roberson * A new node is needed because the right insertion level is reached. 403f2cc1285SJeff Roberson * Setup the new intermediate node and add the 2 children: the 404*16e01c05SDoug Moore * new object and the older edge or object. 405f2cc1285SJeff Roberson */ 406f2cc1285SJeff Roberson clev = pctrie_keydiff(newind, index); 407da72505fSDoug Moore tmp = pctrie_node_get(ptree, allocfn, index, clev); 408f2cc1285SJeff Roberson if (tmp == NULL) 409f2cc1285SJeff Roberson return (ENOMEM); 4103c30b235SConrad Meyer /* These writes are not yet visible due to ordering. */ 411*16e01c05SDoug Moore pctrie_addnode(tmp, index, clev, leaf, PCTRIE_UNSERIALIZED); 412*16e01c05SDoug Moore pctrie_addnode(tmp, newind, clev, node, PCTRIE_UNSERIALIZED); 4133c30b235SConrad Meyer /* Synchronize to make the above visible. */ 4143c30b235SConrad Meyer pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); 415f2cc1285SJeff Roberson return (0); 416f2cc1285SJeff Roberson } 417f2cc1285SJeff Roberson 418f2cc1285SJeff Roberson /* 419f2cc1285SJeff Roberson * Returns the value stored at the index. If the index is not present, 420f2cc1285SJeff Roberson * NULL is returned. 421f2cc1285SJeff Roberson */ 4223c30b235SConrad Meyer static __always_inline uint64_t * 4233c30b235SConrad Meyer _pctrie_lookup(struct pctrie *ptree, uint64_t index, smr_t smr, 4243c30b235SConrad Meyer enum pctrie_access access) 425f2cc1285SJeff Roberson { 426f2cc1285SJeff Roberson struct pctrie_node *node; 427f2cc1285SJeff Roberson uint64_t *m; 428f2cc1285SJeff Roberson int slot; 429f2cc1285SJeff Roberson 4303c30b235SConrad Meyer node = pctrie_root_load(ptree, smr, access); 431f2cc1285SJeff Roberson while (node != NULL) { 432f2cc1285SJeff Roberson if (pctrie_isleaf(node)) { 433f2cc1285SJeff Roberson m = pctrie_toval(node); 434f2cc1285SJeff Roberson if (*m == index) 435f2cc1285SJeff Roberson return (m); 436f2cc1285SJeff Roberson break; 4373c30b235SConrad Meyer } 4383c30b235SConrad Meyer if (pctrie_keybarr(node, index)) 439f2cc1285SJeff Roberson break; 440f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 4413c30b235SConrad Meyer node = pctrie_node_load(&node->pn_child[slot], smr, access); 442f2cc1285SJeff Roberson } 443f2cc1285SJeff Roberson return (NULL); 444f2cc1285SJeff Roberson } 445f2cc1285SJeff Roberson 446f2cc1285SJeff Roberson /* 4473c30b235SConrad Meyer * Returns the value stored at the index, assuming access is externally 4483c30b235SConrad Meyer * synchronized by a lock. 4493c30b235SConrad Meyer * 4503c30b235SConrad Meyer * If the index is not present, NULL is returned. 4513c30b235SConrad Meyer */ 4523c30b235SConrad Meyer uint64_t * 4533c30b235SConrad Meyer pctrie_lookup(struct pctrie *ptree, uint64_t index) 4543c30b235SConrad Meyer { 4553c30b235SConrad Meyer return (_pctrie_lookup(ptree, index, NULL, PCTRIE_LOCKED)); 4563c30b235SConrad Meyer } 4573c30b235SConrad Meyer 4583c30b235SConrad Meyer /* 4593c30b235SConrad Meyer * Returns the value stored at the index without requiring an external lock. 4603c30b235SConrad Meyer * 4613c30b235SConrad Meyer * If the index is not present, NULL is returned. 4623c30b235SConrad Meyer */ 4633c30b235SConrad Meyer uint64_t * 4643c30b235SConrad Meyer pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t index, smr_t smr) 4653c30b235SConrad Meyer { 4663c30b235SConrad Meyer uint64_t *res; 4673c30b235SConrad Meyer 4683c30b235SConrad Meyer smr_enter(smr); 4693c30b235SConrad Meyer res = _pctrie_lookup(ptree, index, smr, PCTRIE_SMR); 4703c30b235SConrad Meyer smr_exit(smr); 4713c30b235SConrad Meyer return (res); 4723c30b235SConrad Meyer } 4733c30b235SConrad Meyer 4743c30b235SConrad Meyer /* 4753c30b235SConrad Meyer * Look up the nearest entry at a position bigger than or equal to index, 4763c30b235SConrad Meyer * assuming access is externally synchronized by a lock. 477f2cc1285SJeff Roberson */ 478f2cc1285SJeff Roberson uint64_t * 479f2cc1285SJeff Roberson pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) 480f2cc1285SJeff Roberson { 481f2cc1285SJeff Roberson struct pctrie_node *stack[PCTRIE_LIMIT]; 482f2cc1285SJeff Roberson uint64_t *m; 483f2cc1285SJeff Roberson struct pctrie_node *child, *node; 484f2cc1285SJeff Roberson #ifdef INVARIANTS 485f2cc1285SJeff Roberson int loops = 0; 486f2cc1285SJeff Roberson #endif 487d1139b52SConrad Meyer unsigned tos; 488d1139b52SConrad Meyer int slot; 489f2cc1285SJeff Roberson 4903c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 491f2cc1285SJeff Roberson if (node == NULL) 492f2cc1285SJeff Roberson return (NULL); 493f2cc1285SJeff Roberson else if (pctrie_isleaf(node)) { 494f2cc1285SJeff Roberson m = pctrie_toval(node); 495f2cc1285SJeff Roberson if (*m >= index) 496f2cc1285SJeff Roberson return (m); 497f2cc1285SJeff Roberson else 498f2cc1285SJeff Roberson return (NULL); 499f2cc1285SJeff Roberson } 500f2cc1285SJeff Roberson tos = 0; 501f2cc1285SJeff Roberson for (;;) { 502f2cc1285SJeff Roberson /* 503f2cc1285SJeff Roberson * If the keys differ before the current bisection node, 504f2cc1285SJeff Roberson * then the search key might rollback to the earliest 505f2cc1285SJeff Roberson * available bisection node or to the smallest key 5063c30b235SConrad Meyer * in the current node (if the owner is greater than the 507f2cc1285SJeff Roberson * search key). 508f2cc1285SJeff Roberson */ 509f2cc1285SJeff Roberson if (pctrie_keybarr(node, index)) { 510f2cc1285SJeff Roberson if (index > node->pn_owner) { 511f2cc1285SJeff Roberson ascend: 512f2cc1285SJeff Roberson KASSERT(++loops < 1000, 513f2cc1285SJeff Roberson ("pctrie_lookup_ge: too many loops")); 514f2cc1285SJeff Roberson 515f2cc1285SJeff Roberson /* 516f2cc1285SJeff Roberson * Pop nodes from the stack until either the 517f2cc1285SJeff Roberson * stack is empty or a node that could have a 518f2cc1285SJeff Roberson * matching descendant is found. 519f2cc1285SJeff Roberson */ 520f2cc1285SJeff Roberson do { 521f2cc1285SJeff Roberson if (tos == 0) 522f2cc1285SJeff Roberson return (NULL); 523f2cc1285SJeff Roberson node = stack[--tos]; 524f2cc1285SJeff Roberson } while (pctrie_slot(index, 525f2cc1285SJeff Roberson node->pn_clev) == (PCTRIE_COUNT - 1)); 526f2cc1285SJeff Roberson 527f2cc1285SJeff Roberson /* 528f2cc1285SJeff Roberson * The following computation cannot overflow 529f2cc1285SJeff Roberson * because index's slot at the current level 530f2cc1285SJeff Roberson * is less than PCTRIE_COUNT - 1. 531f2cc1285SJeff Roberson */ 532f2cc1285SJeff Roberson index = pctrie_trimkey(index, 533f2cc1285SJeff Roberson node->pn_clev); 534f2cc1285SJeff Roberson index += PCTRIE_UNITLEVEL(node->pn_clev); 535f2cc1285SJeff Roberson } else 536f2cc1285SJeff Roberson index = node->pn_owner; 537f2cc1285SJeff Roberson KASSERT(!pctrie_keybarr(node, index), 538f2cc1285SJeff Roberson ("pctrie_lookup_ge: keybarr failed")); 539f2cc1285SJeff Roberson } 540f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 5413c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], NULL, 5423c30b235SConrad Meyer PCTRIE_LOCKED); 543f2cc1285SJeff Roberson if (pctrie_isleaf(child)) { 544f2cc1285SJeff Roberson m = pctrie_toval(child); 545f2cc1285SJeff Roberson if (*m >= index) 546f2cc1285SJeff Roberson return (m); 547f2cc1285SJeff Roberson } else if (child != NULL) 548f2cc1285SJeff Roberson goto descend; 549f2cc1285SJeff Roberson 5508df38859SDoug Moore /* Find the first set bit beyond the first slot+1 bits. */ 5518df38859SDoug Moore slot = ffs(node->pn_popmap & (-2 << slot)) - 1; 5528df38859SDoug Moore if (slot < 0) { 553f2cc1285SJeff Roberson /* 5548df38859SDoug Moore * A value or edge greater than the search slot is not 5558df38859SDoug Moore * found in the current node; ascend to the next 5568df38859SDoug Moore * higher-level node. 557f2cc1285SJeff Roberson */ 558f2cc1285SJeff Roberson goto ascend; 5598df38859SDoug Moore } 5608df38859SDoug Moore child = pctrie_node_load(&node->pn_child[slot], 5618df38859SDoug Moore NULL, PCTRIE_LOCKED); 5628df38859SDoug Moore KASSERT(child != NULL, ("%s: bad popmap slot %d in node %p", 5638df38859SDoug Moore __func__, slot, node)); 5648df38859SDoug Moore if (pctrie_isleaf(child)) 5658df38859SDoug Moore return (pctrie_toval(child)); 5668df38859SDoug Moore index = pctrie_trimkey(index, node->pn_clev + 1) + 5678df38859SDoug Moore slot * PCTRIE_UNITLEVEL(node->pn_clev); 568f2cc1285SJeff Roberson descend: 569f2cc1285SJeff Roberson KASSERT(node->pn_clev > 0, 570f2cc1285SJeff Roberson ("pctrie_lookup_ge: pushing leaf's parent")); 571f2cc1285SJeff Roberson KASSERT(tos < PCTRIE_LIMIT, 572f2cc1285SJeff Roberson ("pctrie_lookup_ge: stack overflow")); 573f2cc1285SJeff Roberson stack[tos++] = node; 574f2cc1285SJeff Roberson node = child; 575f2cc1285SJeff Roberson } 576f2cc1285SJeff Roberson } 577f2cc1285SJeff Roberson 578f2cc1285SJeff Roberson /* 5793c30b235SConrad Meyer * Look up the nearest entry at a position less than or equal to index, 5803c30b235SConrad Meyer * assuming access is externally synchronized by a lock. 581f2cc1285SJeff Roberson */ 582f2cc1285SJeff Roberson uint64_t * 583f2cc1285SJeff Roberson pctrie_lookup_le(struct pctrie *ptree, uint64_t index) 584f2cc1285SJeff Roberson { 585f2cc1285SJeff Roberson struct pctrie_node *stack[PCTRIE_LIMIT]; 586f2cc1285SJeff Roberson uint64_t *m; 587f2cc1285SJeff Roberson struct pctrie_node *child, *node; 588f2cc1285SJeff Roberson #ifdef INVARIANTS 589f2cc1285SJeff Roberson int loops = 0; 590f2cc1285SJeff Roberson #endif 591d1139b52SConrad Meyer unsigned tos; 592d1139b52SConrad Meyer int slot; 593f2cc1285SJeff Roberson 5943c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 595f2cc1285SJeff Roberson if (node == NULL) 596f2cc1285SJeff Roberson return (NULL); 597f2cc1285SJeff Roberson else if (pctrie_isleaf(node)) { 598f2cc1285SJeff Roberson m = pctrie_toval(node); 599f2cc1285SJeff Roberson if (*m <= index) 600f2cc1285SJeff Roberson return (m); 601f2cc1285SJeff Roberson else 602f2cc1285SJeff Roberson return (NULL); 603f2cc1285SJeff Roberson } 604f2cc1285SJeff Roberson tos = 0; 605f2cc1285SJeff Roberson for (;;) { 606f2cc1285SJeff Roberson /* 607f2cc1285SJeff Roberson * If the keys differ before the current bisection node, 608f2cc1285SJeff Roberson * then the search key might rollback to the earliest 609f2cc1285SJeff Roberson * available bisection node or to the largest key 610f2cc1285SJeff Roberson * in the current node (if the owner is smaller than the 611f2cc1285SJeff Roberson * search key). 612f2cc1285SJeff Roberson */ 613f2cc1285SJeff Roberson if (pctrie_keybarr(node, index)) { 614f2cc1285SJeff Roberson if (index > node->pn_owner) { 615f2cc1285SJeff Roberson index = node->pn_owner + PCTRIE_COUNT * 616f2cc1285SJeff Roberson PCTRIE_UNITLEVEL(node->pn_clev); 617f2cc1285SJeff Roberson } else { 618f2cc1285SJeff Roberson ascend: 619f2cc1285SJeff Roberson KASSERT(++loops < 1000, 620f2cc1285SJeff Roberson ("pctrie_lookup_le: too many loops")); 621f2cc1285SJeff Roberson 622f2cc1285SJeff Roberson /* 623f2cc1285SJeff Roberson * Pop nodes from the stack until either the 624f2cc1285SJeff Roberson * stack is empty or a node that could have a 625f2cc1285SJeff Roberson * matching descendant is found. 626f2cc1285SJeff Roberson */ 627f2cc1285SJeff Roberson do { 628f2cc1285SJeff Roberson if (tos == 0) 629f2cc1285SJeff Roberson return (NULL); 630f2cc1285SJeff Roberson node = stack[--tos]; 631f2cc1285SJeff Roberson } while (pctrie_slot(index, 632f2cc1285SJeff Roberson node->pn_clev) == 0); 633f2cc1285SJeff Roberson 634f2cc1285SJeff Roberson /* 635f2cc1285SJeff Roberson * The following computation cannot overflow 636f2cc1285SJeff Roberson * because index's slot at the current level 637f2cc1285SJeff Roberson * is greater than 0. 638f2cc1285SJeff Roberson */ 639f2cc1285SJeff Roberson index = pctrie_trimkey(index, 640f2cc1285SJeff Roberson node->pn_clev); 641f2cc1285SJeff Roberson } 642f2cc1285SJeff Roberson index--; 643f2cc1285SJeff Roberson KASSERT(!pctrie_keybarr(node, index), 644f2cc1285SJeff Roberson ("pctrie_lookup_le: keybarr failed")); 645f2cc1285SJeff Roberson } 646f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 6473c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], NULL, 6483c30b235SConrad Meyer PCTRIE_LOCKED); 649f2cc1285SJeff Roberson if (pctrie_isleaf(child)) { 650f2cc1285SJeff Roberson m = pctrie_toval(child); 651f2cc1285SJeff Roberson if (*m <= index) 652f2cc1285SJeff Roberson return (m); 653f2cc1285SJeff Roberson } else if (child != NULL) 654f2cc1285SJeff Roberson goto descend; 655f2cc1285SJeff Roberson 6568df38859SDoug Moore /* Find the last set bit among the first slot bits. */ 6578df38859SDoug Moore slot = fls(node->pn_popmap & ((1 << slot) - 1)) - 1; 6588df38859SDoug Moore if (slot < 0) { 659f2cc1285SJeff Roberson /* 6608df38859SDoug Moore * A value or edge smaller than the search slot is not 6618df38859SDoug Moore * found in the current node; ascend to the next 6628df38859SDoug Moore * higher-level node. 663f2cc1285SJeff Roberson */ 664f2cc1285SJeff Roberson goto ascend; 6658df38859SDoug Moore } 6668df38859SDoug Moore child = pctrie_node_load(&node->pn_child[slot], 6678df38859SDoug Moore NULL, PCTRIE_LOCKED); 6688df38859SDoug Moore if (pctrie_isleaf(child)) 6698df38859SDoug Moore return (pctrie_toval(child)); 6708df38859SDoug Moore index = pctrie_trimkey(index, node->pn_clev + 1) + 6718df38859SDoug Moore (slot + 1) * PCTRIE_UNITLEVEL(node->pn_clev) - 1; 672f2cc1285SJeff Roberson descend: 673f2cc1285SJeff Roberson KASSERT(node->pn_clev > 0, 674f2cc1285SJeff Roberson ("pctrie_lookup_le: pushing leaf's parent")); 675f2cc1285SJeff Roberson KASSERT(tos < PCTRIE_LIMIT, 676f2cc1285SJeff Roberson ("pctrie_lookup_le: stack overflow")); 677f2cc1285SJeff Roberson stack[tos++] = node; 678f2cc1285SJeff Roberson node = child; 679f2cc1285SJeff Roberson } 680f2cc1285SJeff Roberson } 681f2cc1285SJeff Roberson 682f2cc1285SJeff Roberson /* 683f2cc1285SJeff Roberson * Remove the specified index from the tree. 684f2cc1285SJeff Roberson * Panics if the key is not present. 685f2cc1285SJeff Roberson */ 686f2cc1285SJeff Roberson void 687f2cc1285SJeff Roberson pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn) 688f2cc1285SJeff Roberson { 6893c30b235SConrad Meyer struct pctrie_node *node, *parent, *tmp; 690f2cc1285SJeff Roberson uint64_t *m; 6918df38859SDoug Moore int slot; 692f2cc1285SJeff Roberson 6933c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 694f2cc1285SJeff Roberson if (pctrie_isleaf(node)) { 695f2cc1285SJeff Roberson m = pctrie_toval(node); 696f2cc1285SJeff Roberson if (*m != index) 697f2cc1285SJeff Roberson panic("%s: invalid key found", __func__); 6983c30b235SConrad Meyer pctrie_root_store(ptree, NULL, PCTRIE_LOCKED); 699f2cc1285SJeff Roberson return; 700f2cc1285SJeff Roberson } 701f2cc1285SJeff Roberson parent = NULL; 702f2cc1285SJeff Roberson for (;;) { 703f2cc1285SJeff Roberson if (node == NULL) 704f2cc1285SJeff Roberson panic("pctrie_remove: impossible to locate the key"); 705f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 7063c30b235SConrad Meyer tmp = pctrie_node_load(&node->pn_child[slot], NULL, 7073c30b235SConrad Meyer PCTRIE_LOCKED); 7083c30b235SConrad Meyer if (pctrie_isleaf(tmp)) { 7093c30b235SConrad Meyer m = pctrie_toval(tmp); 710f2cc1285SJeff Roberson if (*m != index) 711f2cc1285SJeff Roberson panic("%s: invalid key found", __func__); 7128df38859SDoug Moore KASSERT((node->pn_popmap & (1 << slot)) != 0, 7138df38859SDoug Moore ("%s: bad popmap slot %d in node %p", 7148df38859SDoug Moore __func__, slot, node)); 7158df38859SDoug Moore node->pn_popmap ^= 1 << slot; 7163c30b235SConrad Meyer pctrie_node_store(&node->pn_child[slot], NULL, 7173c30b235SConrad Meyer PCTRIE_LOCKED); 7188df38859SDoug Moore if (!powerof2(node->pn_popmap)) 719f2cc1285SJeff Roberson break; 7208df38859SDoug Moore KASSERT(node->pn_popmap != 0, 7218df38859SDoug Moore ("%s: bad popmap all zeroes", __func__)); 7228df38859SDoug Moore slot = ffs(node->pn_popmap) - 1; 7238df38859SDoug Moore tmp = pctrie_node_load(&node->pn_child[slot], 7243c30b235SConrad Meyer NULL, PCTRIE_LOCKED); 725e8efee29SDoug Moore KASSERT(tmp != NULL, 7268df38859SDoug Moore ("%s: bad popmap slot %d in node %p", 7278df38859SDoug Moore __func__, slot, node)); 728f2cc1285SJeff Roberson if (parent == NULL) 7293c30b235SConrad Meyer pctrie_root_store(ptree, tmp, PCTRIE_LOCKED); 730f2cc1285SJeff Roberson else { 731f2cc1285SJeff Roberson slot = pctrie_slot(index, parent->pn_clev); 7323c30b235SConrad Meyer KASSERT(pctrie_node_load( 7333c30b235SConrad Meyer &parent->pn_child[slot], NULL, 7343c30b235SConrad Meyer PCTRIE_LOCKED) == node, 735f2cc1285SJeff Roberson ("%s: invalid child value", __func__)); 7363c30b235SConrad Meyer pctrie_node_store(&parent->pn_child[slot], tmp, 7373c30b235SConrad Meyer PCTRIE_LOCKED); 738f2cc1285SJeff Roberson } 7393c30b235SConrad Meyer /* 7403c30b235SConrad Meyer * The child is still valid and we can not zero the 7413c30b235SConrad Meyer * pointer until all SMR references are gone. 7423c30b235SConrad Meyer */ 7438df38859SDoug Moore pctrie_node_put(ptree, node, freefn); 744f2cc1285SJeff Roberson break; 745f2cc1285SJeff Roberson } 746f2cc1285SJeff Roberson parent = node; 7473c30b235SConrad Meyer node = tmp; 748f2cc1285SJeff Roberson } 749f2cc1285SJeff Roberson } 750f2cc1285SJeff Roberson 751f2cc1285SJeff Roberson /* 752f2cc1285SJeff Roberson * Remove and free all the nodes from the tree. 753f2cc1285SJeff Roberson * This function is recursive but there is a tight control on it as the 754f2cc1285SJeff Roberson * maximum depth of the tree is fixed. 755f2cc1285SJeff Roberson */ 756f2cc1285SJeff Roberson void 757f2cc1285SJeff Roberson pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn) 758f2cc1285SJeff Roberson { 759f2cc1285SJeff Roberson struct pctrie_node *root; 760f2cc1285SJeff Roberson 7613c30b235SConrad Meyer root = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 762f2cc1285SJeff Roberson if (root == NULL) 763f2cc1285SJeff Roberson return; 7643c30b235SConrad Meyer pctrie_root_store(ptree, NULL, PCTRIE_UNSERIALIZED); 765f2cc1285SJeff Roberson if (!pctrie_isleaf(root)) 766f2cc1285SJeff Roberson pctrie_reclaim_allnodes_int(ptree, root, freefn); 767f2cc1285SJeff Roberson } 768f2cc1285SJeff Roberson 769f2cc1285SJeff Roberson #ifdef DDB 770f2cc1285SJeff Roberson /* 771f2cc1285SJeff Roberson * Show details about the given node. 772f2cc1285SJeff Roberson */ 773f2cc1285SJeff Roberson DB_SHOW_COMMAND(pctrienode, db_show_pctrienode) 774f2cc1285SJeff Roberson { 7753c30b235SConrad Meyer struct pctrie_node *node, *tmp; 7768df38859SDoug Moore int slot; 7778df38859SDoug Moore pn_popmap_t popmap; 778f2cc1285SJeff Roberson 779f2cc1285SJeff Roberson if (!have_addr) 780f2cc1285SJeff Roberson return; 781f2cc1285SJeff Roberson node = (struct pctrie_node *)addr; 7828df38859SDoug Moore db_printf("node %p, owner %jx, children popmap %04x, level %u:\n", 7838df38859SDoug Moore (void *)node, (uintmax_t)node->pn_owner, node->pn_popmap, 784f2cc1285SJeff Roberson node->pn_clev); 7858df38859SDoug Moore for (popmap = node->pn_popmap; popmap != 0; popmap ^= 1 << slot) { 7868df38859SDoug Moore slot = ffs(popmap) - 1; 7878df38859SDoug Moore tmp = pctrie_node_load(&node->pn_child[slot], NULL, 7883c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 789f2cc1285SJeff Roberson db_printf("slot: %d, val: %p, value: %p, clev: %d\n", 7908df38859SDoug Moore slot, (void *)tmp, 7913c30b235SConrad Meyer pctrie_isleaf(tmp) ? pctrie_toval(tmp) : NULL, 792f2cc1285SJeff Roberson node->pn_clev); 793f2cc1285SJeff Roberson } 7943c30b235SConrad Meyer } 795f2cc1285SJeff Roberson #endif /* DDB */ 796