xref: /freebsd/sys/kern/subr_pctrie.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
18a36da99SPedro F. Giffuni /*-
2*4d846d26SWarner 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>
57f2cc1285SJeff Roberson #include <sys/pctrie.h>
583c30b235SConrad Meyer #include <sys/proc.h>	/* smr.h depends on struct thread. */
593c30b235SConrad Meyer #include <sys/smr.h>
603c30b235SConrad Meyer #include <sys/smr_types.h>
61f2cc1285SJeff Roberson 
62f2cc1285SJeff Roberson #ifdef DDB
63f2cc1285SJeff Roberson #include <ddb/ddb.h>
64f2cc1285SJeff Roberson #endif
65f2cc1285SJeff Roberson 
66f2cc1285SJeff Roberson #define	PCTRIE_MASK	(PCTRIE_COUNT - 1)
6755e0987aSPedro F. Giffuni #define	PCTRIE_LIMIT	(howmany(sizeof(uint64_t) * NBBY, PCTRIE_WIDTH) - 1)
68f2cc1285SJeff Roberson 
69f2cc1285SJeff Roberson /* Flag bits stored in node pointers. */
70f2cc1285SJeff Roberson #define	PCTRIE_ISLEAF	0x1
71f2cc1285SJeff Roberson #define	PCTRIE_FLAGS	0x1
72f2cc1285SJeff Roberson #define	PCTRIE_PAD	PCTRIE_FLAGS
73f2cc1285SJeff Roberson 
74f2cc1285SJeff Roberson /* Returns one unit associated with specified level. */
75f2cc1285SJeff Roberson #define	PCTRIE_UNITLEVEL(lev)						\
76f2cc1285SJeff Roberson 	((uint64_t)1 << ((lev) * PCTRIE_WIDTH))
77f2cc1285SJeff Roberson 
783c30b235SConrad Meyer struct pctrie_node;
793c30b235SConrad Meyer typedef SMR_POINTER(struct pctrie_node *) smr_pctnode_t;
803c30b235SConrad Meyer 
81f2cc1285SJeff Roberson struct pctrie_node {
82f2cc1285SJeff Roberson 	uint64_t	pn_owner;			/* Owner of record. */
83f2cc1285SJeff Roberson 	uint16_t	pn_count;			/* Valid children. */
843c30b235SConrad Meyer 	uint8_t		pn_clev;			/* Current level. */
853c30b235SConrad Meyer 	int8_t		pn_last;			/* Zero last ptr. */
863c30b235SConrad Meyer 	smr_pctnode_t	pn_child[PCTRIE_COUNT];		/* Child nodes. */
87f2cc1285SJeff Roberson };
88f2cc1285SJeff Roberson 
893c30b235SConrad Meyer enum pctrie_access { PCTRIE_SMR, PCTRIE_LOCKED, PCTRIE_UNSERIALIZED };
903c30b235SConrad Meyer 
913c30b235SConrad Meyer static __inline void pctrie_node_store(smr_pctnode_t *p, void *val,
923c30b235SConrad Meyer     enum pctrie_access access);
933c30b235SConrad Meyer 
94f2cc1285SJeff Roberson /*
95f2cc1285SJeff Roberson  * Allocate a node.  Pre-allocation should ensure that the request
96f2cc1285SJeff Roberson  * will always be satisfied.
97f2cc1285SJeff Roberson  */
983c30b235SConrad Meyer static struct pctrie_node *
99f2cc1285SJeff Roberson pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t owner,
100f2cc1285SJeff Roberson     uint16_t count, uint16_t clevel)
101f2cc1285SJeff Roberson {
102f2cc1285SJeff Roberson 	struct pctrie_node *node;
103f2cc1285SJeff Roberson 
104f2cc1285SJeff Roberson 	node = allocfn(ptree);
105f2cc1285SJeff Roberson 	if (node == NULL)
106f2cc1285SJeff Roberson 		return (NULL);
1073c30b235SConrad Meyer 
1083c30b235SConrad Meyer 	/*
1093c30b235SConrad Meyer 	 * We want to clear the last child pointer after the final section
1103c30b235SConrad Meyer 	 * has exited so lookup can not return false negatives.  It is done
1113c30b235SConrad Meyer 	 * here because it will be cache-cold in the dtor callback.
1123c30b235SConrad Meyer 	 */
1133c30b235SConrad Meyer 	if (node->pn_last != 0) {
1143c30b235SConrad Meyer 		pctrie_node_store(&node->pn_child[node->pn_last - 1], NULL,
1153c30b235SConrad Meyer 		    PCTRIE_UNSERIALIZED);
1163c30b235SConrad Meyer 		node->pn_last = 0;
1173c30b235SConrad Meyer 	}
118f2cc1285SJeff Roberson 	node->pn_owner = owner;
119f2cc1285SJeff Roberson 	node->pn_count = count;
120f2cc1285SJeff Roberson 	node->pn_clev = clevel;
121f2cc1285SJeff Roberson 	return (node);
122f2cc1285SJeff Roberson }
123f2cc1285SJeff Roberson 
124f2cc1285SJeff Roberson /*
125f2cc1285SJeff Roberson  * Free radix node.
126f2cc1285SJeff Roberson  */
127f2cc1285SJeff Roberson static __inline void
128f2cc1285SJeff Roberson pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node,
1293c30b235SConrad Meyer     pctrie_free_t freefn, int8_t last)
130f2cc1285SJeff Roberson {
131f2cc1285SJeff Roberson #ifdef INVARIANTS
132f2cc1285SJeff Roberson 	int slot;
133f2cc1285SJeff Roberson 
134f2cc1285SJeff Roberson 	KASSERT(node->pn_count == 0,
135f2cc1285SJeff Roberson 	    ("pctrie_node_put: node %p has %d children", node,
136f2cc1285SJeff Roberson 	    node->pn_count));
1373c30b235SConrad Meyer 	for (slot = 0; slot < PCTRIE_COUNT; slot++) {
1383c30b235SConrad Meyer 		if (slot == last)
1393c30b235SConrad Meyer 			continue;
1403c30b235SConrad Meyer 		KASSERT(smr_unserialized_load(&node->pn_child[slot], true) ==
1413c30b235SConrad Meyer 		    NULL, ("pctrie_node_put: node %p has a child", node));
1423c30b235SConrad Meyer 	}
143f2cc1285SJeff Roberson #endif
1443c30b235SConrad Meyer 	node->pn_last = last + 1;
145f2cc1285SJeff Roberson 	freefn(ptree, node);
146f2cc1285SJeff Roberson }
147f2cc1285SJeff Roberson 
148f2cc1285SJeff Roberson /*
149f2cc1285SJeff Roberson  * Return the position in the array for a given level.
150f2cc1285SJeff Roberson  */
151f2cc1285SJeff Roberson static __inline int
152f2cc1285SJeff Roberson pctrie_slot(uint64_t index, uint16_t level)
153f2cc1285SJeff Roberson {
154f2cc1285SJeff Roberson 
155f2cc1285SJeff Roberson 	return ((index >> (level * PCTRIE_WIDTH)) & PCTRIE_MASK);
156f2cc1285SJeff Roberson }
157f2cc1285SJeff Roberson 
158f2cc1285SJeff Roberson /* Trims the key after the specified level. */
159f2cc1285SJeff Roberson static __inline uint64_t
160f2cc1285SJeff Roberson pctrie_trimkey(uint64_t index, uint16_t level)
161f2cc1285SJeff Roberson {
162f2cc1285SJeff Roberson 	uint64_t ret;
163f2cc1285SJeff Roberson 
164f2cc1285SJeff Roberson 	ret = index;
165f2cc1285SJeff Roberson 	if (level > 0) {
166f2cc1285SJeff Roberson 		ret >>= level * PCTRIE_WIDTH;
167f2cc1285SJeff Roberson 		ret <<= level * PCTRIE_WIDTH;
168f2cc1285SJeff Roberson 	}
169f2cc1285SJeff Roberson 	return (ret);
170f2cc1285SJeff Roberson }
171f2cc1285SJeff Roberson 
172f2cc1285SJeff Roberson /*
1733c30b235SConrad Meyer  * Fetch a node pointer from a slot.
1743c30b235SConrad Meyer  */
1753c30b235SConrad Meyer static __inline struct pctrie_node *
1763c30b235SConrad Meyer pctrie_node_load(smr_pctnode_t *p, smr_t smr, enum pctrie_access access)
1773c30b235SConrad Meyer {
1783c30b235SConrad Meyer 	switch (access) {
1793c30b235SConrad Meyer 	case PCTRIE_UNSERIALIZED:
1803c30b235SConrad Meyer 		return (smr_unserialized_load(p, true));
1813c30b235SConrad Meyer 	case PCTRIE_LOCKED:
1823c30b235SConrad Meyer 		return (smr_serialized_load(p, true));
1833c30b235SConrad Meyer 	case PCTRIE_SMR:
1843c30b235SConrad Meyer 		return (smr_entered_load(p, smr));
1853c30b235SConrad Meyer 	}
1863c30b235SConrad Meyer 	__assert_unreachable();
1873c30b235SConrad Meyer }
1883c30b235SConrad Meyer 
1893c30b235SConrad Meyer static __inline void
1903c30b235SConrad Meyer pctrie_node_store(smr_pctnode_t *p, void *v, enum pctrie_access access)
1913c30b235SConrad Meyer {
1923c30b235SConrad Meyer 	switch (access) {
1933c30b235SConrad Meyer 	case PCTRIE_UNSERIALIZED:
1943c30b235SConrad Meyer 		smr_unserialized_store(p, v, true);
1953c30b235SConrad Meyer 		break;
1963c30b235SConrad Meyer 	case PCTRIE_LOCKED:
1973c30b235SConrad Meyer 		smr_serialized_store(p, v, true);
1983c30b235SConrad Meyer 		break;
1993c30b235SConrad Meyer 	case PCTRIE_SMR:
2003c30b235SConrad Meyer 		panic("%s: Not supported in SMR section.", __func__);
2013c30b235SConrad Meyer 		break;
2023c30b235SConrad Meyer 	default:
2033c30b235SConrad Meyer 		__assert_unreachable();
2043c30b235SConrad Meyer 		break;
2053c30b235SConrad Meyer 	}
2063c30b235SConrad Meyer }
2073c30b235SConrad Meyer 
2083c30b235SConrad Meyer /*
209f2cc1285SJeff Roberson  * Get the root node for a tree.
210f2cc1285SJeff Roberson  */
211f2cc1285SJeff Roberson static __inline struct pctrie_node *
2123c30b235SConrad Meyer pctrie_root_load(struct pctrie *ptree, smr_t smr, enum pctrie_access access)
213f2cc1285SJeff Roberson {
2143c30b235SConrad Meyer 	return (pctrie_node_load((smr_pctnode_t *)&ptree->pt_root, smr, access));
215f2cc1285SJeff Roberson }
216f2cc1285SJeff Roberson 
217f2cc1285SJeff Roberson /*
218f2cc1285SJeff Roberson  * Set the root node for a tree.
219f2cc1285SJeff Roberson  */
220f2cc1285SJeff Roberson static __inline void
2213c30b235SConrad Meyer pctrie_root_store(struct pctrie *ptree, struct pctrie_node *node,
2223c30b235SConrad Meyer     enum pctrie_access access)
223f2cc1285SJeff Roberson {
2243c30b235SConrad Meyer 	pctrie_node_store((smr_pctnode_t *)&ptree->pt_root, node, access);
225f2cc1285SJeff Roberson }
226f2cc1285SJeff Roberson 
227f2cc1285SJeff Roberson /*
228f2cc1285SJeff Roberson  * Returns TRUE if the specified node is a leaf and FALSE otherwise.
229f2cc1285SJeff Roberson  */
23004f9afaeSConrad Meyer static __inline bool
231f2cc1285SJeff Roberson pctrie_isleaf(struct pctrie_node *node)
232f2cc1285SJeff Roberson {
233f2cc1285SJeff Roberson 
234f2cc1285SJeff Roberson 	return (((uintptr_t)node & PCTRIE_ISLEAF) != 0);
235f2cc1285SJeff Roberson }
236f2cc1285SJeff Roberson 
237f2cc1285SJeff Roberson /*
238f2cc1285SJeff Roberson  * Returns the associated val extracted from node.
239f2cc1285SJeff Roberson  */
240f2cc1285SJeff Roberson static __inline uint64_t *
241f2cc1285SJeff Roberson pctrie_toval(struct pctrie_node *node)
242f2cc1285SJeff Roberson {
243f2cc1285SJeff Roberson 
244f2cc1285SJeff Roberson 	return ((uint64_t *)((uintptr_t)node & ~PCTRIE_FLAGS));
245f2cc1285SJeff Roberson }
246f2cc1285SJeff Roberson 
247f2cc1285SJeff Roberson /*
248f2cc1285SJeff Roberson  * Adds the val as a child of the provided node.
249f2cc1285SJeff Roberson  */
250f2cc1285SJeff Roberson static __inline void
251f2cc1285SJeff Roberson pctrie_addval(struct pctrie_node *node, uint64_t index, uint16_t clev,
2523c30b235SConrad Meyer     uint64_t *val, enum pctrie_access access)
253f2cc1285SJeff Roberson {
254f2cc1285SJeff Roberson 	int slot;
255f2cc1285SJeff Roberson 
256f2cc1285SJeff Roberson 	slot = pctrie_slot(index, clev);
2573c30b235SConrad Meyer 	pctrie_node_store(&node->pn_child[slot],
2583c30b235SConrad Meyer 	    (void *)((uintptr_t)val | PCTRIE_ISLEAF), access);
259f2cc1285SJeff Roberson }
260f2cc1285SJeff Roberson 
261f2cc1285SJeff Roberson /*
262f2cc1285SJeff Roberson  * Returns the slot where two keys differ.
263f2cc1285SJeff Roberson  * It cannot accept 2 equal keys.
264f2cc1285SJeff Roberson  */
265f2cc1285SJeff Roberson static __inline uint16_t
266f2cc1285SJeff Roberson pctrie_keydiff(uint64_t index1, uint64_t index2)
267f2cc1285SJeff Roberson {
268f2cc1285SJeff Roberson 	uint16_t clev;
269f2cc1285SJeff Roberson 
270f2cc1285SJeff Roberson 	KASSERT(index1 != index2, ("%s: passing the same key value %jx",
271f2cc1285SJeff Roberson 	    __func__, (uintmax_t)index1));
272f2cc1285SJeff Roberson 
273f2cc1285SJeff Roberson 	index1 ^= index2;
274f2cc1285SJeff Roberson 	for (clev = PCTRIE_LIMIT;; clev--)
275f2cc1285SJeff Roberson 		if (pctrie_slot(index1, clev) != 0)
276f2cc1285SJeff Roberson 			return (clev);
277f2cc1285SJeff Roberson }
278f2cc1285SJeff Roberson 
279f2cc1285SJeff Roberson /*
280f2cc1285SJeff Roberson  * Returns TRUE if it can be determined that key does not belong to the
281f2cc1285SJeff Roberson  * specified node.  Otherwise, returns FALSE.
282f2cc1285SJeff Roberson  */
28304f9afaeSConrad Meyer static __inline bool
284f2cc1285SJeff Roberson pctrie_keybarr(struct pctrie_node *node, uint64_t idx)
285f2cc1285SJeff Roberson {
286f2cc1285SJeff Roberson 
287f2cc1285SJeff Roberson 	if (node->pn_clev < PCTRIE_LIMIT) {
288f2cc1285SJeff Roberson 		idx = pctrie_trimkey(idx, node->pn_clev + 1);
289f2cc1285SJeff Roberson 		return (idx != node->pn_owner);
290f2cc1285SJeff Roberson 	}
29104f9afaeSConrad Meyer 	return (false);
292f2cc1285SJeff Roberson }
293f2cc1285SJeff Roberson 
294f2cc1285SJeff Roberson /*
295f2cc1285SJeff Roberson  * Internal helper for pctrie_reclaim_allnodes().
296f2cc1285SJeff Roberson  * This function is recursive.
297f2cc1285SJeff Roberson  */
298f2cc1285SJeff Roberson static void
299f2cc1285SJeff Roberson pctrie_reclaim_allnodes_int(struct pctrie *ptree, struct pctrie_node *node,
300f2cc1285SJeff Roberson     pctrie_free_t freefn)
301f2cc1285SJeff Roberson {
3023c30b235SConrad Meyer 	struct pctrie_node *child;
303f2cc1285SJeff Roberson 	int slot;
304f2cc1285SJeff Roberson 
305f2cc1285SJeff Roberson 	KASSERT(node->pn_count <= PCTRIE_COUNT,
306f2cc1285SJeff Roberson 	    ("pctrie_reclaim_allnodes_int: bad count in node %p", node));
307f2cc1285SJeff Roberson 	for (slot = 0; node->pn_count != 0; slot++) {
3083c30b235SConrad Meyer 		child = pctrie_node_load(&node->pn_child[slot], NULL,
3093c30b235SConrad Meyer 		    PCTRIE_UNSERIALIZED);
3103c30b235SConrad Meyer 		if (child == NULL)
311f2cc1285SJeff Roberson 			continue;
3123c30b235SConrad Meyer 		if (!pctrie_isleaf(child))
3133c30b235SConrad Meyer 			pctrie_reclaim_allnodes_int(ptree, child, freefn);
3143c30b235SConrad Meyer 		pctrie_node_store(&node->pn_child[slot], NULL,
3153c30b235SConrad Meyer 		    PCTRIE_UNSERIALIZED);
316f2cc1285SJeff Roberson 		node->pn_count--;
317f2cc1285SJeff Roberson 	}
3183c30b235SConrad Meyer 	pctrie_node_put(ptree, node, freefn, -1);
319f2cc1285SJeff Roberson }
320f2cc1285SJeff Roberson 
321f2cc1285SJeff Roberson /*
322f2cc1285SJeff Roberson  * pctrie node zone initializer.
323f2cc1285SJeff Roberson  */
324f2cc1285SJeff Roberson int
325f2cc1285SJeff Roberson pctrie_zone_init(void *mem, int size __unused, int flags __unused)
326f2cc1285SJeff Roberson {
327f2cc1285SJeff Roberson 	struct pctrie_node *node;
328f2cc1285SJeff Roberson 
329f2cc1285SJeff Roberson 	node = mem;
3303c30b235SConrad Meyer 	node->pn_last = 0;
331f2cc1285SJeff Roberson 	memset(node->pn_child, 0, sizeof(node->pn_child));
332f2cc1285SJeff Roberson 	return (0);
333f2cc1285SJeff Roberson }
334f2cc1285SJeff Roberson 
335f2cc1285SJeff Roberson size_t
336f2cc1285SJeff Roberson pctrie_node_size(void)
337f2cc1285SJeff Roberson {
338f2cc1285SJeff Roberson 
339f2cc1285SJeff Roberson 	return (sizeof(struct pctrie_node));
340f2cc1285SJeff Roberson }
341f2cc1285SJeff Roberson 
342f2cc1285SJeff Roberson /*
343f2cc1285SJeff Roberson  * Inserts the key-value pair into the trie.
344f2cc1285SJeff Roberson  * Panics if the key already exists.
345f2cc1285SJeff Roberson  */
346f2cc1285SJeff Roberson int
347f2cc1285SJeff Roberson pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn)
348f2cc1285SJeff Roberson {
349f2cc1285SJeff Roberson 	uint64_t index, newind;
350f2cc1285SJeff Roberson 	struct pctrie_node *node, *tmp;
3513c30b235SConrad Meyer 	smr_pctnode_t *parentp;
352f2cc1285SJeff Roberson 	uint64_t *m;
353f2cc1285SJeff Roberson 	int slot;
354f2cc1285SJeff Roberson 	uint16_t clev;
355f2cc1285SJeff Roberson 
356f2cc1285SJeff Roberson 	index = *val;
357f2cc1285SJeff Roberson 
358f2cc1285SJeff Roberson 	/*
359f2cc1285SJeff Roberson 	 * The owner of record for root is not really important because it
360f2cc1285SJeff Roberson 	 * will never be used.
361f2cc1285SJeff Roberson 	 */
3623c30b235SConrad Meyer 	node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED);
363f2cc1285SJeff Roberson 	if (node == NULL) {
364f2cc1285SJeff Roberson 		ptree->pt_root = (uintptr_t)val | PCTRIE_ISLEAF;
365f2cc1285SJeff Roberson 		return (0);
366f2cc1285SJeff Roberson 	}
3673c30b235SConrad Meyer 	parentp = (smr_pctnode_t *)&ptree->pt_root;
368f2cc1285SJeff Roberson 	for (;;) {
369f2cc1285SJeff Roberson 		if (pctrie_isleaf(node)) {
370f2cc1285SJeff Roberson 			m = pctrie_toval(node);
371f2cc1285SJeff Roberson 			if (*m == index)
372f2cc1285SJeff Roberson 				panic("%s: key %jx is already present",
373f2cc1285SJeff Roberson 				    __func__, (uintmax_t)index);
374f2cc1285SJeff Roberson 			clev = pctrie_keydiff(*m, index);
375f2cc1285SJeff Roberson 			tmp = pctrie_node_get(ptree, allocfn,
376f2cc1285SJeff Roberson 			    pctrie_trimkey(index, clev + 1), 2, clev);
377f2cc1285SJeff Roberson 			if (tmp == NULL)
378f2cc1285SJeff Roberson 				return (ENOMEM);
3793c30b235SConrad Meyer 			/* These writes are not yet visible due to ordering. */
3803c30b235SConrad Meyer 			pctrie_addval(tmp, index, clev, val,
3813c30b235SConrad Meyer 			    PCTRIE_UNSERIALIZED);
3823c30b235SConrad Meyer 			pctrie_addval(tmp, *m, clev, m, PCTRIE_UNSERIALIZED);
3833c30b235SConrad Meyer 			/* Synchronize to make leaf visible. */
3843c30b235SConrad Meyer 			pctrie_node_store(parentp, tmp, PCTRIE_LOCKED);
385f2cc1285SJeff Roberson 			return (0);
386f2cc1285SJeff Roberson 		} else if (pctrie_keybarr(node, index))
387f2cc1285SJeff Roberson 			break;
388f2cc1285SJeff Roberson 		slot = pctrie_slot(index, node->pn_clev);
3893c30b235SConrad Meyer 		parentp = &node->pn_child[slot];
3903c30b235SConrad Meyer 		tmp = pctrie_node_load(parentp, NULL, PCTRIE_LOCKED);
3913c30b235SConrad Meyer 		if (tmp == NULL) {
392f2cc1285SJeff Roberson 			node->pn_count++;
3933c30b235SConrad Meyer 			pctrie_addval(node, index, node->pn_clev, val,
3943c30b235SConrad Meyer 			    PCTRIE_LOCKED);
395f2cc1285SJeff Roberson 			return (0);
396f2cc1285SJeff Roberson 		}
3973c30b235SConrad Meyer 		node = tmp;
398f2cc1285SJeff Roberson 	}
399f2cc1285SJeff Roberson 
400f2cc1285SJeff Roberson 	/*
401f2cc1285SJeff Roberson 	 * A new node is needed because the right insertion level is reached.
402f2cc1285SJeff Roberson 	 * Setup the new intermediate node and add the 2 children: the
403f2cc1285SJeff Roberson 	 * new object and the older edge.
404f2cc1285SJeff Roberson 	 */
405f2cc1285SJeff Roberson 	newind = node->pn_owner;
406f2cc1285SJeff Roberson 	clev = pctrie_keydiff(newind, index);
407f2cc1285SJeff Roberson 	tmp = pctrie_node_get(ptree, allocfn,
408f2cc1285SJeff Roberson 	    pctrie_trimkey(index, clev + 1), 2, clev);
409f2cc1285SJeff Roberson 	if (tmp == NULL)
410f2cc1285SJeff Roberson 		return (ENOMEM);
411f2cc1285SJeff Roberson 	slot = pctrie_slot(newind, clev);
4123c30b235SConrad Meyer 	/* These writes are not yet visible due to ordering. */
4133c30b235SConrad Meyer 	pctrie_addval(tmp, index, clev, val, PCTRIE_UNSERIALIZED);
4143c30b235SConrad Meyer 	pctrie_node_store(&tmp->pn_child[slot], node, PCTRIE_UNSERIALIZED);
4153c30b235SConrad Meyer 	/* Synchronize to make the above visible. */
4163c30b235SConrad Meyer 	pctrie_node_store(parentp, tmp, PCTRIE_LOCKED);
417f2cc1285SJeff Roberson 
418f2cc1285SJeff Roberson 	return (0);
419f2cc1285SJeff Roberson }
420f2cc1285SJeff Roberson 
421f2cc1285SJeff Roberson /*
422f2cc1285SJeff Roberson  * Returns the value stored at the index.  If the index is not present,
423f2cc1285SJeff Roberson  * NULL is returned.
424f2cc1285SJeff Roberson  */
4253c30b235SConrad Meyer static __always_inline uint64_t *
4263c30b235SConrad Meyer _pctrie_lookup(struct pctrie *ptree, uint64_t index, smr_t smr,
4273c30b235SConrad Meyer     enum pctrie_access access)
428f2cc1285SJeff Roberson {
429f2cc1285SJeff Roberson 	struct pctrie_node *node;
430f2cc1285SJeff Roberson 	uint64_t *m;
431f2cc1285SJeff Roberson 	int slot;
432f2cc1285SJeff Roberson 
4333c30b235SConrad Meyer 	node = pctrie_root_load(ptree, smr, access);
434f2cc1285SJeff Roberson 	while (node != NULL) {
435f2cc1285SJeff Roberson 		if (pctrie_isleaf(node)) {
436f2cc1285SJeff Roberson 			m = pctrie_toval(node);
437f2cc1285SJeff Roberson 			if (*m == index)
438f2cc1285SJeff Roberson 				return (m);
439f2cc1285SJeff Roberson 			break;
4403c30b235SConrad Meyer 		}
4413c30b235SConrad Meyer 		if (pctrie_keybarr(node, index))
442f2cc1285SJeff Roberson 			break;
443f2cc1285SJeff Roberson 		slot = pctrie_slot(index, node->pn_clev);
4443c30b235SConrad Meyer 		node = pctrie_node_load(&node->pn_child[slot], smr, access);
445f2cc1285SJeff Roberson 	}
446f2cc1285SJeff Roberson 	return (NULL);
447f2cc1285SJeff Roberson }
448f2cc1285SJeff Roberson 
449f2cc1285SJeff Roberson /*
4503c30b235SConrad Meyer  * Returns the value stored at the index, assuming access is externally
4513c30b235SConrad Meyer  * synchronized by a lock.
4523c30b235SConrad Meyer  *
4533c30b235SConrad Meyer  * If the index is not present, NULL is returned.
4543c30b235SConrad Meyer  */
4553c30b235SConrad Meyer uint64_t *
4563c30b235SConrad Meyer pctrie_lookup(struct pctrie *ptree, uint64_t index)
4573c30b235SConrad Meyer {
4583c30b235SConrad Meyer 	return (_pctrie_lookup(ptree, index, NULL, PCTRIE_LOCKED));
4593c30b235SConrad Meyer }
4603c30b235SConrad Meyer 
4613c30b235SConrad Meyer /*
4623c30b235SConrad Meyer  * Returns the value stored at the index without requiring an external lock.
4633c30b235SConrad Meyer  *
4643c30b235SConrad Meyer  * If the index is not present, NULL is returned.
4653c30b235SConrad Meyer  */
4663c30b235SConrad Meyer uint64_t *
4673c30b235SConrad Meyer pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t index, smr_t smr)
4683c30b235SConrad Meyer {
4693c30b235SConrad Meyer 	uint64_t *res;
4703c30b235SConrad Meyer 
4713c30b235SConrad Meyer 	smr_enter(smr);
4723c30b235SConrad Meyer 	res = _pctrie_lookup(ptree, index, smr, PCTRIE_SMR);
4733c30b235SConrad Meyer 	smr_exit(smr);
4743c30b235SConrad Meyer 	return (res);
4753c30b235SConrad Meyer }
4763c30b235SConrad Meyer 
4773c30b235SConrad Meyer /*
4783c30b235SConrad Meyer  * Look up the nearest entry at a position bigger than or equal to index,
4793c30b235SConrad Meyer  * assuming access is externally synchronized by a lock.
480f2cc1285SJeff Roberson  */
481f2cc1285SJeff Roberson uint64_t *
482f2cc1285SJeff Roberson pctrie_lookup_ge(struct pctrie *ptree, uint64_t index)
483f2cc1285SJeff Roberson {
484f2cc1285SJeff Roberson 	struct pctrie_node *stack[PCTRIE_LIMIT];
485f2cc1285SJeff Roberson 	uint64_t inc;
486f2cc1285SJeff Roberson 	uint64_t *m;
487f2cc1285SJeff Roberson 	struct pctrie_node *child, *node;
488f2cc1285SJeff Roberson #ifdef INVARIANTS
489f2cc1285SJeff Roberson 	int loops = 0;
490f2cc1285SJeff Roberson #endif
491d1139b52SConrad Meyer 	unsigned tos;
492d1139b52SConrad Meyer 	int slot;
493f2cc1285SJeff Roberson 
4943c30b235SConrad Meyer 	node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED);
495f2cc1285SJeff Roberson 	if (node == NULL)
496f2cc1285SJeff Roberson 		return (NULL);
497f2cc1285SJeff Roberson 	else if (pctrie_isleaf(node)) {
498f2cc1285SJeff Roberson 		m = pctrie_toval(node);
499f2cc1285SJeff Roberson 		if (*m >= index)
500f2cc1285SJeff Roberson 			return (m);
501f2cc1285SJeff Roberson 		else
502f2cc1285SJeff Roberson 			return (NULL);
503f2cc1285SJeff Roberson 	}
504f2cc1285SJeff Roberson 	tos = 0;
505f2cc1285SJeff Roberson 	for (;;) {
506f2cc1285SJeff Roberson 		/*
507f2cc1285SJeff Roberson 		 * If the keys differ before the current bisection node,
508f2cc1285SJeff Roberson 		 * then the search key might rollback to the earliest
509f2cc1285SJeff Roberson 		 * available bisection node or to the smallest key
5103c30b235SConrad Meyer 		 * in the current node (if the owner is greater than the
511f2cc1285SJeff Roberson 		 * search key).
512f2cc1285SJeff Roberson 		 */
513f2cc1285SJeff Roberson 		if (pctrie_keybarr(node, index)) {
514f2cc1285SJeff Roberson 			if (index > node->pn_owner) {
515f2cc1285SJeff Roberson ascend:
516f2cc1285SJeff Roberson 				KASSERT(++loops < 1000,
517f2cc1285SJeff Roberson 				    ("pctrie_lookup_ge: too many loops"));
518f2cc1285SJeff Roberson 
519f2cc1285SJeff Roberson 				/*
520f2cc1285SJeff Roberson 				 * Pop nodes from the stack until either the
521f2cc1285SJeff Roberson 				 * stack is empty or a node that could have a
522f2cc1285SJeff Roberson 				 * matching descendant is found.
523f2cc1285SJeff Roberson 				 */
524f2cc1285SJeff Roberson 				do {
525f2cc1285SJeff Roberson 					if (tos == 0)
526f2cc1285SJeff Roberson 						return (NULL);
527f2cc1285SJeff Roberson 					node = stack[--tos];
528f2cc1285SJeff Roberson 				} while (pctrie_slot(index,
529f2cc1285SJeff Roberson 				    node->pn_clev) == (PCTRIE_COUNT - 1));
530f2cc1285SJeff Roberson 
531f2cc1285SJeff Roberson 				/*
532f2cc1285SJeff Roberson 				 * The following computation cannot overflow
533f2cc1285SJeff Roberson 				 * because index's slot at the current level
534f2cc1285SJeff Roberson 				 * is less than PCTRIE_COUNT - 1.
535f2cc1285SJeff Roberson 				 */
536f2cc1285SJeff Roberson 				index = pctrie_trimkey(index,
537f2cc1285SJeff Roberson 				    node->pn_clev);
538f2cc1285SJeff Roberson 				index += PCTRIE_UNITLEVEL(node->pn_clev);
539f2cc1285SJeff Roberson 			} else
540f2cc1285SJeff Roberson 				index = node->pn_owner;
541f2cc1285SJeff Roberson 			KASSERT(!pctrie_keybarr(node, index),
542f2cc1285SJeff Roberson 			    ("pctrie_lookup_ge: keybarr failed"));
543f2cc1285SJeff Roberson 		}
544f2cc1285SJeff Roberson 		slot = pctrie_slot(index, node->pn_clev);
5453c30b235SConrad Meyer 		child = pctrie_node_load(&node->pn_child[slot], NULL,
5463c30b235SConrad Meyer 		    PCTRIE_LOCKED);
547f2cc1285SJeff Roberson 		if (pctrie_isleaf(child)) {
548f2cc1285SJeff Roberson 			m = pctrie_toval(child);
549f2cc1285SJeff Roberson 			if (*m >= index)
550f2cc1285SJeff Roberson 				return (m);
551f2cc1285SJeff Roberson 		} else if (child != NULL)
552f2cc1285SJeff Roberson 			goto descend;
553f2cc1285SJeff Roberson 
554f2cc1285SJeff Roberson 		/*
555f2cc1285SJeff Roberson 		 * Look for an available edge or val within the current
556f2cc1285SJeff Roberson 		 * bisection node.
557f2cc1285SJeff Roberson 		 */
558f2cc1285SJeff Roberson                 if (slot < (PCTRIE_COUNT - 1)) {
559f2cc1285SJeff Roberson 			inc = PCTRIE_UNITLEVEL(node->pn_clev);
560f2cc1285SJeff Roberson 			index = pctrie_trimkey(index, node->pn_clev);
561f2cc1285SJeff Roberson 			do {
562f2cc1285SJeff Roberson 				index += inc;
563f2cc1285SJeff Roberson 				slot++;
5643c30b235SConrad Meyer 				child = pctrie_node_load(&node->pn_child[slot],
5653c30b235SConrad Meyer 				    NULL, PCTRIE_LOCKED);
566f2cc1285SJeff Roberson 				if (pctrie_isleaf(child)) {
567f2cc1285SJeff Roberson 					m = pctrie_toval(child);
568f2cc1285SJeff Roberson 					if (*m >= index)
569f2cc1285SJeff Roberson 						return (m);
570f2cc1285SJeff Roberson 				} else if (child != NULL)
571f2cc1285SJeff Roberson 					goto descend;
572f2cc1285SJeff Roberson 			} while (slot < (PCTRIE_COUNT - 1));
573f2cc1285SJeff Roberson 		}
574f2cc1285SJeff Roberson 		KASSERT(child == NULL || pctrie_isleaf(child),
575f2cc1285SJeff Roberson 		    ("pctrie_lookup_ge: child is radix node"));
576f2cc1285SJeff Roberson 
577f2cc1285SJeff Roberson 		/*
5783c30b235SConrad Meyer 		 * If a value or edge greater than the search slot is not found
579f2cc1285SJeff Roberson 		 * in the current node, ascend to the next higher-level node.
580f2cc1285SJeff Roberson 		 */
581f2cc1285SJeff Roberson 		goto ascend;
582f2cc1285SJeff Roberson descend:
583f2cc1285SJeff Roberson 		KASSERT(node->pn_clev > 0,
584f2cc1285SJeff Roberson 		    ("pctrie_lookup_ge: pushing leaf's parent"));
585f2cc1285SJeff Roberson 		KASSERT(tos < PCTRIE_LIMIT,
586f2cc1285SJeff Roberson 		    ("pctrie_lookup_ge: stack overflow"));
587f2cc1285SJeff Roberson 		stack[tos++] = node;
588f2cc1285SJeff Roberson 		node = child;
589f2cc1285SJeff Roberson 	}
590f2cc1285SJeff Roberson }
591f2cc1285SJeff Roberson 
592f2cc1285SJeff Roberson /*
5933c30b235SConrad Meyer  * Look up the nearest entry at a position less than or equal to index,
5943c30b235SConrad Meyer  * assuming access is externally synchronized by a lock.
595f2cc1285SJeff Roberson  */
596f2cc1285SJeff Roberson uint64_t *
597f2cc1285SJeff Roberson pctrie_lookup_le(struct pctrie *ptree, uint64_t index)
598f2cc1285SJeff Roberson {
599f2cc1285SJeff Roberson 	struct pctrie_node *stack[PCTRIE_LIMIT];
600f2cc1285SJeff Roberson 	uint64_t inc;
601f2cc1285SJeff Roberson 	uint64_t *m;
602f2cc1285SJeff Roberson 	struct pctrie_node *child, *node;
603f2cc1285SJeff Roberson #ifdef INVARIANTS
604f2cc1285SJeff Roberson 	int loops = 0;
605f2cc1285SJeff Roberson #endif
606d1139b52SConrad Meyer 	unsigned tos;
607d1139b52SConrad Meyer 	int slot;
608f2cc1285SJeff Roberson 
6093c30b235SConrad Meyer 	node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED);
610f2cc1285SJeff Roberson 	if (node == NULL)
611f2cc1285SJeff Roberson 		return (NULL);
612f2cc1285SJeff Roberson 	else if (pctrie_isleaf(node)) {
613f2cc1285SJeff Roberson 		m = pctrie_toval(node);
614f2cc1285SJeff Roberson 		if (*m <= index)
615f2cc1285SJeff Roberson 			return (m);
616f2cc1285SJeff Roberson 		else
617f2cc1285SJeff Roberson 			return (NULL);
618f2cc1285SJeff Roberson 	}
619f2cc1285SJeff Roberson 	tos = 0;
620f2cc1285SJeff Roberson 	for (;;) {
621f2cc1285SJeff Roberson 		/*
622f2cc1285SJeff Roberson 		 * If the keys differ before the current bisection node,
623f2cc1285SJeff Roberson 		 * then the search key might rollback to the earliest
624f2cc1285SJeff Roberson 		 * available bisection node or to the largest key
625f2cc1285SJeff Roberson 		 * in the current node (if the owner is smaller than the
626f2cc1285SJeff Roberson 		 * search key).
627f2cc1285SJeff Roberson 		 */
628f2cc1285SJeff Roberson 		if (pctrie_keybarr(node, index)) {
629f2cc1285SJeff Roberson 			if (index > node->pn_owner) {
630f2cc1285SJeff Roberson 				index = node->pn_owner + PCTRIE_COUNT *
631f2cc1285SJeff Roberson 				    PCTRIE_UNITLEVEL(node->pn_clev);
632f2cc1285SJeff Roberson 			} else {
633f2cc1285SJeff Roberson ascend:
634f2cc1285SJeff Roberson 				KASSERT(++loops < 1000,
635f2cc1285SJeff Roberson 				    ("pctrie_lookup_le: too many loops"));
636f2cc1285SJeff Roberson 
637f2cc1285SJeff Roberson 				/*
638f2cc1285SJeff Roberson 				 * Pop nodes from the stack until either the
639f2cc1285SJeff Roberson 				 * stack is empty or a node that could have a
640f2cc1285SJeff Roberson 				 * matching descendant is found.
641f2cc1285SJeff Roberson 				 */
642f2cc1285SJeff Roberson 				do {
643f2cc1285SJeff Roberson 					if (tos == 0)
644f2cc1285SJeff Roberson 						return (NULL);
645f2cc1285SJeff Roberson 					node = stack[--tos];
646f2cc1285SJeff Roberson 				} while (pctrie_slot(index,
647f2cc1285SJeff Roberson 				    node->pn_clev) == 0);
648f2cc1285SJeff Roberson 
649f2cc1285SJeff Roberson 				/*
650f2cc1285SJeff Roberson 				 * The following computation cannot overflow
651f2cc1285SJeff Roberson 				 * because index's slot at the current level
652f2cc1285SJeff Roberson 				 * is greater than 0.
653f2cc1285SJeff Roberson 				 */
654f2cc1285SJeff Roberson 				index = pctrie_trimkey(index,
655f2cc1285SJeff Roberson 				    node->pn_clev);
656f2cc1285SJeff Roberson 			}
657f2cc1285SJeff Roberson 			index--;
658f2cc1285SJeff Roberson 			KASSERT(!pctrie_keybarr(node, index),
659f2cc1285SJeff Roberson 			    ("pctrie_lookup_le: keybarr failed"));
660f2cc1285SJeff Roberson 		}
661f2cc1285SJeff Roberson 		slot = pctrie_slot(index, node->pn_clev);
6623c30b235SConrad Meyer 		child = pctrie_node_load(&node->pn_child[slot], NULL,
6633c30b235SConrad Meyer 		    PCTRIE_LOCKED);
664f2cc1285SJeff Roberson 		if (pctrie_isleaf(child)) {
665f2cc1285SJeff Roberson 			m = pctrie_toval(child);
666f2cc1285SJeff Roberson 			if (*m <= index)
667f2cc1285SJeff Roberson 				return (m);
668f2cc1285SJeff Roberson 		} else if (child != NULL)
669f2cc1285SJeff Roberson 			goto descend;
670f2cc1285SJeff Roberson 
671f2cc1285SJeff Roberson 		/*
672f2cc1285SJeff Roberson 		 * Look for an available edge or value within the current
673f2cc1285SJeff Roberson 		 * bisection node.
674f2cc1285SJeff Roberson 		 */
675f2cc1285SJeff Roberson 		if (slot > 0) {
676f2cc1285SJeff Roberson 			inc = PCTRIE_UNITLEVEL(node->pn_clev);
677f2cc1285SJeff Roberson 			index |= inc - 1;
678f2cc1285SJeff Roberson 			do {
679f2cc1285SJeff Roberson 				index -= inc;
680f2cc1285SJeff Roberson 				slot--;
6813c30b235SConrad Meyer 				child = pctrie_node_load(&node->pn_child[slot],
6823c30b235SConrad Meyer 				    NULL, PCTRIE_LOCKED);
683f2cc1285SJeff Roberson 				if (pctrie_isleaf(child)) {
684f2cc1285SJeff Roberson 					m = pctrie_toval(child);
685f2cc1285SJeff Roberson 					if (*m <= index)
686f2cc1285SJeff Roberson 						return (m);
687f2cc1285SJeff Roberson 				} else if (child != NULL)
688f2cc1285SJeff Roberson 					goto descend;
689f2cc1285SJeff Roberson 			} while (slot > 0);
690f2cc1285SJeff Roberson 		}
691f2cc1285SJeff Roberson 		KASSERT(child == NULL || pctrie_isleaf(child),
692f2cc1285SJeff Roberson 		    ("pctrie_lookup_le: child is radix node"));
693f2cc1285SJeff Roberson 
694f2cc1285SJeff Roberson 		/*
695f2cc1285SJeff Roberson 		 * If a value or edge smaller than the search slot is not found
696f2cc1285SJeff Roberson 		 * in the current node, ascend to the next higher-level node.
697f2cc1285SJeff Roberson 		 */
698f2cc1285SJeff Roberson 		goto ascend;
699f2cc1285SJeff Roberson descend:
700f2cc1285SJeff Roberson 		KASSERT(node->pn_clev > 0,
701f2cc1285SJeff Roberson 		    ("pctrie_lookup_le: pushing leaf's parent"));
702f2cc1285SJeff Roberson 		KASSERT(tos < PCTRIE_LIMIT,
703f2cc1285SJeff Roberson 		    ("pctrie_lookup_le: stack overflow"));
704f2cc1285SJeff Roberson 		stack[tos++] = node;
705f2cc1285SJeff Roberson 		node = child;
706f2cc1285SJeff Roberson 	}
707f2cc1285SJeff Roberson }
708f2cc1285SJeff Roberson 
709f2cc1285SJeff Roberson /*
710f2cc1285SJeff Roberson  * Remove the specified index from the tree.
711f2cc1285SJeff Roberson  * Panics if the key is not present.
712f2cc1285SJeff Roberson  */
713f2cc1285SJeff Roberson void
714f2cc1285SJeff Roberson pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn)
715f2cc1285SJeff Roberson {
7163c30b235SConrad Meyer 	struct pctrie_node *node, *parent, *tmp;
717f2cc1285SJeff Roberson 	uint64_t *m;
718f2cc1285SJeff Roberson 	int i, slot;
719f2cc1285SJeff Roberson 
7203c30b235SConrad Meyer 	node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED);
721f2cc1285SJeff Roberson 	if (pctrie_isleaf(node)) {
722f2cc1285SJeff Roberson 		m = pctrie_toval(node);
723f2cc1285SJeff Roberson 		if (*m != index)
724f2cc1285SJeff Roberson 			panic("%s: invalid key found", __func__);
7253c30b235SConrad Meyer 		pctrie_root_store(ptree, NULL, PCTRIE_LOCKED);
726f2cc1285SJeff Roberson 		return;
727f2cc1285SJeff Roberson 	}
728f2cc1285SJeff Roberson 	parent = NULL;
729f2cc1285SJeff Roberson 	for (;;) {
730f2cc1285SJeff Roberson 		if (node == NULL)
731f2cc1285SJeff Roberson 			panic("pctrie_remove: impossible to locate the key");
732f2cc1285SJeff Roberson 		slot = pctrie_slot(index, node->pn_clev);
7333c30b235SConrad Meyer 		tmp = pctrie_node_load(&node->pn_child[slot], NULL,
7343c30b235SConrad Meyer 		    PCTRIE_LOCKED);
7353c30b235SConrad Meyer 		if (pctrie_isleaf(tmp)) {
7363c30b235SConrad Meyer 			m = pctrie_toval(tmp);
737f2cc1285SJeff Roberson 			if (*m != index)
738f2cc1285SJeff Roberson 				panic("%s: invalid key found", __func__);
7393c30b235SConrad Meyer 			pctrie_node_store(&node->pn_child[slot], NULL,
7403c30b235SConrad Meyer 			    PCTRIE_LOCKED);
741f2cc1285SJeff Roberson 			node->pn_count--;
742f2cc1285SJeff Roberson 			if (node->pn_count > 1)
743f2cc1285SJeff Roberson 				break;
7443c30b235SConrad Meyer 			for (i = 0; i < PCTRIE_COUNT; i++) {
7453c30b235SConrad Meyer 				tmp = pctrie_node_load(&node->pn_child[i],
7463c30b235SConrad Meyer 				    NULL, PCTRIE_LOCKED);
7473c30b235SConrad Meyer 				if (tmp != NULL)
748f2cc1285SJeff Roberson 					break;
7493c30b235SConrad Meyer 			}
750f2cc1285SJeff Roberson 			KASSERT(i != PCTRIE_COUNT,
751f2cc1285SJeff Roberson 			    ("%s: invalid node configuration", __func__));
752f2cc1285SJeff Roberson 			if (parent == NULL)
7533c30b235SConrad Meyer 				pctrie_root_store(ptree, tmp, PCTRIE_LOCKED);
754f2cc1285SJeff Roberson 			else {
755f2cc1285SJeff Roberson 				slot = pctrie_slot(index, parent->pn_clev);
7563c30b235SConrad Meyer 				KASSERT(pctrie_node_load(
7573c30b235SConrad Meyer 					&parent->pn_child[slot], NULL,
7583c30b235SConrad Meyer 					PCTRIE_LOCKED) == node,
759f2cc1285SJeff Roberson 				    ("%s: invalid child value", __func__));
7603c30b235SConrad Meyer 				pctrie_node_store(&parent->pn_child[slot], tmp,
7613c30b235SConrad Meyer 				    PCTRIE_LOCKED);
762f2cc1285SJeff Roberson 			}
7633c30b235SConrad Meyer 			/*
7643c30b235SConrad Meyer 			 * The child is still valid and we can not zero the
7653c30b235SConrad Meyer 			 * pointer until all SMR references are gone.
7663c30b235SConrad Meyer 			 */
767f2cc1285SJeff Roberson 			node->pn_count--;
7683c30b235SConrad Meyer 			pctrie_node_put(ptree, node, freefn, i);
769f2cc1285SJeff Roberson 			break;
770f2cc1285SJeff Roberson 		}
771f2cc1285SJeff Roberson 		parent = node;
7723c30b235SConrad Meyer 		node = tmp;
773f2cc1285SJeff Roberson 	}
774f2cc1285SJeff Roberson }
775f2cc1285SJeff Roberson 
776f2cc1285SJeff Roberson /*
777f2cc1285SJeff Roberson  * Remove and free all the nodes from the tree.
778f2cc1285SJeff Roberson  * This function is recursive but there is a tight control on it as the
779f2cc1285SJeff Roberson  * maximum depth of the tree is fixed.
780f2cc1285SJeff Roberson  */
781f2cc1285SJeff Roberson void
782f2cc1285SJeff Roberson pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn)
783f2cc1285SJeff Roberson {
784f2cc1285SJeff Roberson 	struct pctrie_node *root;
785f2cc1285SJeff Roberson 
7863c30b235SConrad Meyer 	root = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED);
787f2cc1285SJeff Roberson 	if (root == NULL)
788f2cc1285SJeff Roberson 		return;
7893c30b235SConrad Meyer 	pctrie_root_store(ptree, NULL, PCTRIE_UNSERIALIZED);
790f2cc1285SJeff Roberson 	if (!pctrie_isleaf(root))
791f2cc1285SJeff Roberson 		pctrie_reclaim_allnodes_int(ptree, root, freefn);
792f2cc1285SJeff Roberson }
793f2cc1285SJeff Roberson 
794f2cc1285SJeff Roberson #ifdef DDB
795f2cc1285SJeff Roberson /*
796f2cc1285SJeff Roberson  * Show details about the given node.
797f2cc1285SJeff Roberson  */
798f2cc1285SJeff Roberson DB_SHOW_COMMAND(pctrienode, db_show_pctrienode)
799f2cc1285SJeff Roberson {
8003c30b235SConrad Meyer 	struct pctrie_node *node, *tmp;
801f2cc1285SJeff Roberson 	int i;
802f2cc1285SJeff Roberson 
803f2cc1285SJeff Roberson         if (!have_addr)
804f2cc1285SJeff Roberson                 return;
805f2cc1285SJeff Roberson 	node = (struct pctrie_node *)addr;
806f2cc1285SJeff Roberson 	db_printf("node %p, owner %jx, children count %u, level %u:\n",
807f2cc1285SJeff Roberson 	    (void *)node, (uintmax_t)node->pn_owner, node->pn_count,
808f2cc1285SJeff Roberson 	    node->pn_clev);
8093c30b235SConrad Meyer 	for (i = 0; i < PCTRIE_COUNT; i++) {
8103c30b235SConrad Meyer 		tmp = pctrie_node_load(&node->pn_child[i], NULL,
8113c30b235SConrad Meyer 		    PCTRIE_UNSERIALIZED);
8123c30b235SConrad Meyer 		if (tmp != NULL)
813f2cc1285SJeff Roberson 			db_printf("slot: %d, val: %p, value: %p, clev: %d\n",
8143c30b235SConrad Meyer 			    i, (void *)tmp,
8153c30b235SConrad Meyer 			    pctrie_isleaf(tmp) ? pctrie_toval(tmp) : NULL,
816f2cc1285SJeff Roberson 			    node->pn_clev);
817f2cc1285SJeff Roberson 	}
8183c30b235SConrad Meyer }
819f2cc1285SJeff Roberson #endif /* DDB */
820