18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky * Copyright (c) 2010 Panasas, Inc.
5*6b839ff4SHans Petter Selasky * Copyright (c) 2013-2020 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky * All rights reserved.
78d59ecb2SHans Petter Selasky *
88d59ecb2SHans Petter Selasky * Redistribution and use in source and binary forms, with or without
98d59ecb2SHans Petter Selasky * modification, are permitted provided that the following conditions
108d59ecb2SHans Petter Selasky * are met:
118d59ecb2SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright
128d59ecb2SHans Petter Selasky * notice unmodified, this list of conditions, and the following
138d59ecb2SHans Petter Selasky * disclaimer.
148d59ecb2SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright
158d59ecb2SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the
168d59ecb2SHans Petter Selasky * documentation and/or other materials provided with the distribution.
178d59ecb2SHans Petter Selasky *
188d59ecb2SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
198d59ecb2SHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
208d59ecb2SHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
218d59ecb2SHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
228d59ecb2SHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
238d59ecb2SHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
248d59ecb2SHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
258d59ecb2SHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268d59ecb2SHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278d59ecb2SHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288d59ecb2SHans Petter Selasky */
298d59ecb2SHans Petter Selasky
308d59ecb2SHans Petter Selasky #include <sys/param.h>
318d59ecb2SHans Petter Selasky #include <sys/systm.h>
328d59ecb2SHans Petter Selasky #include <sys/malloc.h>
338d59ecb2SHans Petter Selasky #include <sys/kernel.h>
348d59ecb2SHans Petter Selasky #include <sys/sysctl.h>
358d59ecb2SHans Petter Selasky
368d59ecb2SHans Petter Selasky #include <linux/slab.h>
378d59ecb2SHans Petter Selasky #include <linux/kernel.h>
388d59ecb2SHans Petter Selasky #include <linux/radix-tree.h>
398d59ecb2SHans Petter Selasky #include <linux/err.h>
408d59ecb2SHans Petter Selasky
418d59ecb2SHans Petter Selasky static MALLOC_DEFINE(M_RADIX, "radix", "Linux radix compat");
428d59ecb2SHans Petter Selasky
43ead15282SHans Petter Selasky static inline unsigned long
radix_max(struct radix_tree_root * root)448d59ecb2SHans Petter Selasky radix_max(struct radix_tree_root *root)
458d59ecb2SHans Petter Selasky {
46ead15282SHans Petter Selasky return ((1UL << (root->height * RADIX_TREE_MAP_SHIFT)) - 1UL);
478d59ecb2SHans Petter Selasky }
488d59ecb2SHans Petter Selasky
498d59ecb2SHans Petter Selasky static inline int
radix_pos(long id,int height)508d59ecb2SHans Petter Selasky radix_pos(long id, int height)
518d59ecb2SHans Petter Selasky {
528d59ecb2SHans Petter Selasky return (id >> (RADIX_TREE_MAP_SHIFT * height)) & RADIX_TREE_MAP_MASK;
538d59ecb2SHans Petter Selasky }
548d59ecb2SHans Petter Selasky
55*6b839ff4SHans Petter Selasky static void
radix_tree_clean_root_node(struct radix_tree_root * root)56*6b839ff4SHans Petter Selasky radix_tree_clean_root_node(struct radix_tree_root *root)
57*6b839ff4SHans Petter Selasky {
58*6b839ff4SHans Petter Selasky /* Check if the root node should be freed */
59*6b839ff4SHans Petter Selasky if (root->rnode->count == 0) {
60*6b839ff4SHans Petter Selasky free(root->rnode, M_RADIX);
61*6b839ff4SHans Petter Selasky root->rnode = NULL;
62*6b839ff4SHans Petter Selasky root->height = 0;
63*6b839ff4SHans Petter Selasky }
64*6b839ff4SHans Petter Selasky }
65*6b839ff4SHans Petter Selasky
668d59ecb2SHans Petter Selasky void *
radix_tree_lookup(struct radix_tree_root * root,unsigned long index)678d59ecb2SHans Petter Selasky radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
688d59ecb2SHans Petter Selasky {
698d59ecb2SHans Petter Selasky struct radix_tree_node *node;
708d59ecb2SHans Petter Selasky void *item;
718d59ecb2SHans Petter Selasky int height;
728d59ecb2SHans Petter Selasky
738d59ecb2SHans Petter Selasky item = NULL;
748d59ecb2SHans Petter Selasky node = root->rnode;
758d59ecb2SHans Petter Selasky height = root->height - 1;
768d59ecb2SHans Petter Selasky if (index > radix_max(root))
778d59ecb2SHans Petter Selasky goto out;
788d59ecb2SHans Petter Selasky while (height && node)
798d59ecb2SHans Petter Selasky node = node->slots[radix_pos(index, height--)];
808d59ecb2SHans Petter Selasky if (node)
818d59ecb2SHans Petter Selasky item = node->slots[radix_pos(index, 0)];
828d59ecb2SHans Petter Selasky
838d59ecb2SHans Petter Selasky out:
848d59ecb2SHans Petter Selasky return (item);
858d59ecb2SHans Petter Selasky }
868d59ecb2SHans Petter Selasky
87ead15282SHans Petter Selasky bool
radix_tree_iter_find(struct radix_tree_root * root,struct radix_tree_iter * iter,void *** pppslot)88ead15282SHans Petter Selasky radix_tree_iter_find(struct radix_tree_root *root, struct radix_tree_iter *iter,
89ead15282SHans Petter Selasky void ***pppslot)
90ead15282SHans Petter Selasky {
91ead15282SHans Petter Selasky struct radix_tree_node *node;
92ead15282SHans Petter Selasky unsigned long index = iter->index;
93ead15282SHans Petter Selasky int height;
94ead15282SHans Petter Selasky
95ead15282SHans Petter Selasky restart:
96ead15282SHans Petter Selasky node = root->rnode;
97ead15282SHans Petter Selasky if (node == NULL)
98ead15282SHans Petter Selasky return (false);
99ead15282SHans Petter Selasky height = root->height - 1;
100ead15282SHans Petter Selasky if (height == -1 || index > radix_max(root))
101ead15282SHans Petter Selasky return (false);
102ead15282SHans Petter Selasky do {
103ead15282SHans Petter Selasky unsigned long mask = RADIX_TREE_MAP_MASK << (RADIX_TREE_MAP_SHIFT * height);
104ead15282SHans Petter Selasky unsigned long step = 1UL << (RADIX_TREE_MAP_SHIFT * height);
105ead15282SHans Petter Selasky int pos = radix_pos(index, height);
106ead15282SHans Petter Selasky struct radix_tree_node *next;
107ead15282SHans Petter Selasky
108ead15282SHans Petter Selasky /* track last slot */
109ead15282SHans Petter Selasky *pppslot = node->slots + pos;
110ead15282SHans Petter Selasky
111ead15282SHans Petter Selasky next = node->slots[pos];
112ead15282SHans Petter Selasky if (next == NULL) {
113ead15282SHans Petter Selasky index += step;
1140f839f3aSHans Petter Selasky index &= -step;
115ead15282SHans Petter Selasky if ((index & mask) == 0)
116ead15282SHans Petter Selasky goto restart;
117ead15282SHans Petter Selasky } else {
118ead15282SHans Petter Selasky node = next;
119ead15282SHans Petter Selasky height--;
120ead15282SHans Petter Selasky }
121ead15282SHans Petter Selasky } while (height != -1);
122ead15282SHans Petter Selasky iter->index = index;
123ead15282SHans Petter Selasky return (true);
124ead15282SHans Petter Selasky }
125ead15282SHans Petter Selasky
1268d59ecb2SHans Petter Selasky void *
radix_tree_delete(struct radix_tree_root * root,unsigned long index)1278d59ecb2SHans Petter Selasky radix_tree_delete(struct radix_tree_root *root, unsigned long index)
1288d59ecb2SHans Petter Selasky {
1298d59ecb2SHans Petter Selasky struct radix_tree_node *stack[RADIX_TREE_MAX_HEIGHT];
1308d59ecb2SHans Petter Selasky struct radix_tree_node *node;
1318d59ecb2SHans Petter Selasky void *item;
1328d59ecb2SHans Petter Selasky int height;
1338d59ecb2SHans Petter Selasky int idx;
1348d59ecb2SHans Petter Selasky
1358d59ecb2SHans Petter Selasky item = NULL;
1368d59ecb2SHans Petter Selasky node = root->rnode;
1378d59ecb2SHans Petter Selasky height = root->height - 1;
1388d59ecb2SHans Petter Selasky if (index > radix_max(root))
1398d59ecb2SHans Petter Selasky goto out;
1408d59ecb2SHans Petter Selasky /*
1418d59ecb2SHans Petter Selasky * Find the node and record the path in stack.
1428d59ecb2SHans Petter Selasky */
1438d59ecb2SHans Petter Selasky while (height && node) {
1448d59ecb2SHans Petter Selasky stack[height] = node;
1458d59ecb2SHans Petter Selasky node = node->slots[radix_pos(index, height--)];
1468d59ecb2SHans Petter Selasky }
1478d59ecb2SHans Petter Selasky idx = radix_pos(index, 0);
1488d59ecb2SHans Petter Selasky if (node)
1498d59ecb2SHans Petter Selasky item = node->slots[idx];
1508d59ecb2SHans Petter Selasky /*
1518d59ecb2SHans Petter Selasky * If we removed something reduce the height of the tree.
1528d59ecb2SHans Petter Selasky */
1538d59ecb2SHans Petter Selasky if (item)
1548d59ecb2SHans Petter Selasky for (;;) {
1558d59ecb2SHans Petter Selasky node->slots[idx] = NULL;
1568d59ecb2SHans Petter Selasky node->count--;
1578d59ecb2SHans Petter Selasky if (node->count > 0)
1588d59ecb2SHans Petter Selasky break;
1598d59ecb2SHans Petter Selasky free(node, M_RADIX);
1608d59ecb2SHans Petter Selasky if (node == root->rnode) {
1618d59ecb2SHans Petter Selasky root->rnode = NULL;
1628d59ecb2SHans Petter Selasky root->height = 0;
1638d59ecb2SHans Petter Selasky break;
1648d59ecb2SHans Petter Selasky }
1658d59ecb2SHans Petter Selasky height++;
1668d59ecb2SHans Petter Selasky node = stack[height];
1678d59ecb2SHans Petter Selasky idx = radix_pos(index, height);
1688d59ecb2SHans Petter Selasky }
1698d59ecb2SHans Petter Selasky out:
1708d59ecb2SHans Petter Selasky return (item);
1718d59ecb2SHans Petter Selasky }
1728d59ecb2SHans Petter Selasky
1736fad8d17SHans Petter Selasky void
radix_tree_iter_delete(struct radix_tree_root * root,struct radix_tree_iter * iter,void ** slot)1746fad8d17SHans Petter Selasky radix_tree_iter_delete(struct radix_tree_root *root,
1756fad8d17SHans Petter Selasky struct radix_tree_iter *iter, void **slot)
1766fad8d17SHans Petter Selasky {
1776fad8d17SHans Petter Selasky radix_tree_delete(root, iter->index);
1786fad8d17SHans Petter Selasky }
1796fad8d17SHans Petter Selasky
1808d59ecb2SHans Petter Selasky int
radix_tree_insert(struct radix_tree_root * root,unsigned long index,void * item)1818d59ecb2SHans Petter Selasky radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
1828d59ecb2SHans Petter Selasky {
1838d59ecb2SHans Petter Selasky struct radix_tree_node *node;
1848d59ecb2SHans Petter Selasky struct radix_tree_node *temp[RADIX_TREE_MAX_HEIGHT - 1];
1858d59ecb2SHans Petter Selasky int height;
1868d59ecb2SHans Petter Selasky int idx;
1878d59ecb2SHans Petter Selasky
1888d59ecb2SHans Petter Selasky /* bail out upon insertion of a NULL item */
1898d59ecb2SHans Petter Selasky if (item == NULL)
1908d59ecb2SHans Petter Selasky return (-EINVAL);
1918d59ecb2SHans Petter Selasky
1928d59ecb2SHans Petter Selasky /* get root node, if any */
1938d59ecb2SHans Petter Selasky node = root->rnode;
1948d59ecb2SHans Petter Selasky
1958d59ecb2SHans Petter Selasky /* allocate root node, if any */
1968d59ecb2SHans Petter Selasky if (node == NULL) {
1978d59ecb2SHans Petter Selasky node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
1988d59ecb2SHans Petter Selasky if (node == NULL)
1998d59ecb2SHans Petter Selasky return (-ENOMEM);
2008d59ecb2SHans Petter Selasky root->rnode = node;
2018d59ecb2SHans Petter Selasky root->height++;
2028d59ecb2SHans Petter Selasky }
2038d59ecb2SHans Petter Selasky
2048d59ecb2SHans Petter Selasky /* expand radix tree as needed */
2058d59ecb2SHans Petter Selasky while (radix_max(root) < index) {
2068d59ecb2SHans Petter Selasky /* check if the radix tree is getting too big */
207*6b839ff4SHans Petter Selasky if (root->height == RADIX_TREE_MAX_HEIGHT) {
208*6b839ff4SHans Petter Selasky radix_tree_clean_root_node(root);
2098d59ecb2SHans Petter Selasky return (-E2BIG);
210*6b839ff4SHans Petter Selasky }
2118d59ecb2SHans Petter Selasky
2128d59ecb2SHans Petter Selasky /*
2138d59ecb2SHans Petter Selasky * If the root radix level is not empty, we need to
2148d59ecb2SHans Petter Selasky * allocate a new radix level:
2158d59ecb2SHans Petter Selasky */
2168d59ecb2SHans Petter Selasky if (node->count != 0) {
2178d59ecb2SHans Petter Selasky node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
218*6b839ff4SHans Petter Selasky if (node == NULL) {
219*6b839ff4SHans Petter Selasky /*
220*6b839ff4SHans Petter Selasky * Freeing the already allocated radix
221*6b839ff4SHans Petter Selasky * levels, if any, will be handled by
222*6b839ff4SHans Petter Selasky * the radix_tree_delete() function.
223*6b839ff4SHans Petter Selasky * This code path can only happen when
224*6b839ff4SHans Petter Selasky * the tree is not empty.
225*6b839ff4SHans Petter Selasky */
2268d59ecb2SHans Petter Selasky return (-ENOMEM);
227*6b839ff4SHans Petter Selasky }
2288d59ecb2SHans Petter Selasky node->slots[0] = root->rnode;
2298d59ecb2SHans Petter Selasky node->count++;
2308d59ecb2SHans Petter Selasky root->rnode = node;
2318d59ecb2SHans Petter Selasky }
2328d59ecb2SHans Petter Selasky root->height++;
2338d59ecb2SHans Petter Selasky }
2348d59ecb2SHans Petter Selasky
2358d59ecb2SHans Petter Selasky /* get radix tree height index */
2368d59ecb2SHans Petter Selasky height = root->height - 1;
2378d59ecb2SHans Petter Selasky
2388d59ecb2SHans Petter Selasky /* walk down the tree until the first missing node, if any */
2398d59ecb2SHans Petter Selasky for ( ; height != 0; height--) {
2408d59ecb2SHans Petter Selasky idx = radix_pos(index, height);
2418d59ecb2SHans Petter Selasky if (node->slots[idx] == NULL)
2428d59ecb2SHans Petter Selasky break;
2438d59ecb2SHans Petter Selasky node = node->slots[idx];
2448d59ecb2SHans Petter Selasky }
2458d59ecb2SHans Petter Selasky
2468d59ecb2SHans Petter Selasky /* allocate the missing radix levels, if any */
2478d59ecb2SHans Petter Selasky for (idx = 0; idx != height; idx++) {
2488d59ecb2SHans Petter Selasky temp[idx] = malloc(sizeof(*node), M_RADIX,
2498d59ecb2SHans Petter Selasky root->gfp_mask | M_ZERO);
2508d59ecb2SHans Petter Selasky if (temp[idx] == NULL) {
2518d59ecb2SHans Petter Selasky while (idx--)
2528d59ecb2SHans Petter Selasky free(temp[idx], M_RADIX);
253*6b839ff4SHans Petter Selasky radix_tree_clean_root_node(root);
2548d59ecb2SHans Petter Selasky return (-ENOMEM);
2558d59ecb2SHans Petter Selasky }
2568d59ecb2SHans Petter Selasky }
2578d59ecb2SHans Petter Selasky
2588d59ecb2SHans Petter Selasky /* setup new radix levels, if any */
2598d59ecb2SHans Petter Selasky for ( ; height != 0; height--) {
2608d59ecb2SHans Petter Selasky idx = radix_pos(index, height);
2618d59ecb2SHans Petter Selasky node->slots[idx] = temp[height - 1];
2628d59ecb2SHans Petter Selasky node->count++;
2638d59ecb2SHans Petter Selasky node = node->slots[idx];
2648d59ecb2SHans Petter Selasky }
2658d59ecb2SHans Petter Selasky
2668d59ecb2SHans Petter Selasky /*
2678d59ecb2SHans Petter Selasky * Insert and adjust count if the item does not already exist.
2688d59ecb2SHans Petter Selasky */
2698d59ecb2SHans Petter Selasky idx = radix_pos(index, 0);
2708d59ecb2SHans Petter Selasky if (node->slots[idx])
2718d59ecb2SHans Petter Selasky return (-EEXIST);
2728d59ecb2SHans Petter Selasky node->slots[idx] = item;
2738d59ecb2SHans Petter Selasky node->count++;
2748d59ecb2SHans Petter Selasky
2758d59ecb2SHans Petter Selasky return (0);
2768d59ecb2SHans Petter Selasky }
277*6b839ff4SHans Petter Selasky
278*6b839ff4SHans Petter Selasky int
radix_tree_store(struct radix_tree_root * root,unsigned long index,void ** ppitem)279*6b839ff4SHans Petter Selasky radix_tree_store(struct radix_tree_root *root, unsigned long index, void **ppitem)
280*6b839ff4SHans Petter Selasky {
281*6b839ff4SHans Petter Selasky struct radix_tree_node *node;
282*6b839ff4SHans Petter Selasky struct radix_tree_node *temp[RADIX_TREE_MAX_HEIGHT - 1];
283*6b839ff4SHans Petter Selasky void *pitem;
284*6b839ff4SHans Petter Selasky int height;
285*6b839ff4SHans Petter Selasky int idx;
286*6b839ff4SHans Petter Selasky
287*6b839ff4SHans Petter Selasky /*
288*6b839ff4SHans Petter Selasky * Inserting a NULL item means delete it. The old pointer is
289*6b839ff4SHans Petter Selasky * stored at the location pointed to by "ppitem".
290*6b839ff4SHans Petter Selasky */
291*6b839ff4SHans Petter Selasky if (*ppitem == NULL) {
292*6b839ff4SHans Petter Selasky *ppitem = radix_tree_delete(root, index);
293*6b839ff4SHans Petter Selasky return (0);
294*6b839ff4SHans Petter Selasky }
295*6b839ff4SHans Petter Selasky
296*6b839ff4SHans Petter Selasky /* get root node, if any */
297*6b839ff4SHans Petter Selasky node = root->rnode;
298*6b839ff4SHans Petter Selasky
299*6b839ff4SHans Petter Selasky /* allocate root node, if any */
300*6b839ff4SHans Petter Selasky if (node == NULL) {
301*6b839ff4SHans Petter Selasky node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
302*6b839ff4SHans Petter Selasky if (node == NULL)
303*6b839ff4SHans Petter Selasky return (-ENOMEM);
304*6b839ff4SHans Petter Selasky root->rnode = node;
305*6b839ff4SHans Petter Selasky root->height++;
306*6b839ff4SHans Petter Selasky }
307*6b839ff4SHans Petter Selasky
308*6b839ff4SHans Petter Selasky /* expand radix tree as needed */
309*6b839ff4SHans Petter Selasky while (radix_max(root) < index) {
310*6b839ff4SHans Petter Selasky /* check if the radix tree is getting too big */
311*6b839ff4SHans Petter Selasky if (root->height == RADIX_TREE_MAX_HEIGHT) {
312*6b839ff4SHans Petter Selasky radix_tree_clean_root_node(root);
313*6b839ff4SHans Petter Selasky return (-E2BIG);
314*6b839ff4SHans Petter Selasky }
315*6b839ff4SHans Petter Selasky
316*6b839ff4SHans Petter Selasky /*
317*6b839ff4SHans Petter Selasky * If the root radix level is not empty, we need to
318*6b839ff4SHans Petter Selasky * allocate a new radix level:
319*6b839ff4SHans Petter Selasky */
320*6b839ff4SHans Petter Selasky if (node->count != 0) {
321*6b839ff4SHans Petter Selasky node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
322*6b839ff4SHans Petter Selasky if (node == NULL) {
323*6b839ff4SHans Petter Selasky /*
324*6b839ff4SHans Petter Selasky * Freeing the already allocated radix
325*6b839ff4SHans Petter Selasky * levels, if any, will be handled by
326*6b839ff4SHans Petter Selasky * the radix_tree_delete() function.
327*6b839ff4SHans Petter Selasky * This code path can only happen when
328*6b839ff4SHans Petter Selasky * the tree is not empty.
329*6b839ff4SHans Petter Selasky */
330*6b839ff4SHans Petter Selasky return (-ENOMEM);
331*6b839ff4SHans Petter Selasky }
332*6b839ff4SHans Petter Selasky node->slots[0] = root->rnode;
333*6b839ff4SHans Petter Selasky node->count++;
334*6b839ff4SHans Petter Selasky root->rnode = node;
335*6b839ff4SHans Petter Selasky }
336*6b839ff4SHans Petter Selasky root->height++;
337*6b839ff4SHans Petter Selasky }
338*6b839ff4SHans Petter Selasky
339*6b839ff4SHans Petter Selasky /* get radix tree height index */
340*6b839ff4SHans Petter Selasky height = root->height - 1;
341*6b839ff4SHans Petter Selasky
342*6b839ff4SHans Petter Selasky /* walk down the tree until the first missing node, if any */
343*6b839ff4SHans Petter Selasky for ( ; height != 0; height--) {
344*6b839ff4SHans Petter Selasky idx = radix_pos(index, height);
345*6b839ff4SHans Petter Selasky if (node->slots[idx] == NULL)
346*6b839ff4SHans Petter Selasky break;
347*6b839ff4SHans Petter Selasky node = node->slots[idx];
348*6b839ff4SHans Petter Selasky }
349*6b839ff4SHans Petter Selasky
350*6b839ff4SHans Petter Selasky /* allocate the missing radix levels, if any */
351*6b839ff4SHans Petter Selasky for (idx = 0; idx != height; idx++) {
352*6b839ff4SHans Petter Selasky temp[idx] = malloc(sizeof(*node), M_RADIX,
353*6b839ff4SHans Petter Selasky root->gfp_mask | M_ZERO);
354*6b839ff4SHans Petter Selasky if (temp[idx] == NULL) {
355*6b839ff4SHans Petter Selasky while (idx--)
356*6b839ff4SHans Petter Selasky free(temp[idx], M_RADIX);
357*6b839ff4SHans Petter Selasky radix_tree_clean_root_node(root);
358*6b839ff4SHans Petter Selasky return (-ENOMEM);
359*6b839ff4SHans Petter Selasky }
360*6b839ff4SHans Petter Selasky }
361*6b839ff4SHans Petter Selasky
362*6b839ff4SHans Petter Selasky /* setup new radix levels, if any */
363*6b839ff4SHans Petter Selasky for ( ; height != 0; height--) {
364*6b839ff4SHans Petter Selasky idx = radix_pos(index, height);
365*6b839ff4SHans Petter Selasky node->slots[idx] = temp[height - 1];
366*6b839ff4SHans Petter Selasky node->count++;
367*6b839ff4SHans Petter Selasky node = node->slots[idx];
368*6b839ff4SHans Petter Selasky }
369*6b839ff4SHans Petter Selasky
370*6b839ff4SHans Petter Selasky /*
371*6b839ff4SHans Petter Selasky * Insert and adjust count if the item does not already exist.
372*6b839ff4SHans Petter Selasky */
373*6b839ff4SHans Petter Selasky idx = radix_pos(index, 0);
374*6b839ff4SHans Petter Selasky /* swap */
375*6b839ff4SHans Petter Selasky pitem = node->slots[idx];
376*6b839ff4SHans Petter Selasky node->slots[idx] = *ppitem;
377*6b839ff4SHans Petter Selasky *ppitem = pitem;
378*6b839ff4SHans Petter Selasky
379*6b839ff4SHans Petter Selasky if (pitem == NULL)
380*6b839ff4SHans Petter Selasky node->count++;
381*6b839ff4SHans Petter Selasky return (0);
382*6b839ff4SHans Petter Selasky }
383