Home | History | Annotate | Line # | Download | only in linux
linux_idr.c revision 1.6.4.1
      1  1.6.4.1  christos /*	$NetBSD: linux_idr.c,v 1.6.4.1 2019/06/10 22:08:32 christos Exp $	*/
      2      1.2  riastrad 
      3      1.2  riastrad /*-
      4      1.2  riastrad  * Copyright (c) 2013 The NetBSD Foundation, Inc.
      5      1.2  riastrad  * All rights reserved.
      6      1.2  riastrad  *
      7      1.2  riastrad  * This code is derived from software contributed to The NetBSD Foundation
      8      1.2  riastrad  * by Taylor R. Campbell.
      9      1.2  riastrad  *
     10      1.2  riastrad  * Redistribution and use in source and binary forms, with or without
     11      1.2  riastrad  * modification, are permitted provided that the following conditions
     12      1.2  riastrad  * are met:
     13      1.2  riastrad  * 1. Redistributions of source code must retain the above copyright
     14      1.2  riastrad  *    notice, this list of conditions and the following disclaimer.
     15      1.2  riastrad  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.2  riastrad  *    notice, this list of conditions and the following disclaimer in the
     17      1.2  riastrad  *    documentation and/or other materials provided with the distribution.
     18      1.2  riastrad  *
     19      1.2  riastrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20      1.2  riastrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21      1.2  riastrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22      1.2  riastrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23      1.2  riastrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24      1.2  riastrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25      1.2  riastrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26      1.2  riastrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27      1.2  riastrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28      1.2  riastrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29      1.2  riastrad  * POSSIBILITY OF SUCH DAMAGE.
     30      1.2  riastrad  */
     31      1.2  riastrad 
     32      1.2  riastrad #include <sys/cdefs.h>
     33  1.6.4.1  christos __KERNEL_RCSID(0, "$NetBSD: linux_idr.c,v 1.6.4.1 2019/06/10 22:08:32 christos Exp $");
     34      1.2  riastrad 
     35      1.2  riastrad #include <sys/param.h>
     36      1.2  riastrad #include <sys/atomic.h>
     37      1.2  riastrad #include <sys/rbtree.h>
     38  1.6.4.1  christos #include <sys/sdt.h>
     39      1.2  riastrad 
     40      1.2  riastrad #include <linux/err.h>
     41      1.2  riastrad #include <linux/idr.h>
     42      1.3  riastrad #include <linux/slab.h>
     43      1.2  riastrad 
     44  1.6.4.1  christos #ifdef _KERNEL_OPT
     45  1.6.4.1  christos #include "opt_ddb.h"
     46  1.6.4.1  christos #endif
     47  1.6.4.1  christos 
     48  1.6.4.1  christos #ifdef DDB
     49  1.6.4.1  christos #include <ddb/ddb.h>
     50  1.6.4.1  christos #endif
     51  1.6.4.1  christos 
     52      1.2  riastrad struct idr_node {
     53      1.3  riastrad 	rb_node_t		in_rb_node;
     54      1.3  riastrad 	int			in_index;
     55      1.3  riastrad 	void			*in_data;
     56      1.2  riastrad };
     57      1.3  riastrad 
     58  1.6.4.1  christos struct idr_cache {
     59  1.6.4.1  christos 	struct idr_node		*ic_node;
     60  1.6.4.1  christos 	void			*ic_where;
     61  1.6.4.1  christos };
     62  1.6.4.1  christos 
     63  1.6.4.1  christos SDT_PROBE_DEFINE0(sdt, linux, idr, leak);
     64  1.6.4.1  christos SDT_PROBE_DEFINE1(sdt, linux, idr, init, "struct idr *"/*idr*/);
     65  1.6.4.1  christos SDT_PROBE_DEFINE1(sdt, linux, idr, destroy, "struct idr *"/*idr*/);
     66  1.6.4.1  christos SDT_PROBE_DEFINE4(sdt, linux, idr, replace,
     67  1.6.4.1  christos     "struct idr *"/*idr*/, "int"/*id*/, "void *"/*odata*/, "void *"/*ndata*/);
     68  1.6.4.1  christos SDT_PROBE_DEFINE3(sdt, linux, idr, remove,
     69  1.6.4.1  christos     "struct idr *"/*idr*/, "int"/*id*/, "void *"/*data*/);
     70  1.6.4.1  christos SDT_PROBE_DEFINE0(sdt, linux, idr, preload);
     71  1.6.4.1  christos SDT_PROBE_DEFINE0(sdt, linux, idr, preload__end);
     72  1.6.4.1  christos SDT_PROBE_DEFINE3(sdt, linux, idr, alloc,
     73  1.6.4.1  christos     "struct idr *"/*idr*/, "int"/*id*/, "void *"/*data*/);
     74  1.6.4.1  christos 
     75  1.6.4.1  christos static specificdata_key_t idr_cache_key __read_mostly;
     76  1.6.4.1  christos 
     77  1.6.4.1  christos static void
     78  1.6.4.1  christos idr_cache_warning(struct idr_cache *cache)
     79  1.6.4.1  christos {
     80  1.6.4.1  christos #ifdef DDB
     81  1.6.4.1  christos 	const char *name;
     82  1.6.4.1  christos 	db_expr_t offset;
     83  1.6.4.1  christos #endif
     84  1.6.4.1  christos 
     85  1.6.4.1  christos 	KASSERT(cache->ic_node != NULL);
     86  1.6.4.1  christos 
     87  1.6.4.1  christos #ifdef DDB
     88  1.6.4.1  christos 	db_find_sym_and_offset((db_addr_t)(uintptr_t)cache->ic_where,
     89  1.6.4.1  christos 	    &name, &offset);
     90  1.6.4.1  christos 	if (name) {
     91  1.6.4.1  christos 		printf("WARNING: idr preload at %s+%#"DDB_EXPR_FMT"x"
     92  1.6.4.1  christos 		    " leaked in lwp %s @ %p\n",
     93  1.6.4.1  christos 		    name, offset, curlwp->l_name, curlwp);
     94  1.6.4.1  christos 	} else
     95  1.6.4.1  christos #endif
     96  1.6.4.1  christos 	{
     97  1.6.4.1  christos 		printf("WARNING: idr preload at %p leaked in lwp %s @ %p\n",
     98  1.6.4.1  christos 		    cache->ic_where, curlwp->l_name, curlwp);
     99  1.6.4.1  christos 	}
    100  1.6.4.1  christos }
    101  1.6.4.1  christos 
    102  1.6.4.1  christos static void
    103  1.6.4.1  christos idr_cache_dtor(void *cookie)
    104  1.6.4.1  christos {
    105  1.6.4.1  christos 	struct idr_cache *cache = cookie;
    106  1.6.4.1  christos 
    107  1.6.4.1  christos 	if (cache->ic_node) {
    108  1.6.4.1  christos 		SDT_PROBE0(sdt, linux, idr, leak);
    109  1.6.4.1  christos 		idr_cache_warning(cache);
    110  1.6.4.1  christos 		kmem_free(cache->ic_node, sizeof(*cache->ic_node));
    111  1.6.4.1  christos 	}
    112  1.6.4.1  christos 	kmem_free(cache, sizeof(*cache));
    113  1.6.4.1  christos }
    114      1.3  riastrad 
    115      1.3  riastrad int
    116      1.3  riastrad linux_idr_module_init(void)
    117      1.3  riastrad {
    118  1.6.4.1  christos 	int error;
    119  1.6.4.1  christos 
    120  1.6.4.1  christos 	error = lwp_specific_key_create(&idr_cache_key, &idr_cache_dtor);
    121  1.6.4.1  christos 	if (error)
    122  1.6.4.1  christos 		return error;
    123      1.3  riastrad 
    124      1.3  riastrad 	return 0;
    125      1.3  riastrad }
    126      1.3  riastrad 
    127      1.3  riastrad void
    128      1.3  riastrad linux_idr_module_fini(void)
    129      1.3  riastrad {
    130      1.3  riastrad 
    131  1.6.4.1  christos 	lwp_specific_key_delete(idr_cache_key);
    132      1.3  riastrad }
    133      1.2  riastrad 
    134      1.2  riastrad static signed int idr_tree_compare_nodes(void *, const void *, const void *);
    135      1.2  riastrad static signed int idr_tree_compare_key(void *, const void *, const void *);
    136      1.2  riastrad 
    137      1.2  riastrad static const rb_tree_ops_t idr_rb_ops = {
    138      1.2  riastrad 	.rbto_compare_nodes = &idr_tree_compare_nodes,
    139      1.2  riastrad 	.rbto_compare_key = &idr_tree_compare_key,
    140      1.2  riastrad 	.rbto_node_offset = offsetof(struct idr_node, in_rb_node),
    141      1.2  riastrad 	.rbto_context = NULL,
    142      1.2  riastrad };
    143      1.2  riastrad 
    144      1.2  riastrad static signed int
    145      1.2  riastrad idr_tree_compare_nodes(void *ctx __unused, const void *na, const void *nb)
    146      1.2  riastrad {
    147      1.2  riastrad 	const int a = ((const struct idr_node *)na)->in_index;
    148      1.2  riastrad 	const int b = ((const struct idr_node *)nb)->in_index;
    149      1.2  riastrad 
    150      1.2  riastrad 	if (a < b)
    151      1.2  riastrad 		return -1;
    152      1.2  riastrad 	else if (b < a)
    153      1.2  riastrad 		 return +1;
    154      1.2  riastrad 	else
    155      1.2  riastrad 		return 0;
    156      1.2  riastrad }
    157      1.2  riastrad 
    158      1.2  riastrad static signed int
    159      1.2  riastrad idr_tree_compare_key(void *ctx __unused, const void *n, const void *key)
    160      1.2  riastrad {
    161      1.2  riastrad 	const int a = ((const struct idr_node *)n)->in_index;
    162      1.2  riastrad 	const int b = *(const int *)key;
    163      1.2  riastrad 
    164      1.2  riastrad 	if (a < b)
    165      1.2  riastrad 		return -1;
    166      1.2  riastrad 	else if (b < a)
    167      1.2  riastrad 		return +1;
    168      1.2  riastrad 	else
    169      1.2  riastrad 		return 0;
    170      1.2  riastrad }
    171      1.2  riastrad 
    172      1.2  riastrad void
    173      1.2  riastrad idr_init(struct idr *idr)
    174      1.2  riastrad {
    175      1.2  riastrad 
    176      1.5       mrg 	mutex_init(&idr->idr_lock, MUTEX_DEFAULT, IPL_VM);
    177      1.2  riastrad 	rb_tree_init(&idr->idr_tree, &idr_rb_ops);
    178  1.6.4.1  christos 	SDT_PROBE1(sdt, linux, idr, init,  idr);
    179      1.2  riastrad }
    180      1.2  riastrad 
    181      1.2  riastrad void
    182      1.2  riastrad idr_destroy(struct idr *idr)
    183      1.2  riastrad {
    184      1.2  riastrad 
    185  1.6.4.1  christos 	SDT_PROBE1(sdt, linux, idr, destroy,  idr);
    186      1.2  riastrad #if 0				/* XXX No rb_tree_destroy?  */
    187      1.2  riastrad 	rb_tree_destroy(&idr->idr_tree);
    188      1.2  riastrad #endif
    189      1.2  riastrad 	mutex_destroy(&idr->idr_lock);
    190      1.2  riastrad }
    191      1.2  riastrad 
    192      1.3  riastrad bool
    193      1.3  riastrad idr_is_empty(struct idr *idr)
    194      1.3  riastrad {
    195      1.3  riastrad 
    196      1.3  riastrad 	return (RB_TREE_MIN(&idr->idr_tree) == NULL);
    197      1.3  riastrad }
    198      1.3  riastrad 
    199      1.2  riastrad void *
    200      1.2  riastrad idr_find(struct idr *idr, int id)
    201      1.2  riastrad {
    202      1.2  riastrad 	const struct idr_node *node;
    203      1.2  riastrad 	void *data;
    204      1.2  riastrad 
    205      1.2  riastrad 	mutex_spin_enter(&idr->idr_lock);
    206      1.2  riastrad 	node = rb_tree_find_node(&idr->idr_tree, &id);
    207      1.2  riastrad 	data = (node == NULL? NULL : node->in_data);
    208      1.2  riastrad 	mutex_spin_exit(&idr->idr_lock);
    209      1.2  riastrad 
    210      1.2  riastrad 	return data;
    211      1.2  riastrad }
    212      1.2  riastrad 
    213      1.2  riastrad void *
    214  1.6.4.1  christos idr_get_next(struct idr *idr, int *idp)
    215  1.6.4.1  christos {
    216  1.6.4.1  christos 	const struct idr_node *node;
    217  1.6.4.1  christos 	void *data;
    218  1.6.4.1  christos 
    219  1.6.4.1  christos 	mutex_spin_enter(&idr->idr_lock);
    220  1.6.4.1  christos 	node = rb_tree_find_node_geq(&idr->idr_tree, idp);
    221  1.6.4.1  christos 	if (node == NULL) {
    222  1.6.4.1  christos 		data = NULL;
    223  1.6.4.1  christos 	} else {
    224  1.6.4.1  christos 		data = node->in_data;
    225  1.6.4.1  christos 		*idp = node->in_index;
    226  1.6.4.1  christos 	}
    227  1.6.4.1  christos 	mutex_spin_exit(&idr->idr_lock);
    228  1.6.4.1  christos 
    229  1.6.4.1  christos 	return data;
    230  1.6.4.1  christos }
    231  1.6.4.1  christos 
    232  1.6.4.1  christos void *
    233      1.2  riastrad idr_replace(struct idr *idr, void *replacement, int id)
    234      1.2  riastrad {
    235      1.2  riastrad 	struct idr_node *node;
    236      1.2  riastrad 	void *result;
    237      1.2  riastrad 
    238      1.2  riastrad 	mutex_spin_enter(&idr->idr_lock);
    239      1.2  riastrad 	node = rb_tree_find_node(&idr->idr_tree, &id);
    240      1.2  riastrad 	if (node == NULL) {
    241      1.2  riastrad 		result = ERR_PTR(-ENOENT);
    242      1.2  riastrad 	} else {
    243      1.2  riastrad 		result = node->in_data;
    244      1.2  riastrad 		node->in_data = replacement;
    245  1.6.4.1  christos 		SDT_PROBE4(sdt, linux, idr, replace,
    246  1.6.4.1  christos 		    idr, id, result, replacement);
    247      1.2  riastrad 	}
    248      1.2  riastrad 	mutex_spin_exit(&idr->idr_lock);
    249      1.2  riastrad 
    250      1.2  riastrad 	return result;
    251      1.2  riastrad }
    252      1.2  riastrad 
    253      1.2  riastrad void
    254      1.2  riastrad idr_remove(struct idr *idr, int id)
    255      1.2  riastrad {
    256      1.2  riastrad 	struct idr_node *node;
    257      1.2  riastrad 
    258      1.2  riastrad 	mutex_spin_enter(&idr->idr_lock);
    259      1.2  riastrad 	node = rb_tree_find_node(&idr->idr_tree, &id);
    260      1.3  riastrad 	KASSERTMSG((node != NULL), "idr %p has no entry for id %d", idr, id);
    261  1.6.4.1  christos 	SDT_PROBE3(sdt, linux, idr, remove,  idr, id, node->in_data);
    262      1.2  riastrad 	rb_tree_remove_node(&idr->idr_tree, node);
    263      1.2  riastrad 	mutex_spin_exit(&idr->idr_lock);
    264  1.6.4.1  christos 
    265  1.6.4.1  christos 	kmem_free(node, sizeof(*node));
    266      1.2  riastrad }
    267      1.2  riastrad 
    268      1.2  riastrad void
    269      1.3  riastrad idr_preload(gfp_t gfp)
    270      1.2  riastrad {
    271  1.6.4.1  christos 	struct idr_cache *cache;
    272      1.2  riastrad 	struct idr_node *node;
    273  1.6.4.1  christos 	km_flag_t kmflag = ISSET(gfp, __GFP_WAIT) ? KM_SLEEP : KM_NOSLEEP;
    274      1.2  riastrad 
    275  1.6.4.1  christos 	SDT_PROBE0(sdt, linux, idr, preload);
    276  1.6.4.1  christos 
    277  1.6.4.1  christos 	/* If caller asked to wait, we had better be sleepable.  */
    278      1.3  riastrad 	if (ISSET(gfp, __GFP_WAIT))
    279      1.3  riastrad 		ASSERT_SLEEPABLE();
    280      1.2  riastrad 
    281  1.6.4.1  christos 	/*
    282  1.6.4.1  christos 	 * Get the current lwp's private idr cache.
    283  1.6.4.1  christos 	 */
    284  1.6.4.1  christos 	cache = lwp_getspecific(idr_cache_key);
    285  1.6.4.1  christos 	if (cache == NULL) {
    286  1.6.4.1  christos 		/* lwp_setspecific must be sleepable.  */
    287  1.6.4.1  christos 		if (!ISSET(gfp, __GFP_WAIT))
    288  1.6.4.1  christos 			return;
    289  1.6.4.1  christos 		cache = kmem_zalloc(sizeof(*cache), kmflag);
    290  1.6.4.1  christos 		if (cache == NULL)
    291  1.6.4.1  christos 			return;
    292  1.6.4.1  christos 		lwp_setspecific(idr_cache_key, cache);
    293  1.6.4.1  christos 	}
    294  1.6.4.1  christos 
    295  1.6.4.1  christos 	/*
    296  1.6.4.1  christos 	 * If there already is a node, a prior call to idr_preload must
    297  1.6.4.1  christos 	 * not have been matched by idr_preload_end.  Print a warning,
    298  1.6.4.1  christos 	 * claim the node, and record our return address for where this
    299  1.6.4.1  christos 	 * node came from so the next leak is attributed to us.
    300  1.6.4.1  christos 	 */
    301  1.6.4.1  christos 	if (cache->ic_node) {
    302  1.6.4.1  christos 		idr_cache_warning(cache);
    303  1.6.4.1  christos 		goto out;
    304  1.6.4.1  christos 	}
    305  1.6.4.1  christos 
    306  1.6.4.1  christos 	/*
    307  1.6.4.1  christos 	 * No cached node.  Allocate a new one, store it in the cache,
    308  1.6.4.1  christos 	 * and record our return address for where this node came from
    309  1.6.4.1  christos 	 * so the next leak is attributed to us.
    310  1.6.4.1  christos 	 */
    311  1.6.4.1  christos 	node = kmem_alloc(sizeof(*node), kmflag);
    312      1.6  riastrad 	KASSERT(node != NULL || !ISSET(gfp, __GFP_WAIT));
    313      1.3  riastrad 	if (node == NULL)
    314      1.3  riastrad 		return;
    315      1.3  riastrad 
    316  1.6.4.1  christos 	cache->ic_node = node;
    317  1.6.4.1  christos out:	cache->ic_where = __builtin_return_address(0);
    318      1.2  riastrad }
    319      1.2  riastrad 
    320      1.2  riastrad int
    321      1.3  riastrad idr_alloc(struct idr *idr, void *data, int start, int end, gfp_t gfp)
    322      1.2  riastrad {
    323      1.3  riastrad 	int maximum = (end <= 0? INT_MAX : (end - 1));
    324  1.6.4.1  christos 	struct idr_cache *cache;
    325      1.3  riastrad 	struct idr_node *node, *search, *collision __diagused;
    326      1.3  riastrad 	int id = start;
    327      1.3  riastrad 
    328      1.3  riastrad 	/* Sanity-check inputs.  */
    329      1.3  riastrad 	if (ISSET(gfp, __GFP_WAIT))
    330      1.3  riastrad 		ASSERT_SLEEPABLE();
    331      1.3  riastrad 	if (__predict_false(start < 0))
    332      1.3  riastrad 		return -EINVAL;
    333      1.3  riastrad 	if (__predict_false(maximum < start))
    334      1.3  riastrad 		return -ENOSPC;
    335      1.3  riastrad 
    336  1.6.4.1  christos 	/*
    337  1.6.4.1  christos 	 * Grab a node allocated by idr_preload, if we have a cache and
    338  1.6.4.1  christos 	 * it is populated.
    339  1.6.4.1  christos 	 */
    340  1.6.4.1  christos 	cache = lwp_getspecific(idr_cache_key);
    341  1.6.4.1  christos 	if (cache == NULL || cache->ic_node == NULL)
    342      1.6  riastrad 		return -ENOMEM;
    343  1.6.4.1  christos 	node = cache->ic_node;
    344  1.6.4.1  christos 	cache->ic_node = NULL;
    345      1.2  riastrad 
    346      1.3  riastrad 	/* Find an id.  */
    347      1.2  riastrad 	mutex_spin_enter(&idr->idr_lock);
    348      1.3  riastrad 	search = rb_tree_find_node_geq(&idr->idr_tree, &start);
    349      1.3  riastrad 	while ((search != NULL) && (search->in_index == id)) {
    350      1.3  riastrad 		if (maximum <= id) {
    351      1.3  riastrad 			id = -ENOSPC;
    352      1.2  riastrad 			goto out;
    353      1.2  riastrad 		}
    354      1.2  riastrad 		search = rb_tree_iterate(&idr->idr_tree, search, RB_DIR_RIGHT);
    355      1.3  riastrad 		id++;
    356      1.2  riastrad 	}
    357      1.3  riastrad 	node->in_index = id;
    358      1.2  riastrad 	node->in_data = data;
    359      1.2  riastrad 	collision = rb_tree_insert_node(&idr->idr_tree, node);
    360      1.2  riastrad 	KASSERT(collision == node);
    361      1.3  riastrad out:	mutex_spin_exit(&idr->idr_lock);
    362      1.3  riastrad 
    363  1.6.4.1  christos 	/* Discard the node on failure.  */
    364      1.3  riastrad 	if (id < 0) {
    365  1.6.4.1  christos 		cache->ic_node = node;
    366  1.6.4.1  christos 	} else {
    367  1.6.4.1  christos 		SDT_PROBE3(sdt, linux, idr, alloc,  idr, id, data);
    368      1.3  riastrad 	}
    369      1.3  riastrad 	return id;
    370      1.3  riastrad }
    371      1.2  riastrad 
    372      1.3  riastrad void
    373      1.3  riastrad idr_preload_end(void)
    374      1.3  riastrad {
    375  1.6.4.1  christos 	struct idr_cache *cache;
    376      1.2  riastrad 
    377  1.6.4.1  christos 	SDT_PROBE0(sdt, linux, idr, preload__end);
    378  1.6.4.1  christos 
    379  1.6.4.1  christos 	/* Get the cache, or bail if it's not there.  */
    380  1.6.4.1  christos 	cache = lwp_getspecific(idr_cache_key);
    381  1.6.4.1  christos 	if (cache == NULL)
    382  1.6.4.1  christos 		return;
    383  1.6.4.1  christos 
    384  1.6.4.1  christos 	/*
    385  1.6.4.1  christos 	 * If there is a node, either because we didn't idr_alloc or
    386  1.6.4.1  christos 	 * because idr_alloc failed, chuck it.
    387  1.6.4.1  christos 	 *
    388  1.6.4.1  christos 	 * XXX If we are not sleepable, then while the caller may have
    389  1.6.4.1  christos 	 * used idr_preload(GFP_ATOMIC), kmem_free may still sleep.
    390  1.6.4.1  christos 	 * What to do?
    391  1.6.4.1  christos 	 */
    392  1.6.4.1  christos 	if (cache->ic_node) {
    393  1.6.4.1  christos 		struct idr_node *node;
    394  1.6.4.1  christos 
    395  1.6.4.1  christos 		node = cache->ic_node;
    396  1.6.4.1  christos 		cache->ic_node = NULL;
    397  1.6.4.1  christos 		cache->ic_where = NULL;
    398      1.3  riastrad 
    399  1.6.4.1  christos 		kmem_free(node, sizeof(*node));
    400      1.3  riastrad 	}
    401      1.2  riastrad }
    402      1.2  riastrad 
    403      1.2  riastrad int
    404      1.2  riastrad idr_for_each(struct idr *idr, int (*proc)(int, void *, void *), void *arg)
    405      1.2  riastrad {
    406      1.2  riastrad 	struct idr_node *node;
    407      1.2  riastrad 	int error = 0;
    408      1.2  riastrad 
    409      1.2  riastrad 	/* XXX Caller must exclude modifications.  */
    410      1.2  riastrad 	membar_consumer();
    411      1.2  riastrad 	RB_TREE_FOREACH(node, &idr->idr_tree) {
    412      1.2  riastrad 		error = (*proc)(node->in_index, node->in_data, arg);
    413      1.2  riastrad 		if (error)
    414      1.2  riastrad 			break;
    415      1.2  riastrad 	}
    416      1.2  riastrad 
    417      1.2  riastrad 	return error;
    418      1.2  riastrad }
    419