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 70f2cc1285SJeff Roberson /* Flag bits stored in node pointers. */ 71f2cc1285SJeff Roberson #define PCTRIE_ISLEAF 0x1 72f2cc1285SJeff Roberson #define PCTRIE_FLAGS 0x1 73f2cc1285SJeff Roberson #define PCTRIE_PAD PCTRIE_FLAGS 74f2cc1285SJeff Roberson 75f2cc1285SJeff Roberson /* Returns one unit associated with specified level. */ 76f2cc1285SJeff Roberson #define PCTRIE_UNITLEVEL(lev) \ 77f2cc1285SJeff Roberson ((uint64_t)1 << ((lev) * PCTRIE_WIDTH)) 78f2cc1285SJeff Roberson 793c30b235SConrad Meyer struct pctrie_node; 803c30b235SConrad Meyer typedef SMR_POINTER(struct pctrie_node *) smr_pctnode_t; 813c30b235SConrad Meyer 82f2cc1285SJeff Roberson struct pctrie_node { 83f2cc1285SJeff Roberson uint64_t pn_owner; /* Owner of record. */ 84f2cc1285SJeff Roberson uint16_t pn_count; /* Valid children. */ 853c30b235SConrad Meyer uint8_t pn_clev; /* Current level. */ 863c30b235SConrad Meyer int8_t pn_last; /* Zero last ptr. */ 873c30b235SConrad Meyer smr_pctnode_t pn_child[PCTRIE_COUNT]; /* Child nodes. */ 88f2cc1285SJeff Roberson }; 89f2cc1285SJeff Roberson 903c30b235SConrad Meyer enum pctrie_access { PCTRIE_SMR, PCTRIE_LOCKED, PCTRIE_UNSERIALIZED }; 913c30b235SConrad Meyer 923c30b235SConrad Meyer static __inline void pctrie_node_store(smr_pctnode_t *p, void *val, 933c30b235SConrad Meyer enum pctrie_access access); 943c30b235SConrad Meyer 95f2cc1285SJeff Roberson /* 96f2cc1285SJeff Roberson * Allocate a node. Pre-allocation should ensure that the request 97f2cc1285SJeff Roberson * will always be satisfied. 98f2cc1285SJeff Roberson */ 993c30b235SConrad Meyer static struct pctrie_node * 100f2cc1285SJeff Roberson pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t owner, 101f2cc1285SJeff Roberson uint16_t count, uint16_t clevel) 102f2cc1285SJeff Roberson { 103f2cc1285SJeff Roberson struct pctrie_node *node; 104f2cc1285SJeff Roberson 105f2cc1285SJeff Roberson node = allocfn(ptree); 106f2cc1285SJeff Roberson if (node == NULL) 107f2cc1285SJeff Roberson return (NULL); 1083c30b235SConrad Meyer 1093c30b235SConrad Meyer /* 1103c30b235SConrad Meyer * We want to clear the last child pointer after the final section 1113c30b235SConrad Meyer * has exited so lookup can not return false negatives. It is done 1123c30b235SConrad Meyer * here because it will be cache-cold in the dtor callback. 1133c30b235SConrad Meyer */ 1143c30b235SConrad Meyer if (node->pn_last != 0) { 1153c30b235SConrad Meyer pctrie_node_store(&node->pn_child[node->pn_last - 1], NULL, 1163c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 1173c30b235SConrad Meyer node->pn_last = 0; 1183c30b235SConrad Meyer } 119f2cc1285SJeff Roberson node->pn_owner = owner; 120f2cc1285SJeff Roberson node->pn_count = count; 121f2cc1285SJeff Roberson node->pn_clev = clevel; 122f2cc1285SJeff Roberson return (node); 123f2cc1285SJeff Roberson } 124f2cc1285SJeff Roberson 125f2cc1285SJeff Roberson /* 126f2cc1285SJeff Roberson * Free radix node. 127f2cc1285SJeff Roberson */ 128f2cc1285SJeff Roberson static __inline void 129f2cc1285SJeff Roberson pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node, 1303c30b235SConrad Meyer pctrie_free_t freefn, int8_t last) 131f2cc1285SJeff Roberson { 132f2cc1285SJeff Roberson #ifdef INVARIANTS 133f2cc1285SJeff Roberson int slot; 134f2cc1285SJeff Roberson 135f2cc1285SJeff Roberson KASSERT(node->pn_count == 0, 136f2cc1285SJeff Roberson ("pctrie_node_put: node %p has %d children", node, 137f2cc1285SJeff Roberson node->pn_count)); 1383c30b235SConrad Meyer for (slot = 0; slot < PCTRIE_COUNT; slot++) { 1393c30b235SConrad Meyer if (slot == last) 1403c30b235SConrad Meyer continue; 1413c30b235SConrad Meyer KASSERT(smr_unserialized_load(&node->pn_child[slot], true) == 1423c30b235SConrad Meyer NULL, ("pctrie_node_put: node %p has a child", node)); 1433c30b235SConrad Meyer } 144f2cc1285SJeff Roberson #endif 1453c30b235SConrad Meyer node->pn_last = last + 1; 146f2cc1285SJeff Roberson freefn(ptree, node); 147f2cc1285SJeff Roberson } 148f2cc1285SJeff Roberson 149f2cc1285SJeff Roberson /* 150f2cc1285SJeff Roberson * Return the position in the array for a given level. 151f2cc1285SJeff Roberson */ 152f2cc1285SJeff Roberson static __inline int 153f2cc1285SJeff Roberson pctrie_slot(uint64_t index, uint16_t level) 154f2cc1285SJeff Roberson { 155f2cc1285SJeff Roberson 156f2cc1285SJeff Roberson return ((index >> (level * PCTRIE_WIDTH)) & PCTRIE_MASK); 157f2cc1285SJeff Roberson } 158f2cc1285SJeff Roberson 159a42d8fe0SDoug Moore /* Computes the key (index) with the low-order 'level' radix-digits zeroed. */ 160f2cc1285SJeff Roberson static __inline uint64_t 161f2cc1285SJeff Roberson pctrie_trimkey(uint64_t index, uint16_t level) 162f2cc1285SJeff Roberson { 163a42d8fe0SDoug Moore return (index & -PCTRIE_UNITLEVEL(level)); 164f2cc1285SJeff Roberson } 165f2cc1285SJeff Roberson 166f2cc1285SJeff Roberson /* 1673c30b235SConrad Meyer * Fetch a node pointer from a slot. 1683c30b235SConrad Meyer */ 1693c30b235SConrad Meyer static __inline struct pctrie_node * 1703c30b235SConrad Meyer pctrie_node_load(smr_pctnode_t *p, smr_t smr, enum pctrie_access access) 1713c30b235SConrad Meyer { 1723c30b235SConrad Meyer switch (access) { 1733c30b235SConrad Meyer case PCTRIE_UNSERIALIZED: 1743c30b235SConrad Meyer return (smr_unserialized_load(p, true)); 1753c30b235SConrad Meyer case PCTRIE_LOCKED: 1763c30b235SConrad Meyer return (smr_serialized_load(p, true)); 1773c30b235SConrad Meyer case PCTRIE_SMR: 1783c30b235SConrad Meyer return (smr_entered_load(p, smr)); 1793c30b235SConrad Meyer } 1803c30b235SConrad Meyer __assert_unreachable(); 1813c30b235SConrad Meyer } 1823c30b235SConrad Meyer 1833c30b235SConrad Meyer static __inline void 1843c30b235SConrad Meyer pctrie_node_store(smr_pctnode_t *p, void *v, enum pctrie_access access) 1853c30b235SConrad Meyer { 1863c30b235SConrad Meyer switch (access) { 1873c30b235SConrad Meyer case PCTRIE_UNSERIALIZED: 1883c30b235SConrad Meyer smr_unserialized_store(p, v, true); 1893c30b235SConrad Meyer break; 1903c30b235SConrad Meyer case PCTRIE_LOCKED: 1913c30b235SConrad Meyer smr_serialized_store(p, v, true); 1923c30b235SConrad Meyer break; 1933c30b235SConrad Meyer case PCTRIE_SMR: 1943c30b235SConrad Meyer panic("%s: Not supported in SMR section.", __func__); 1953c30b235SConrad Meyer break; 1963c30b235SConrad Meyer default: 1973c30b235SConrad Meyer __assert_unreachable(); 1983c30b235SConrad Meyer break; 1993c30b235SConrad Meyer } 2003c30b235SConrad Meyer } 2013c30b235SConrad Meyer 2023c30b235SConrad Meyer /* 203f2cc1285SJeff Roberson * Get the root node for a tree. 204f2cc1285SJeff Roberson */ 205f2cc1285SJeff Roberson static __inline struct pctrie_node * 2063c30b235SConrad Meyer pctrie_root_load(struct pctrie *ptree, smr_t smr, enum pctrie_access access) 207f2cc1285SJeff Roberson { 2083c30b235SConrad Meyer return (pctrie_node_load((smr_pctnode_t *)&ptree->pt_root, smr, access)); 209f2cc1285SJeff Roberson } 210f2cc1285SJeff Roberson 211f2cc1285SJeff Roberson /* 212f2cc1285SJeff Roberson * Set the root node for a tree. 213f2cc1285SJeff Roberson */ 214f2cc1285SJeff Roberson static __inline void 2153c30b235SConrad Meyer pctrie_root_store(struct pctrie *ptree, struct pctrie_node *node, 2163c30b235SConrad Meyer enum pctrie_access access) 217f2cc1285SJeff Roberson { 2183c30b235SConrad Meyer pctrie_node_store((smr_pctnode_t *)&ptree->pt_root, node, access); 219f2cc1285SJeff Roberson } 220f2cc1285SJeff Roberson 221f2cc1285SJeff Roberson /* 222f2cc1285SJeff Roberson * Returns TRUE if the specified node is a leaf and FALSE otherwise. 223f2cc1285SJeff Roberson */ 22404f9afaeSConrad Meyer static __inline bool 225f2cc1285SJeff Roberson pctrie_isleaf(struct pctrie_node *node) 226f2cc1285SJeff Roberson { 227f2cc1285SJeff Roberson 228f2cc1285SJeff Roberson return (((uintptr_t)node & PCTRIE_ISLEAF) != 0); 229f2cc1285SJeff Roberson } 230f2cc1285SJeff Roberson 231f2cc1285SJeff Roberson /* 232*9cfed089SDoug Moore * Returns val with leaf bit set. 233*9cfed089SDoug Moore */ 234*9cfed089SDoug Moore static __inline void * 235*9cfed089SDoug Moore pctrie_toleaf(uint64_t *val) 236*9cfed089SDoug Moore { 237*9cfed089SDoug Moore return ((void *)((uintptr_t)val | PCTRIE_ISLEAF)); 238*9cfed089SDoug Moore } 239*9cfed089SDoug Moore 240*9cfed089SDoug Moore /* 241f2cc1285SJeff Roberson * Returns the associated val extracted from node. 242f2cc1285SJeff Roberson */ 243f2cc1285SJeff Roberson static __inline uint64_t * 244f2cc1285SJeff Roberson pctrie_toval(struct pctrie_node *node) 245f2cc1285SJeff Roberson { 246f2cc1285SJeff Roberson 247f2cc1285SJeff Roberson return ((uint64_t *)((uintptr_t)node & ~PCTRIE_FLAGS)); 248f2cc1285SJeff Roberson } 249f2cc1285SJeff Roberson 250f2cc1285SJeff Roberson /* 251f2cc1285SJeff Roberson * Adds the val as a child of the provided node. 252f2cc1285SJeff Roberson */ 253f2cc1285SJeff Roberson static __inline void 254f2cc1285SJeff Roberson pctrie_addval(struct pctrie_node *node, uint64_t index, uint16_t clev, 2553c30b235SConrad Meyer uint64_t *val, enum pctrie_access access) 256f2cc1285SJeff Roberson { 257f2cc1285SJeff Roberson int slot; 258f2cc1285SJeff Roberson 259f2cc1285SJeff Roberson slot = pctrie_slot(index, clev); 2603c30b235SConrad Meyer pctrie_node_store(&node->pn_child[slot], 261*9cfed089SDoug Moore pctrie_toleaf(val), access); 262f2cc1285SJeff Roberson } 263f2cc1285SJeff Roberson 264f2cc1285SJeff Roberson /* 26505963ea4SDoug Moore * Returns the level where two keys differ. 266f2cc1285SJeff Roberson * It cannot accept 2 equal keys. 267f2cc1285SJeff Roberson */ 268f2cc1285SJeff Roberson static __inline uint16_t 269f2cc1285SJeff Roberson pctrie_keydiff(uint64_t index1, uint64_t index2) 270f2cc1285SJeff Roberson { 271f2cc1285SJeff Roberson 272f2cc1285SJeff Roberson KASSERT(index1 != index2, ("%s: passing the same key value %jx", 273f2cc1285SJeff Roberson __func__, (uintmax_t)index1)); 27405963ea4SDoug Moore CTASSERT(sizeof(long long) >= sizeof(uint64_t)); 275f2cc1285SJeff Roberson 27605963ea4SDoug Moore /* 27705963ea4SDoug Moore * From the highest-order bit where the indexes differ, 27805963ea4SDoug Moore * compute the highest level in the trie where they differ. 27905963ea4SDoug Moore */ 28005963ea4SDoug Moore return ((flsll(index1 ^ index2) - 1) / PCTRIE_WIDTH); 281f2cc1285SJeff Roberson } 282f2cc1285SJeff Roberson 283f2cc1285SJeff Roberson /* 284f2cc1285SJeff Roberson * Returns TRUE if it can be determined that key does not belong to the 285f2cc1285SJeff Roberson * specified node. Otherwise, returns FALSE. 286f2cc1285SJeff Roberson */ 28704f9afaeSConrad Meyer static __inline bool 288f2cc1285SJeff Roberson pctrie_keybarr(struct pctrie_node *node, uint64_t idx) 289f2cc1285SJeff Roberson { 290f2cc1285SJeff Roberson 291f2cc1285SJeff Roberson if (node->pn_clev < PCTRIE_LIMIT) { 292f2cc1285SJeff Roberson idx = pctrie_trimkey(idx, node->pn_clev + 1); 293f2cc1285SJeff Roberson return (idx != node->pn_owner); 294f2cc1285SJeff Roberson } 29504f9afaeSConrad Meyer return (false); 296f2cc1285SJeff Roberson } 297f2cc1285SJeff Roberson 298f2cc1285SJeff Roberson /* 299f2cc1285SJeff Roberson * Internal helper for pctrie_reclaim_allnodes(). 300f2cc1285SJeff Roberson * This function is recursive. 301f2cc1285SJeff Roberson */ 302f2cc1285SJeff Roberson static void 303f2cc1285SJeff Roberson pctrie_reclaim_allnodes_int(struct pctrie *ptree, struct pctrie_node *node, 304f2cc1285SJeff Roberson pctrie_free_t freefn) 305f2cc1285SJeff Roberson { 3063c30b235SConrad Meyer struct pctrie_node *child; 307f2cc1285SJeff Roberson int slot; 308f2cc1285SJeff Roberson 309f2cc1285SJeff Roberson KASSERT(node->pn_count <= PCTRIE_COUNT, 310f2cc1285SJeff Roberson ("pctrie_reclaim_allnodes_int: bad count in node %p", node)); 311f2cc1285SJeff Roberson for (slot = 0; node->pn_count != 0; slot++) { 3123c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], NULL, 3133c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 3143c30b235SConrad Meyer if (child == NULL) 315f2cc1285SJeff Roberson continue; 3163c30b235SConrad Meyer if (!pctrie_isleaf(child)) 3173c30b235SConrad Meyer pctrie_reclaim_allnodes_int(ptree, child, freefn); 3183c30b235SConrad Meyer pctrie_node_store(&node->pn_child[slot], NULL, 3193c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 320f2cc1285SJeff Roberson node->pn_count--; 321f2cc1285SJeff Roberson } 3223c30b235SConrad Meyer pctrie_node_put(ptree, node, freefn, -1); 323f2cc1285SJeff Roberson } 324f2cc1285SJeff Roberson 325f2cc1285SJeff Roberson /* 326f2cc1285SJeff Roberson * pctrie node zone initializer. 327f2cc1285SJeff Roberson */ 328f2cc1285SJeff Roberson int 329f2cc1285SJeff Roberson pctrie_zone_init(void *mem, int size __unused, int flags __unused) 330f2cc1285SJeff Roberson { 331f2cc1285SJeff Roberson struct pctrie_node *node; 332f2cc1285SJeff Roberson 333f2cc1285SJeff Roberson node = mem; 3343c30b235SConrad Meyer node->pn_last = 0; 335f2cc1285SJeff Roberson memset(node->pn_child, 0, sizeof(node->pn_child)); 336f2cc1285SJeff Roberson return (0); 337f2cc1285SJeff Roberson } 338f2cc1285SJeff Roberson 339f2cc1285SJeff Roberson size_t 340f2cc1285SJeff Roberson pctrie_node_size(void) 341f2cc1285SJeff Roberson { 342f2cc1285SJeff Roberson 343f2cc1285SJeff Roberson return (sizeof(struct pctrie_node)); 344f2cc1285SJeff Roberson } 345f2cc1285SJeff Roberson 346f2cc1285SJeff Roberson /* 347f2cc1285SJeff Roberson * Inserts the key-value pair into the trie. 348f2cc1285SJeff Roberson * Panics if the key already exists. 349f2cc1285SJeff Roberson */ 350f2cc1285SJeff Roberson int 351f2cc1285SJeff Roberson pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) 352f2cc1285SJeff Roberson { 353f2cc1285SJeff Roberson uint64_t index, newind; 354f2cc1285SJeff Roberson struct pctrie_node *node, *tmp; 3553c30b235SConrad Meyer smr_pctnode_t *parentp; 356f2cc1285SJeff Roberson uint64_t *m; 357f2cc1285SJeff Roberson int slot; 358f2cc1285SJeff Roberson uint16_t clev; 359f2cc1285SJeff Roberson 360f2cc1285SJeff Roberson index = *val; 361f2cc1285SJeff Roberson 362f2cc1285SJeff Roberson /* 363f2cc1285SJeff Roberson * The owner of record for root is not really important because it 364f2cc1285SJeff Roberson * will never be used. 365f2cc1285SJeff Roberson */ 3663c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 367f2cc1285SJeff Roberson if (node == NULL) { 368*9cfed089SDoug Moore ptree->pt_root = (uintptr_t)pctrie_toleaf(val); 369f2cc1285SJeff Roberson return (0); 370f2cc1285SJeff Roberson } 3713c30b235SConrad Meyer parentp = (smr_pctnode_t *)&ptree->pt_root; 372f2cc1285SJeff Roberson for (;;) { 373f2cc1285SJeff Roberson if (pctrie_isleaf(node)) { 374f2cc1285SJeff Roberson m = pctrie_toval(node); 375f2cc1285SJeff Roberson if (*m == index) 376f2cc1285SJeff Roberson panic("%s: key %jx is already present", 377f2cc1285SJeff Roberson __func__, (uintmax_t)index); 378f2cc1285SJeff Roberson clev = pctrie_keydiff(*m, index); 379f2cc1285SJeff Roberson tmp = pctrie_node_get(ptree, allocfn, 380f2cc1285SJeff Roberson pctrie_trimkey(index, clev + 1), 2, clev); 381f2cc1285SJeff Roberson if (tmp == NULL) 382f2cc1285SJeff Roberson return (ENOMEM); 3833c30b235SConrad Meyer /* These writes are not yet visible due to ordering. */ 3843c30b235SConrad Meyer pctrie_addval(tmp, index, clev, val, 3853c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 3863c30b235SConrad Meyer pctrie_addval(tmp, *m, clev, m, PCTRIE_UNSERIALIZED); 3873c30b235SConrad Meyer /* Synchronize to make leaf visible. */ 3883c30b235SConrad Meyer pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); 389f2cc1285SJeff Roberson return (0); 390f2cc1285SJeff Roberson } else if (pctrie_keybarr(node, index)) 391f2cc1285SJeff Roberson break; 392f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 3933c30b235SConrad Meyer parentp = &node->pn_child[slot]; 3943c30b235SConrad Meyer tmp = pctrie_node_load(parentp, NULL, PCTRIE_LOCKED); 3953c30b235SConrad Meyer if (tmp == NULL) { 396f2cc1285SJeff Roberson node->pn_count++; 3973c30b235SConrad Meyer pctrie_addval(node, index, node->pn_clev, val, 3983c30b235SConrad Meyer PCTRIE_LOCKED); 399f2cc1285SJeff Roberson return (0); 400f2cc1285SJeff Roberson } 4013c30b235SConrad Meyer node = tmp; 402f2cc1285SJeff Roberson } 403f2cc1285SJeff Roberson 404f2cc1285SJeff Roberson /* 405f2cc1285SJeff Roberson * A new node is needed because the right insertion level is reached. 406f2cc1285SJeff Roberson * Setup the new intermediate node and add the 2 children: the 407f2cc1285SJeff Roberson * new object and the older edge. 408f2cc1285SJeff Roberson */ 409f2cc1285SJeff Roberson newind = node->pn_owner; 410f2cc1285SJeff Roberson clev = pctrie_keydiff(newind, index); 411f2cc1285SJeff Roberson tmp = pctrie_node_get(ptree, allocfn, 412f2cc1285SJeff Roberson pctrie_trimkey(index, clev + 1), 2, clev); 413f2cc1285SJeff Roberson if (tmp == NULL) 414f2cc1285SJeff Roberson return (ENOMEM); 415f2cc1285SJeff Roberson slot = pctrie_slot(newind, clev); 4163c30b235SConrad Meyer /* These writes are not yet visible due to ordering. */ 4173c30b235SConrad Meyer pctrie_addval(tmp, index, clev, val, PCTRIE_UNSERIALIZED); 4183c30b235SConrad Meyer pctrie_node_store(&tmp->pn_child[slot], node, PCTRIE_UNSERIALIZED); 4193c30b235SConrad Meyer /* Synchronize to make the above visible. */ 4203c30b235SConrad Meyer pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); 421f2cc1285SJeff Roberson 422f2cc1285SJeff Roberson return (0); 423f2cc1285SJeff Roberson } 424f2cc1285SJeff Roberson 425f2cc1285SJeff Roberson /* 426f2cc1285SJeff Roberson * Returns the value stored at the index. If the index is not present, 427f2cc1285SJeff Roberson * NULL is returned. 428f2cc1285SJeff Roberson */ 4293c30b235SConrad Meyer static __always_inline uint64_t * 4303c30b235SConrad Meyer _pctrie_lookup(struct pctrie *ptree, uint64_t index, smr_t smr, 4313c30b235SConrad Meyer enum pctrie_access access) 432f2cc1285SJeff Roberson { 433f2cc1285SJeff Roberson struct pctrie_node *node; 434f2cc1285SJeff Roberson uint64_t *m; 435f2cc1285SJeff Roberson int slot; 436f2cc1285SJeff Roberson 4373c30b235SConrad Meyer node = pctrie_root_load(ptree, smr, access); 438f2cc1285SJeff Roberson while (node != NULL) { 439f2cc1285SJeff Roberson if (pctrie_isleaf(node)) { 440f2cc1285SJeff Roberson m = pctrie_toval(node); 441f2cc1285SJeff Roberson if (*m == index) 442f2cc1285SJeff Roberson return (m); 443f2cc1285SJeff Roberson break; 4443c30b235SConrad Meyer } 4453c30b235SConrad Meyer if (pctrie_keybarr(node, index)) 446f2cc1285SJeff Roberson break; 447f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 4483c30b235SConrad Meyer node = pctrie_node_load(&node->pn_child[slot], smr, access); 449f2cc1285SJeff Roberson } 450f2cc1285SJeff Roberson return (NULL); 451f2cc1285SJeff Roberson } 452f2cc1285SJeff Roberson 453f2cc1285SJeff Roberson /* 4543c30b235SConrad Meyer * Returns the value stored at the index, assuming access is externally 4553c30b235SConrad Meyer * synchronized by a lock. 4563c30b235SConrad Meyer * 4573c30b235SConrad Meyer * If the index is not present, NULL is returned. 4583c30b235SConrad Meyer */ 4593c30b235SConrad Meyer uint64_t * 4603c30b235SConrad Meyer pctrie_lookup(struct pctrie *ptree, uint64_t index) 4613c30b235SConrad Meyer { 4623c30b235SConrad Meyer return (_pctrie_lookup(ptree, index, NULL, PCTRIE_LOCKED)); 4633c30b235SConrad Meyer } 4643c30b235SConrad Meyer 4653c30b235SConrad Meyer /* 4663c30b235SConrad Meyer * Returns the value stored at the index without requiring an external lock. 4673c30b235SConrad Meyer * 4683c30b235SConrad Meyer * If the index is not present, NULL is returned. 4693c30b235SConrad Meyer */ 4703c30b235SConrad Meyer uint64_t * 4713c30b235SConrad Meyer pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t index, smr_t smr) 4723c30b235SConrad Meyer { 4733c30b235SConrad Meyer uint64_t *res; 4743c30b235SConrad Meyer 4753c30b235SConrad Meyer smr_enter(smr); 4763c30b235SConrad Meyer res = _pctrie_lookup(ptree, index, smr, PCTRIE_SMR); 4773c30b235SConrad Meyer smr_exit(smr); 4783c30b235SConrad Meyer return (res); 4793c30b235SConrad Meyer } 4803c30b235SConrad Meyer 4813c30b235SConrad Meyer /* 4823c30b235SConrad Meyer * Look up the nearest entry at a position bigger than or equal to index, 4833c30b235SConrad Meyer * assuming access is externally synchronized by a lock. 484f2cc1285SJeff Roberson */ 485f2cc1285SJeff Roberson uint64_t * 486f2cc1285SJeff Roberson pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) 487f2cc1285SJeff Roberson { 488f2cc1285SJeff Roberson struct pctrie_node *stack[PCTRIE_LIMIT]; 489f2cc1285SJeff Roberson uint64_t inc; 490f2cc1285SJeff Roberson uint64_t *m; 491f2cc1285SJeff Roberson struct pctrie_node *child, *node; 492f2cc1285SJeff Roberson #ifdef INVARIANTS 493f2cc1285SJeff Roberson int loops = 0; 494f2cc1285SJeff Roberson #endif 495d1139b52SConrad Meyer unsigned tos; 496d1139b52SConrad Meyer int slot; 497f2cc1285SJeff Roberson 4983c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 499f2cc1285SJeff Roberson if (node == NULL) 500f2cc1285SJeff Roberson return (NULL); 501f2cc1285SJeff Roberson else if (pctrie_isleaf(node)) { 502f2cc1285SJeff Roberson m = pctrie_toval(node); 503f2cc1285SJeff Roberson if (*m >= index) 504f2cc1285SJeff Roberson return (m); 505f2cc1285SJeff Roberson else 506f2cc1285SJeff Roberson return (NULL); 507f2cc1285SJeff Roberson } 508f2cc1285SJeff Roberson tos = 0; 509f2cc1285SJeff Roberson for (;;) { 510f2cc1285SJeff Roberson /* 511f2cc1285SJeff Roberson * If the keys differ before the current bisection node, 512f2cc1285SJeff Roberson * then the search key might rollback to the earliest 513f2cc1285SJeff Roberson * available bisection node or to the smallest key 5143c30b235SConrad Meyer * in the current node (if the owner is greater than the 515f2cc1285SJeff Roberson * search key). 516f2cc1285SJeff Roberson */ 517f2cc1285SJeff Roberson if (pctrie_keybarr(node, index)) { 518f2cc1285SJeff Roberson if (index > node->pn_owner) { 519f2cc1285SJeff Roberson ascend: 520f2cc1285SJeff Roberson KASSERT(++loops < 1000, 521f2cc1285SJeff Roberson ("pctrie_lookup_ge: too many loops")); 522f2cc1285SJeff Roberson 523f2cc1285SJeff Roberson /* 524f2cc1285SJeff Roberson * Pop nodes from the stack until either the 525f2cc1285SJeff Roberson * stack is empty or a node that could have a 526f2cc1285SJeff Roberson * matching descendant is found. 527f2cc1285SJeff Roberson */ 528f2cc1285SJeff Roberson do { 529f2cc1285SJeff Roberson if (tos == 0) 530f2cc1285SJeff Roberson return (NULL); 531f2cc1285SJeff Roberson node = stack[--tos]; 532f2cc1285SJeff Roberson } while (pctrie_slot(index, 533f2cc1285SJeff Roberson node->pn_clev) == (PCTRIE_COUNT - 1)); 534f2cc1285SJeff Roberson 535f2cc1285SJeff Roberson /* 536f2cc1285SJeff Roberson * The following computation cannot overflow 537f2cc1285SJeff Roberson * because index's slot at the current level 538f2cc1285SJeff Roberson * is less than PCTRIE_COUNT - 1. 539f2cc1285SJeff Roberson */ 540f2cc1285SJeff Roberson index = pctrie_trimkey(index, 541f2cc1285SJeff Roberson node->pn_clev); 542f2cc1285SJeff Roberson index += PCTRIE_UNITLEVEL(node->pn_clev); 543f2cc1285SJeff Roberson } else 544f2cc1285SJeff Roberson index = node->pn_owner; 545f2cc1285SJeff Roberson KASSERT(!pctrie_keybarr(node, index), 546f2cc1285SJeff Roberson ("pctrie_lookup_ge: keybarr failed")); 547f2cc1285SJeff Roberson } 548f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 5493c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], NULL, 5503c30b235SConrad Meyer PCTRIE_LOCKED); 551f2cc1285SJeff Roberson if (pctrie_isleaf(child)) { 552f2cc1285SJeff Roberson m = pctrie_toval(child); 553f2cc1285SJeff Roberson if (*m >= index) 554f2cc1285SJeff Roberson return (m); 555f2cc1285SJeff Roberson } else if (child != NULL) 556f2cc1285SJeff Roberson goto descend; 557f2cc1285SJeff Roberson 558f2cc1285SJeff Roberson /* 559f2cc1285SJeff Roberson * Look for an available edge or val within the current 560f2cc1285SJeff Roberson * bisection node. 561f2cc1285SJeff Roberson */ 562f2cc1285SJeff Roberson if (slot < (PCTRIE_COUNT - 1)) { 563f2cc1285SJeff Roberson inc = PCTRIE_UNITLEVEL(node->pn_clev); 564f2cc1285SJeff Roberson index = pctrie_trimkey(index, node->pn_clev); 565f2cc1285SJeff Roberson do { 566f2cc1285SJeff Roberson index += inc; 567f2cc1285SJeff Roberson slot++; 5683c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], 5693c30b235SConrad Meyer NULL, PCTRIE_LOCKED); 570f2cc1285SJeff Roberson if (pctrie_isleaf(child)) { 571f2cc1285SJeff Roberson m = pctrie_toval(child); 57272c3a43bSDoug Moore KASSERT(*m >= index, 57372c3a43bSDoug Moore ("pctrie_lookup_ge: leaf < index")); 574f2cc1285SJeff Roberson return (m); 575f2cc1285SJeff Roberson } else if (child != NULL) 576f2cc1285SJeff Roberson goto descend; 577f2cc1285SJeff Roberson } while (slot < (PCTRIE_COUNT - 1)); 578f2cc1285SJeff Roberson } 579f2cc1285SJeff Roberson KASSERT(child == NULL || pctrie_isleaf(child), 580f2cc1285SJeff Roberson ("pctrie_lookup_ge: child is radix node")); 581f2cc1285SJeff Roberson 582f2cc1285SJeff Roberson /* 5833c30b235SConrad Meyer * If a value or edge greater than the search slot is not found 584f2cc1285SJeff Roberson * in the current node, ascend to the next higher-level node. 585f2cc1285SJeff Roberson */ 586f2cc1285SJeff Roberson goto ascend; 587f2cc1285SJeff Roberson descend: 588f2cc1285SJeff Roberson KASSERT(node->pn_clev > 0, 589f2cc1285SJeff Roberson ("pctrie_lookup_ge: pushing leaf's parent")); 590f2cc1285SJeff Roberson KASSERT(tos < PCTRIE_LIMIT, 591f2cc1285SJeff Roberson ("pctrie_lookup_ge: stack overflow")); 592f2cc1285SJeff Roberson stack[tos++] = node; 593f2cc1285SJeff Roberson node = child; 594f2cc1285SJeff Roberson } 595f2cc1285SJeff Roberson } 596f2cc1285SJeff Roberson 597f2cc1285SJeff Roberson /* 5983c30b235SConrad Meyer * Look up the nearest entry at a position less than or equal to index, 5993c30b235SConrad Meyer * assuming access is externally synchronized by a lock. 600f2cc1285SJeff Roberson */ 601f2cc1285SJeff Roberson uint64_t * 602f2cc1285SJeff Roberson pctrie_lookup_le(struct pctrie *ptree, uint64_t index) 603f2cc1285SJeff Roberson { 604f2cc1285SJeff Roberson struct pctrie_node *stack[PCTRIE_LIMIT]; 605f2cc1285SJeff Roberson uint64_t inc; 606f2cc1285SJeff Roberson uint64_t *m; 607f2cc1285SJeff Roberson struct pctrie_node *child, *node; 608f2cc1285SJeff Roberson #ifdef INVARIANTS 609f2cc1285SJeff Roberson int loops = 0; 610f2cc1285SJeff Roberson #endif 611d1139b52SConrad Meyer unsigned tos; 612d1139b52SConrad Meyer int slot; 613f2cc1285SJeff Roberson 6143c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 615f2cc1285SJeff Roberson if (node == NULL) 616f2cc1285SJeff Roberson return (NULL); 617f2cc1285SJeff Roberson else if (pctrie_isleaf(node)) { 618f2cc1285SJeff Roberson m = pctrie_toval(node); 619f2cc1285SJeff Roberson if (*m <= index) 620f2cc1285SJeff Roberson return (m); 621f2cc1285SJeff Roberson else 622f2cc1285SJeff Roberson return (NULL); 623f2cc1285SJeff Roberson } 624f2cc1285SJeff Roberson tos = 0; 625f2cc1285SJeff Roberson for (;;) { 626f2cc1285SJeff Roberson /* 627f2cc1285SJeff Roberson * If the keys differ before the current bisection node, 628f2cc1285SJeff Roberson * then the search key might rollback to the earliest 629f2cc1285SJeff Roberson * available bisection node or to the largest key 630f2cc1285SJeff Roberson * in the current node (if the owner is smaller than the 631f2cc1285SJeff Roberson * search key). 632f2cc1285SJeff Roberson */ 633f2cc1285SJeff Roberson if (pctrie_keybarr(node, index)) { 634f2cc1285SJeff Roberson if (index > node->pn_owner) { 635f2cc1285SJeff Roberson index = node->pn_owner + PCTRIE_COUNT * 636f2cc1285SJeff Roberson PCTRIE_UNITLEVEL(node->pn_clev); 637f2cc1285SJeff Roberson } else { 638f2cc1285SJeff Roberson ascend: 639f2cc1285SJeff Roberson KASSERT(++loops < 1000, 640f2cc1285SJeff Roberson ("pctrie_lookup_le: too many loops")); 641f2cc1285SJeff Roberson 642f2cc1285SJeff Roberson /* 643f2cc1285SJeff Roberson * Pop nodes from the stack until either the 644f2cc1285SJeff Roberson * stack is empty or a node that could have a 645f2cc1285SJeff Roberson * matching descendant is found. 646f2cc1285SJeff Roberson */ 647f2cc1285SJeff Roberson do { 648f2cc1285SJeff Roberson if (tos == 0) 649f2cc1285SJeff Roberson return (NULL); 650f2cc1285SJeff Roberson node = stack[--tos]; 651f2cc1285SJeff Roberson } while (pctrie_slot(index, 652f2cc1285SJeff Roberson node->pn_clev) == 0); 653f2cc1285SJeff Roberson 654f2cc1285SJeff Roberson /* 655f2cc1285SJeff Roberson * The following computation cannot overflow 656f2cc1285SJeff Roberson * because index's slot at the current level 657f2cc1285SJeff Roberson * is greater than 0. 658f2cc1285SJeff Roberson */ 659f2cc1285SJeff Roberson index = pctrie_trimkey(index, 660f2cc1285SJeff Roberson node->pn_clev); 661f2cc1285SJeff Roberson } 662f2cc1285SJeff Roberson index--; 663f2cc1285SJeff Roberson KASSERT(!pctrie_keybarr(node, index), 664f2cc1285SJeff Roberson ("pctrie_lookup_le: keybarr failed")); 665f2cc1285SJeff Roberson } 666f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 6673c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], NULL, 6683c30b235SConrad Meyer PCTRIE_LOCKED); 669f2cc1285SJeff Roberson if (pctrie_isleaf(child)) { 670f2cc1285SJeff Roberson m = pctrie_toval(child); 671f2cc1285SJeff Roberson if (*m <= index) 672f2cc1285SJeff Roberson return (m); 673f2cc1285SJeff Roberson } else if (child != NULL) 674f2cc1285SJeff Roberson goto descend; 675f2cc1285SJeff Roberson 676f2cc1285SJeff Roberson /* 677f2cc1285SJeff Roberson * Look for an available edge or value within the current 678f2cc1285SJeff Roberson * bisection node. 679f2cc1285SJeff Roberson */ 680f2cc1285SJeff Roberson if (slot > 0) { 681f2cc1285SJeff Roberson inc = PCTRIE_UNITLEVEL(node->pn_clev); 682f2cc1285SJeff Roberson index |= inc - 1; 683f2cc1285SJeff Roberson do { 684f2cc1285SJeff Roberson index -= inc; 685f2cc1285SJeff Roberson slot--; 6863c30b235SConrad Meyer child = pctrie_node_load(&node->pn_child[slot], 6873c30b235SConrad Meyer NULL, PCTRIE_LOCKED); 688f2cc1285SJeff Roberson if (pctrie_isleaf(child)) { 689f2cc1285SJeff Roberson m = pctrie_toval(child); 69072c3a43bSDoug Moore KASSERT(*m <= index, 69172c3a43bSDoug Moore ("pctrie_lookup_le: leaf > index")); 692f2cc1285SJeff Roberson return (m); 693f2cc1285SJeff Roberson } else if (child != NULL) 694f2cc1285SJeff Roberson goto descend; 695f2cc1285SJeff Roberson } while (slot > 0); 696f2cc1285SJeff Roberson } 697f2cc1285SJeff Roberson KASSERT(child == NULL || pctrie_isleaf(child), 698f2cc1285SJeff Roberson ("pctrie_lookup_le: child is radix node")); 699f2cc1285SJeff Roberson 700f2cc1285SJeff Roberson /* 701f2cc1285SJeff Roberson * If a value or edge smaller than the search slot is not found 702f2cc1285SJeff Roberson * in the current node, ascend to the next higher-level node. 703f2cc1285SJeff Roberson */ 704f2cc1285SJeff Roberson goto ascend; 705f2cc1285SJeff Roberson descend: 706f2cc1285SJeff Roberson KASSERT(node->pn_clev > 0, 707f2cc1285SJeff Roberson ("pctrie_lookup_le: pushing leaf's parent")); 708f2cc1285SJeff Roberson KASSERT(tos < PCTRIE_LIMIT, 709f2cc1285SJeff Roberson ("pctrie_lookup_le: stack overflow")); 710f2cc1285SJeff Roberson stack[tos++] = node; 711f2cc1285SJeff Roberson node = child; 712f2cc1285SJeff Roberson } 713f2cc1285SJeff Roberson } 714f2cc1285SJeff Roberson 715f2cc1285SJeff Roberson /* 716f2cc1285SJeff Roberson * Remove the specified index from the tree. 717f2cc1285SJeff Roberson * Panics if the key is not present. 718f2cc1285SJeff Roberson */ 719f2cc1285SJeff Roberson void 720f2cc1285SJeff Roberson pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn) 721f2cc1285SJeff Roberson { 7223c30b235SConrad Meyer struct pctrie_node *node, *parent, *tmp; 723f2cc1285SJeff Roberson uint64_t *m; 724f2cc1285SJeff Roberson int i, slot; 725f2cc1285SJeff Roberson 7263c30b235SConrad Meyer node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 727f2cc1285SJeff Roberson if (pctrie_isleaf(node)) { 728f2cc1285SJeff Roberson m = pctrie_toval(node); 729f2cc1285SJeff Roberson if (*m != index) 730f2cc1285SJeff Roberson panic("%s: invalid key found", __func__); 7313c30b235SConrad Meyer pctrie_root_store(ptree, NULL, PCTRIE_LOCKED); 732f2cc1285SJeff Roberson return; 733f2cc1285SJeff Roberson } 734f2cc1285SJeff Roberson parent = NULL; 735f2cc1285SJeff Roberson for (;;) { 736f2cc1285SJeff Roberson if (node == NULL) 737f2cc1285SJeff Roberson panic("pctrie_remove: impossible to locate the key"); 738f2cc1285SJeff Roberson slot = pctrie_slot(index, node->pn_clev); 7393c30b235SConrad Meyer tmp = pctrie_node_load(&node->pn_child[slot], NULL, 7403c30b235SConrad Meyer PCTRIE_LOCKED); 7413c30b235SConrad Meyer if (pctrie_isleaf(tmp)) { 7423c30b235SConrad Meyer m = pctrie_toval(tmp); 743f2cc1285SJeff Roberson if (*m != index) 744f2cc1285SJeff Roberson panic("%s: invalid key found", __func__); 7453c30b235SConrad Meyer pctrie_node_store(&node->pn_child[slot], NULL, 7463c30b235SConrad Meyer PCTRIE_LOCKED); 747f2cc1285SJeff Roberson node->pn_count--; 748f2cc1285SJeff Roberson if (node->pn_count > 1) 749f2cc1285SJeff Roberson break; 7503c30b235SConrad Meyer for (i = 0; i < PCTRIE_COUNT; i++) { 7513c30b235SConrad Meyer tmp = pctrie_node_load(&node->pn_child[i], 7523c30b235SConrad Meyer NULL, PCTRIE_LOCKED); 7533c30b235SConrad Meyer if (tmp != NULL) 754f2cc1285SJeff Roberson break; 7553c30b235SConrad Meyer } 756e8efee29SDoug Moore KASSERT(tmp != NULL, 757f2cc1285SJeff Roberson ("%s: invalid node configuration", __func__)); 758f2cc1285SJeff Roberson if (parent == NULL) 7593c30b235SConrad Meyer pctrie_root_store(ptree, tmp, PCTRIE_LOCKED); 760f2cc1285SJeff Roberson else { 761f2cc1285SJeff Roberson slot = pctrie_slot(index, parent->pn_clev); 7623c30b235SConrad Meyer KASSERT(pctrie_node_load( 7633c30b235SConrad Meyer &parent->pn_child[slot], NULL, 7643c30b235SConrad Meyer PCTRIE_LOCKED) == node, 765f2cc1285SJeff Roberson ("%s: invalid child value", __func__)); 7663c30b235SConrad Meyer pctrie_node_store(&parent->pn_child[slot], tmp, 7673c30b235SConrad Meyer PCTRIE_LOCKED); 768f2cc1285SJeff Roberson } 7693c30b235SConrad Meyer /* 7703c30b235SConrad Meyer * The child is still valid and we can not zero the 7713c30b235SConrad Meyer * pointer until all SMR references are gone. 7723c30b235SConrad Meyer */ 773f2cc1285SJeff Roberson node->pn_count--; 7743c30b235SConrad Meyer pctrie_node_put(ptree, node, freefn, i); 775f2cc1285SJeff Roberson break; 776f2cc1285SJeff Roberson } 777f2cc1285SJeff Roberson parent = node; 7783c30b235SConrad Meyer node = tmp; 779f2cc1285SJeff Roberson } 780f2cc1285SJeff Roberson } 781f2cc1285SJeff Roberson 782f2cc1285SJeff Roberson /* 783f2cc1285SJeff Roberson * Remove and free all the nodes from the tree. 784f2cc1285SJeff Roberson * This function is recursive but there is a tight control on it as the 785f2cc1285SJeff Roberson * maximum depth of the tree is fixed. 786f2cc1285SJeff Roberson */ 787f2cc1285SJeff Roberson void 788f2cc1285SJeff Roberson pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn) 789f2cc1285SJeff Roberson { 790f2cc1285SJeff Roberson struct pctrie_node *root; 791f2cc1285SJeff Roberson 7923c30b235SConrad Meyer root = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); 793f2cc1285SJeff Roberson if (root == NULL) 794f2cc1285SJeff Roberson return; 7953c30b235SConrad Meyer pctrie_root_store(ptree, NULL, PCTRIE_UNSERIALIZED); 796f2cc1285SJeff Roberson if (!pctrie_isleaf(root)) 797f2cc1285SJeff Roberson pctrie_reclaim_allnodes_int(ptree, root, freefn); 798f2cc1285SJeff Roberson } 799f2cc1285SJeff Roberson 800f2cc1285SJeff Roberson #ifdef DDB 801f2cc1285SJeff Roberson /* 802f2cc1285SJeff Roberson * Show details about the given node. 803f2cc1285SJeff Roberson */ 804f2cc1285SJeff Roberson DB_SHOW_COMMAND(pctrienode, db_show_pctrienode) 805f2cc1285SJeff Roberson { 8063c30b235SConrad Meyer struct pctrie_node *node, *tmp; 807f2cc1285SJeff Roberson int i; 808f2cc1285SJeff Roberson 809f2cc1285SJeff Roberson if (!have_addr) 810f2cc1285SJeff Roberson return; 811f2cc1285SJeff Roberson node = (struct pctrie_node *)addr; 812f2cc1285SJeff Roberson db_printf("node %p, owner %jx, children count %u, level %u:\n", 813f2cc1285SJeff Roberson (void *)node, (uintmax_t)node->pn_owner, node->pn_count, 814f2cc1285SJeff Roberson node->pn_clev); 8153c30b235SConrad Meyer for (i = 0; i < PCTRIE_COUNT; i++) { 8163c30b235SConrad Meyer tmp = pctrie_node_load(&node->pn_child[i], NULL, 8173c30b235SConrad Meyer PCTRIE_UNSERIALIZED); 8183c30b235SConrad Meyer if (tmp != NULL) 819f2cc1285SJeff Roberson db_printf("slot: %d, val: %p, value: %p, clev: %d\n", 8203c30b235SConrad Meyer i, (void *)tmp, 8213c30b235SConrad Meyer pctrie_isleaf(tmp) ? pctrie_toval(tmp) : NULL, 822f2cc1285SJeff Roberson node->pn_clev); 823f2cc1285SJeff Roberson } 8243c30b235SConrad Meyer } 825f2cc1285SJeff Roberson #endif /* DDB */ 826