1*51e5c539Sriastradh /* $NetBSD: linux_idr.c,v 1.15 2021/12/19 12:21:02 riastradh Exp $ */
26cb10275Sriastradh
36cb10275Sriastradh /*-
46cb10275Sriastradh * Copyright (c) 2013 The NetBSD Foundation, Inc.
56cb10275Sriastradh * All rights reserved.
66cb10275Sriastradh *
76cb10275Sriastradh * This code is derived from software contributed to The NetBSD Foundation
86cb10275Sriastradh * by Taylor R. Campbell.
96cb10275Sriastradh *
106cb10275Sriastradh * Redistribution and use in source and binary forms, with or without
116cb10275Sriastradh * modification, are permitted provided that the following conditions
126cb10275Sriastradh * are met:
136cb10275Sriastradh * 1. Redistributions of source code must retain the above copyright
146cb10275Sriastradh * notice, this list of conditions and the following disclaimer.
156cb10275Sriastradh * 2. Redistributions in binary form must reproduce the above copyright
166cb10275Sriastradh * notice, this list of conditions and the following disclaimer in the
176cb10275Sriastradh * documentation and/or other materials provided with the distribution.
186cb10275Sriastradh *
196cb10275Sriastradh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206cb10275Sriastradh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216cb10275Sriastradh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226cb10275Sriastradh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236cb10275Sriastradh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246cb10275Sriastradh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256cb10275Sriastradh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266cb10275Sriastradh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276cb10275Sriastradh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286cb10275Sriastradh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296cb10275Sriastradh * POSSIBILITY OF SUCH DAMAGE.
306cb10275Sriastradh */
316cb10275Sriastradh
326cb10275Sriastradh #include <sys/cdefs.h>
33*51e5c539Sriastradh __KERNEL_RCSID(0, "$NetBSD: linux_idr.c,v 1.15 2021/12/19 12:21:02 riastradh Exp $");
346cb10275Sriastradh
356cb10275Sriastradh #include <sys/param.h>
366cb10275Sriastradh #include <sys/atomic.h>
376cb10275Sriastradh #include <sys/rbtree.h>
385248a24cSriastradh #include <sys/sdt.h>
396cb10275Sriastradh
406cb10275Sriastradh #include <linux/err.h>
416cb10275Sriastradh #include <linux/idr.h>
4277b5597aSriastradh #include <linux/slab.h>
436cb10275Sriastradh
441d8bbc46Sriastradh #ifdef _KERNEL_OPT
451d8bbc46Sriastradh #include "opt_ddb.h"
461d8bbc46Sriastradh #endif
471d8bbc46Sriastradh
481d8bbc46Sriastradh #ifdef DDB
491d8bbc46Sriastradh #include <ddb/ddb.h>
501d8bbc46Sriastradh #endif
511d8bbc46Sriastradh
526cb10275Sriastradh struct idr_node {
536cb10275Sriastradh rb_node_t in_rb_node;
546cb10275Sriastradh int in_index;
556cb10275Sriastradh void *in_data;
566cb10275Sriastradh };
5777b5597aSriastradh
581d8bbc46Sriastradh struct idr_cache {
591d8bbc46Sriastradh struct idr_node *ic_node;
601d8bbc46Sriastradh void *ic_where;
611d8bbc46Sriastradh };
621d8bbc46Sriastradh
635248a24cSriastradh SDT_PROBE_DEFINE0(sdt, linux, idr, leak);
645248a24cSriastradh SDT_PROBE_DEFINE1(sdt, linux, idr, init, "struct idr *"/*idr*/);
655248a24cSriastradh SDT_PROBE_DEFINE1(sdt, linux, idr, destroy, "struct idr *"/*idr*/);
665248a24cSriastradh SDT_PROBE_DEFINE4(sdt, linux, idr, replace,
675248a24cSriastradh "struct idr *"/*idr*/, "int"/*id*/, "void *"/*odata*/, "void *"/*ndata*/);
685248a24cSriastradh SDT_PROBE_DEFINE3(sdt, linux, idr, remove,
695248a24cSriastradh "struct idr *"/*idr*/, "int"/*id*/, "void *"/*data*/);
705248a24cSriastradh SDT_PROBE_DEFINE0(sdt, linux, idr, preload);
7171b0b921Sriastradh SDT_PROBE_DEFINE0(sdt, linux, idr, preload__end);
725248a24cSriastradh SDT_PROBE_DEFINE3(sdt, linux, idr, alloc,
735248a24cSriastradh "struct idr *"/*idr*/, "int"/*id*/, "void *"/*data*/);
745248a24cSriastradh
751d8bbc46Sriastradh static specificdata_key_t idr_cache_key __read_mostly;
761d8bbc46Sriastradh
771d8bbc46Sriastradh static void
idr_cache_warning(struct idr_cache * cache)781d8bbc46Sriastradh idr_cache_warning(struct idr_cache *cache)
791d8bbc46Sriastradh {
801d8bbc46Sriastradh #ifdef DDB
811d8bbc46Sriastradh const char *name;
821d8bbc46Sriastradh db_expr_t offset;
831d8bbc46Sriastradh #endif
841d8bbc46Sriastradh
851d8bbc46Sriastradh KASSERT(cache->ic_node != NULL);
861d8bbc46Sriastradh
871d8bbc46Sriastradh #ifdef DDB
881d8bbc46Sriastradh db_find_sym_and_offset((db_addr_t)(uintptr_t)cache->ic_where,
891d8bbc46Sriastradh &name, &offset);
901d8bbc46Sriastradh if (name) {
911d8bbc46Sriastradh printf("WARNING: idr preload at %s+%#"DDB_EXPR_FMT"x"
921d8bbc46Sriastradh " leaked in lwp %s @ %p\n",
931d8bbc46Sriastradh name, offset, curlwp->l_name, curlwp);
941d8bbc46Sriastradh } else
951d8bbc46Sriastradh #endif
961d8bbc46Sriastradh {
971d8bbc46Sriastradh printf("WARNING: idr preload at %p leaked in lwp %s @ %p\n",
981d8bbc46Sriastradh cache->ic_where, curlwp->l_name, curlwp);
991d8bbc46Sriastradh }
1001d8bbc46Sriastradh }
1011d8bbc46Sriastradh
1021d8bbc46Sriastradh static void
idr_cache_dtor(void * cookie)1031d8bbc46Sriastradh idr_cache_dtor(void *cookie)
1041d8bbc46Sriastradh {
1051d8bbc46Sriastradh struct idr_cache *cache = cookie;
1061d8bbc46Sriastradh
1071d8bbc46Sriastradh if (cache->ic_node) {
1085248a24cSriastradh SDT_PROBE0(sdt, linux, idr, leak);
1091d8bbc46Sriastradh idr_cache_warning(cache);
1101d8bbc46Sriastradh kmem_free(cache->ic_node, sizeof(*cache->ic_node));
1111d8bbc46Sriastradh }
1121d8bbc46Sriastradh kmem_free(cache, sizeof(*cache));
1131d8bbc46Sriastradh }
11477b5597aSriastradh
11577b5597aSriastradh int
linux_idr_module_init(void)11677b5597aSriastradh linux_idr_module_init(void)
11777b5597aSriastradh {
1181d8bbc46Sriastradh int error;
11977b5597aSriastradh
1201d8bbc46Sriastradh error = lwp_specific_key_create(&idr_cache_key, &idr_cache_dtor);
1211d8bbc46Sriastradh if (error)
1221d8bbc46Sriastradh return error;
1231d8bbc46Sriastradh
12477b5597aSriastradh return 0;
12577b5597aSriastradh }
12677b5597aSriastradh
12777b5597aSriastradh void
linux_idr_module_fini(void)12877b5597aSriastradh linux_idr_module_fini(void)
12977b5597aSriastradh {
13077b5597aSriastradh
1311d8bbc46Sriastradh lwp_specific_key_delete(idr_cache_key);
13277b5597aSriastradh }
1336cb10275Sriastradh
1346cb10275Sriastradh static signed int idr_tree_compare_nodes(void *, const void *, const void *);
1356cb10275Sriastradh static signed int idr_tree_compare_key(void *, const void *, const void *);
1366cb10275Sriastradh
1376cb10275Sriastradh static const rb_tree_ops_t idr_rb_ops = {
1386cb10275Sriastradh .rbto_compare_nodes = &idr_tree_compare_nodes,
1396cb10275Sriastradh .rbto_compare_key = &idr_tree_compare_key,
1406cb10275Sriastradh .rbto_node_offset = offsetof(struct idr_node, in_rb_node),
1416cb10275Sriastradh .rbto_context = NULL,
1426cb10275Sriastradh };
1436cb10275Sriastradh
1446cb10275Sriastradh static signed int
idr_tree_compare_nodes(void * ctx __unused,const void * na,const void * nb)1456cb10275Sriastradh idr_tree_compare_nodes(void *ctx __unused, const void *na, const void *nb)
1466cb10275Sriastradh {
1476cb10275Sriastradh const int a = ((const struct idr_node *)na)->in_index;
1486cb10275Sriastradh const int b = ((const struct idr_node *)nb)->in_index;
1496cb10275Sriastradh
1506cb10275Sriastradh if (a < b)
1516cb10275Sriastradh return -1;
1526cb10275Sriastradh else if (b < a)
1536cb10275Sriastradh return +1;
1546cb10275Sriastradh else
1556cb10275Sriastradh return 0;
1566cb10275Sriastradh }
1576cb10275Sriastradh
1586cb10275Sriastradh static signed int
idr_tree_compare_key(void * ctx __unused,const void * n,const void * key)1596cb10275Sriastradh idr_tree_compare_key(void *ctx __unused, const void *n, const void *key)
1606cb10275Sriastradh {
1616cb10275Sriastradh const int a = ((const struct idr_node *)n)->in_index;
1626cb10275Sriastradh const int b = *(const int *)key;
1636cb10275Sriastradh
1646cb10275Sriastradh if (a < b)
1656cb10275Sriastradh return -1;
1666cb10275Sriastradh else if (b < a)
1676cb10275Sriastradh return +1;
1686cb10275Sriastradh else
1696cb10275Sriastradh return 0;
1706cb10275Sriastradh }
1716cb10275Sriastradh
1726cb10275Sriastradh void
idr_init(struct idr * idr)1736cb10275Sriastradh idr_init(struct idr *idr)
1746cb10275Sriastradh {
1756cb10275Sriastradh
17692c79c76Sriastradh idr_init_base(idr, 0);
17792c79c76Sriastradh }
17892c79c76Sriastradh
17992c79c76Sriastradh void
idr_init_base(struct idr * idr,int base)18092c79c76Sriastradh idr_init_base(struct idr *idr, int base)
18192c79c76Sriastradh {
18292c79c76Sriastradh
18332b977d2Smrg mutex_init(&idr->idr_lock, MUTEX_DEFAULT, IPL_VM);
1846cb10275Sriastradh rb_tree_init(&idr->idr_tree, &idr_rb_ops);
18592c79c76Sriastradh idr->idr_base = base;
18692c79c76Sriastradh
1875248a24cSriastradh SDT_PROBE1(sdt, linux, idr, init, idr);
1886cb10275Sriastradh }
1896cb10275Sriastradh
1906cb10275Sriastradh void
idr_destroy(struct idr * idr)1916cb10275Sriastradh idr_destroy(struct idr *idr)
1926cb10275Sriastradh {
1936cb10275Sriastradh
1945248a24cSriastradh SDT_PROBE1(sdt, linux, idr, destroy, idr);
1956cb10275Sriastradh #if 0 /* XXX No rb_tree_destroy? */
1966cb10275Sriastradh rb_tree_destroy(&idr->idr_tree);
1976cb10275Sriastradh #endif
1986cb10275Sriastradh mutex_destroy(&idr->idr_lock);
1996cb10275Sriastradh }
2006cb10275Sriastradh
20177b5597aSriastradh bool
idr_is_empty(struct idr * idr)20277b5597aSriastradh idr_is_empty(struct idr *idr)
20377b5597aSriastradh {
20477b5597aSriastradh
20577b5597aSriastradh return (RB_TREE_MIN(&idr->idr_tree) == NULL);
20677b5597aSriastradh }
20777b5597aSriastradh
2086cb10275Sriastradh void *
idr_find(struct idr * idr,int id)2096cb10275Sriastradh idr_find(struct idr *idr, int id)
2106cb10275Sriastradh {
2116cb10275Sriastradh const struct idr_node *node;
2126cb10275Sriastradh void *data;
2136cb10275Sriastradh
2146cb10275Sriastradh mutex_spin_enter(&idr->idr_lock);
2156cb10275Sriastradh node = rb_tree_find_node(&idr->idr_tree, &id);
2166cb10275Sriastradh data = (node == NULL? NULL : node->in_data);
2176cb10275Sriastradh mutex_spin_exit(&idr->idr_lock);
2186cb10275Sriastradh
2196cb10275Sriastradh return data;
2206cb10275Sriastradh }
2216cb10275Sriastradh
2226cb10275Sriastradh void *
idr_get_next(struct idr * idr,int * idp)22377a04540Sriastradh idr_get_next(struct idr *idr, int *idp)
22477a04540Sriastradh {
22577a04540Sriastradh const struct idr_node *node;
22677a04540Sriastradh void *data;
22777a04540Sriastradh
22877a04540Sriastradh mutex_spin_enter(&idr->idr_lock);
22977a04540Sriastradh node = rb_tree_find_node_geq(&idr->idr_tree, idp);
23077a04540Sriastradh if (node == NULL) {
23177a04540Sriastradh data = NULL;
23277a04540Sriastradh } else {
23377a04540Sriastradh data = node->in_data;
23477a04540Sriastradh *idp = node->in_index;
23577a04540Sriastradh }
23677a04540Sriastradh mutex_spin_exit(&idr->idr_lock);
23777a04540Sriastradh
23877a04540Sriastradh return data;
23977a04540Sriastradh }
24077a04540Sriastradh
24177a04540Sriastradh void *
idr_replace(struct idr * idr,void * replacement,int id)2426cb10275Sriastradh idr_replace(struct idr *idr, void *replacement, int id)
2436cb10275Sriastradh {
2446cb10275Sriastradh struct idr_node *node;
2456cb10275Sriastradh void *result;
2466cb10275Sriastradh
2476cb10275Sriastradh mutex_spin_enter(&idr->idr_lock);
2486cb10275Sriastradh node = rb_tree_find_node(&idr->idr_tree, &id);
2496cb10275Sriastradh if (node == NULL) {
2506cb10275Sriastradh result = ERR_PTR(-ENOENT);
2516cb10275Sriastradh } else {
2526cb10275Sriastradh result = node->in_data;
2536cb10275Sriastradh node->in_data = replacement;
2545248a24cSriastradh SDT_PROBE4(sdt, linux, idr, replace,
2555248a24cSriastradh idr, id, result, replacement);
2566cb10275Sriastradh }
2576cb10275Sriastradh mutex_spin_exit(&idr->idr_lock);
2586cb10275Sriastradh
2596cb10275Sriastradh return result;
2606cb10275Sriastradh }
2616cb10275Sriastradh
262f14e25d8Sriastradh void *
idr_remove(struct idr * idr,int id)2636cb10275Sriastradh idr_remove(struct idr *idr, int id)
2646cb10275Sriastradh {
2656cb10275Sriastradh struct idr_node *node;
266f14e25d8Sriastradh void *data;
2676cb10275Sriastradh
2686cb10275Sriastradh mutex_spin_enter(&idr->idr_lock);
2696cb10275Sriastradh node = rb_tree_find_node(&idr->idr_tree, &id);
270f14e25d8Sriastradh if (node == NULL) {
271f14e25d8Sriastradh data = NULL;
272f14e25d8Sriastradh } else {
273f14e25d8Sriastradh data = node->in_data;
274f14e25d8Sriastradh SDT_PROBE3(sdt, linux, idr, remove, idr, id, data);
2756cb10275Sriastradh rb_tree_remove_node(&idr->idr_tree, node);
276f14e25d8Sriastradh }
2776cb10275Sriastradh mutex_spin_exit(&idr->idr_lock);
2781d8bbc46Sriastradh
2791d8bbc46Sriastradh kmem_free(node, sizeof(*node));
280f14e25d8Sriastradh
281f14e25d8Sriastradh return data;
2826cb10275Sriastradh }
2836cb10275Sriastradh
2846cb10275Sriastradh void
idr_preload(gfp_t gfp)28577b5597aSriastradh idr_preload(gfp_t gfp)
2866cb10275Sriastradh {
2871d8bbc46Sriastradh struct idr_cache *cache;
2886cb10275Sriastradh struct idr_node *node;
2891d8bbc46Sriastradh km_flag_t kmflag = ISSET(gfp, __GFP_WAIT) ? KM_SLEEP : KM_NOSLEEP;
2906cb10275Sriastradh
2915248a24cSriastradh SDT_PROBE0(sdt, linux, idr, preload);
2925248a24cSriastradh
2931d8bbc46Sriastradh /* If caller asked to wait, we had better be sleepable. */
29477b5597aSriastradh if (ISSET(gfp, __GFP_WAIT))
29577b5597aSriastradh ASSERT_SLEEPABLE();
29677b5597aSriastradh
2971d8bbc46Sriastradh /*
2981d8bbc46Sriastradh * Get the current lwp's private idr cache.
2991d8bbc46Sriastradh */
3001d8bbc46Sriastradh cache = lwp_getspecific(idr_cache_key);
3011d8bbc46Sriastradh if (cache == NULL) {
3021d8bbc46Sriastradh /* lwp_setspecific must be sleepable. */
3031d8bbc46Sriastradh if (!ISSET(gfp, __GFP_WAIT))
3041d8bbc46Sriastradh return;
3054f49d672Sriastradh cache = kmem_zalloc(sizeof(*cache), kmflag);
3061d8bbc46Sriastradh if (cache == NULL)
3071d8bbc46Sriastradh return;
3081d8bbc46Sriastradh lwp_setspecific(idr_cache_key, cache);
3091d8bbc46Sriastradh }
3101d8bbc46Sriastradh
3111d8bbc46Sriastradh /*
3121d8bbc46Sriastradh * If there already is a node, a prior call to idr_preload must
3131d8bbc46Sriastradh * not have been matched by idr_preload_end. Print a warning,
3141d8bbc46Sriastradh * claim the node, and record our return address for where this
3151d8bbc46Sriastradh * node came from so the next leak is attributed to us.
3161d8bbc46Sriastradh */
3171d8bbc46Sriastradh if (cache->ic_node) {
3181d8bbc46Sriastradh idr_cache_warning(cache);
3191d8bbc46Sriastradh goto out;
3201d8bbc46Sriastradh }
3211d8bbc46Sriastradh
3221d8bbc46Sriastradh /*
3231d8bbc46Sriastradh * No cached node. Allocate a new one, store it in the cache,
3241d8bbc46Sriastradh * and record our return address for where this node came from
3251d8bbc46Sriastradh * so the next leak is attributed to us.
3261d8bbc46Sriastradh */
3271d8bbc46Sriastradh node = kmem_alloc(sizeof(*node), kmflag);
32806a27a01Sriastradh KASSERT(node != NULL || !ISSET(gfp, __GFP_WAIT));
32977b5597aSriastradh if (node == NULL)
33077b5597aSriastradh return;
33177b5597aSriastradh
3321d8bbc46Sriastradh cache->ic_node = node;
3331d8bbc46Sriastradh out: cache->ic_where = __builtin_return_address(0);
3346cb10275Sriastradh }
3356cb10275Sriastradh
3366cb10275Sriastradh int
idr_alloc(struct idr * idr,void * data,int start,int end,gfp_t gfp)33777b5597aSriastradh idr_alloc(struct idr *idr, void *data, int start, int end, gfp_t gfp)
3386cb10275Sriastradh {
33977b5597aSriastradh int maximum = (end <= 0? INT_MAX : (end - 1));
3401d8bbc46Sriastradh struct idr_cache *cache;
34177b5597aSriastradh struct idr_node *node, *search, *collision __diagused;
34277b5597aSriastradh int id = start;
3436cb10275Sriastradh
34477b5597aSriastradh /* Sanity-check inputs. */
34577b5597aSriastradh if (ISSET(gfp, __GFP_WAIT))
34677b5597aSriastradh ASSERT_SLEEPABLE();
34777b5597aSriastradh if (__predict_false(start < 0))
34877b5597aSriastradh return -EINVAL;
34977b5597aSriastradh if (__predict_false(maximum < start))
35077b5597aSriastradh return -ENOSPC;
35177b5597aSriastradh
3521d8bbc46Sriastradh /*
3531d8bbc46Sriastradh * Grab a node allocated by idr_preload, if we have a cache and
3541d8bbc46Sriastradh * it is populated.
3551d8bbc46Sriastradh */
3561d8bbc46Sriastradh cache = lwp_getspecific(idr_cache_key);
3571d8bbc46Sriastradh if (cache == NULL || cache->ic_node == NULL)
35806a27a01Sriastradh return -ENOMEM;
3591d8bbc46Sriastradh node = cache->ic_node;
3601d8bbc46Sriastradh cache->ic_node = NULL;
36177b5597aSriastradh
36277b5597aSriastradh /* Find an id. */
3636cb10275Sriastradh mutex_spin_enter(&idr->idr_lock);
36477b5597aSriastradh search = rb_tree_find_node_geq(&idr->idr_tree, &start);
36577b5597aSriastradh while ((search != NULL) && (search->in_index == id)) {
36677b5597aSriastradh if (maximum <= id) {
36777b5597aSriastradh id = -ENOSPC;
3686cb10275Sriastradh goto out;
3696cb10275Sriastradh }
3706cb10275Sriastradh search = rb_tree_iterate(&idr->idr_tree, search, RB_DIR_RIGHT);
37177b5597aSriastradh id++;
3726cb10275Sriastradh }
37377b5597aSriastradh node->in_index = id;
3746cb10275Sriastradh node->in_data = data;
3756cb10275Sriastradh collision = rb_tree_insert_node(&idr->idr_tree, node);
3766cb10275Sriastradh KASSERT(collision == node);
3776cb10275Sriastradh out: mutex_spin_exit(&idr->idr_lock);
37877b5597aSriastradh
37977b5597aSriastradh /* Discard the node on failure. */
380077afc9aSriastradh if (id < 0) {
3811d8bbc46Sriastradh cache->ic_node = node;
382077afc9aSriastradh } else {
3835248a24cSriastradh SDT_PROBE3(sdt, linux, idr, alloc, idr, id, data);
384077afc9aSriastradh }
38577b5597aSriastradh return id;
38677b5597aSriastradh }
38777b5597aSriastradh
38877b5597aSriastradh void
idr_preload_end(void)38977b5597aSriastradh idr_preload_end(void)
39077b5597aSriastradh {
3911d8bbc46Sriastradh struct idr_cache *cache;
39277b5597aSriastradh
39371b0b921Sriastradh SDT_PROBE0(sdt, linux, idr, preload__end);
3945248a24cSriastradh
3951d8bbc46Sriastradh /* Get the cache, or bail if it's not there. */
3961d8bbc46Sriastradh cache = lwp_getspecific(idr_cache_key);
3971d8bbc46Sriastradh if (cache == NULL)
3981d8bbc46Sriastradh return;
39977b5597aSriastradh
4001d8bbc46Sriastradh /*
4011d8bbc46Sriastradh * If there is a node, either because we didn't idr_alloc or
4021d8bbc46Sriastradh * because idr_alloc failed, chuck it.
4031d8bbc46Sriastradh *
4041d8bbc46Sriastradh * XXX If we are not sleepable, then while the caller may have
4051d8bbc46Sriastradh * used idr_preload(GFP_ATOMIC), kmem_free may still sleep.
4061d8bbc46Sriastradh * What to do?
4071d8bbc46Sriastradh */
4081d8bbc46Sriastradh if (cache->ic_node) {
4091d8bbc46Sriastradh struct idr_node *node;
4101d8bbc46Sriastradh
4111d8bbc46Sriastradh node = cache->ic_node;
4121d8bbc46Sriastradh cache->ic_node = NULL;
4131d8bbc46Sriastradh cache->ic_where = NULL;
4141d8bbc46Sriastradh
4151d8bbc46Sriastradh kmem_free(node, sizeof(*node));
41677b5597aSriastradh }
4176cb10275Sriastradh }
4186cb10275Sriastradh
4196cb10275Sriastradh int
idr_for_each(struct idr * idr,int (* proc)(int,void *,void *),void * arg)4206cb10275Sriastradh idr_for_each(struct idr *idr, int (*proc)(int, void *, void *), void *arg)
4216cb10275Sriastradh {
4226cb10275Sriastradh struct idr_node *node;
4236cb10275Sriastradh int error = 0;
4246cb10275Sriastradh
4256cb10275Sriastradh /* XXX Caller must exclude modifications. */
4266cb10275Sriastradh RB_TREE_FOREACH(node, &idr->idr_tree) {
4276cb10275Sriastradh error = (*proc)(node->in_index, node->in_data, arg);
4286cb10275Sriastradh if (error)
4296cb10275Sriastradh break;
4306cb10275Sriastradh }
4316cb10275Sriastradh
4326cb10275Sriastradh return error;
4336cb10275Sriastradh }
434