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.
5427cefdeSHans Petter Selasky * Copyright (c) 2013-2017 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 #include <sys/lock.h>
368d59ecb2SHans Petter Selasky #include <sys/mutex.h>
378d59ecb2SHans Petter Selasky
388d59ecb2SHans Petter Selasky #include <machine/stdarg.h>
398d59ecb2SHans Petter Selasky
40c9dd0b48SHans Petter Selasky #include <linux/bitmap.h>
418d59ecb2SHans Petter Selasky #include <linux/kobject.h>
428d59ecb2SHans Petter Selasky #include <linux/slab.h>
438d59ecb2SHans Petter Selasky #include <linux/idr.h>
448d59ecb2SHans Petter Selasky #include <linux/err.h>
458d59ecb2SHans Petter Selasky
46427cefdeSHans Petter Selasky #define MAX_IDR_LEVEL ((MAX_IDR_SHIFT + IDR_BITS - 1) / IDR_BITS)
47427cefdeSHans Petter Selasky #define MAX_IDR_FREE (MAX_IDR_LEVEL * 2)
48427cefdeSHans Petter Selasky
49427cefdeSHans Petter Selasky struct linux_idr_cache {
50427cefdeSHans Petter Selasky spinlock_t lock;
51427cefdeSHans Petter Selasky struct idr_layer *head;
52427cefdeSHans Petter Selasky unsigned count;
53427cefdeSHans Petter Selasky };
54427cefdeSHans Petter Selasky
552bf95012SAndrew Turner DPCPU_DEFINE_STATIC(struct linux_idr_cache, linux_idr_cache);
56427cefdeSHans Petter Selasky
578d59ecb2SHans Petter Selasky /*
588d59ecb2SHans Petter Selasky * IDR Implementation.
598d59ecb2SHans Petter Selasky *
608d59ecb2SHans Petter Selasky * This is quick and dirty and not as re-entrant as the linux version
618d59ecb2SHans Petter Selasky * however it should be fairly fast. It is basically a radix tree with
628d59ecb2SHans Petter Selasky * a builtin bitmap for allocation.
638d59ecb2SHans Petter Selasky */
648d59ecb2SHans Petter Selasky static MALLOC_DEFINE(M_IDR, "idr", "Linux IDR compat");
658d59ecb2SHans Petter Selasky
66427cefdeSHans Petter Selasky static struct idr_layer *
idr_preload_dequeue_locked(struct linux_idr_cache * lic)67427cefdeSHans Petter Selasky idr_preload_dequeue_locked(struct linux_idr_cache *lic)
68427cefdeSHans Petter Selasky {
69427cefdeSHans Petter Selasky struct idr_layer *retval;
70427cefdeSHans Petter Selasky
71427cefdeSHans Petter Selasky /* check if wrong thread is trying to dequeue */
72ae38a1a1SEmmanuel Vadot if (mtx_owned(&lic->lock) == 0)
73427cefdeSHans Petter Selasky return (NULL);
74427cefdeSHans Petter Selasky
75427cefdeSHans Petter Selasky retval = lic->head;
76427cefdeSHans Petter Selasky if (likely(retval != NULL)) {
77427cefdeSHans Petter Selasky lic->head = retval->ary[0];
78427cefdeSHans Petter Selasky lic->count--;
79427cefdeSHans Petter Selasky retval->ary[0] = NULL;
80427cefdeSHans Petter Selasky }
81427cefdeSHans Petter Selasky return (retval);
82427cefdeSHans Petter Selasky }
83427cefdeSHans Petter Selasky
84427cefdeSHans Petter Selasky static void
idr_preload_init(void * arg)85427cefdeSHans Petter Selasky idr_preload_init(void *arg)
86427cefdeSHans Petter Selasky {
87427cefdeSHans Petter Selasky int cpu;
88427cefdeSHans Petter Selasky
89427cefdeSHans Petter Selasky CPU_FOREACH(cpu) {
90427cefdeSHans Petter Selasky struct linux_idr_cache *lic =
91427cefdeSHans Petter Selasky DPCPU_ID_PTR(cpu, linux_idr_cache);
92427cefdeSHans Petter Selasky
93427cefdeSHans Petter Selasky spin_lock_init(&lic->lock);
94427cefdeSHans Petter Selasky }
95427cefdeSHans Petter Selasky }
9625b3ef2cSHans Petter Selasky SYSINIT(idr_preload_init, SI_SUB_CPU, SI_ORDER_ANY, idr_preload_init, NULL);
97427cefdeSHans Petter Selasky
98427cefdeSHans Petter Selasky static void
idr_preload_uninit(void * arg)99427cefdeSHans Petter Selasky idr_preload_uninit(void *arg)
100427cefdeSHans Petter Selasky {
101427cefdeSHans Petter Selasky int cpu;
102427cefdeSHans Petter Selasky
103427cefdeSHans Petter Selasky CPU_FOREACH(cpu) {
104427cefdeSHans Petter Selasky struct idr_layer *cacheval;
105427cefdeSHans Petter Selasky struct linux_idr_cache *lic =
106427cefdeSHans Petter Selasky DPCPU_ID_PTR(cpu, linux_idr_cache);
107427cefdeSHans Petter Selasky
108427cefdeSHans Petter Selasky while (1) {
109427cefdeSHans Petter Selasky spin_lock(&lic->lock);
110427cefdeSHans Petter Selasky cacheval = idr_preload_dequeue_locked(lic);
111427cefdeSHans Petter Selasky spin_unlock(&lic->lock);
112427cefdeSHans Petter Selasky
113427cefdeSHans Petter Selasky if (cacheval == NULL)
114427cefdeSHans Petter Selasky break;
115427cefdeSHans Petter Selasky free(cacheval, M_IDR);
116427cefdeSHans Petter Selasky }
117427cefdeSHans Petter Selasky spin_lock_destroy(&lic->lock);
118427cefdeSHans Petter Selasky }
119427cefdeSHans Petter Selasky }
120427cefdeSHans Petter Selasky SYSUNINIT(idr_preload_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, idr_preload_uninit, NULL);
121427cefdeSHans Petter Selasky
122427cefdeSHans Petter Selasky void
idr_preload(gfp_t gfp_mask)123427cefdeSHans Petter Selasky idr_preload(gfp_t gfp_mask)
124427cefdeSHans Petter Selasky {
125427cefdeSHans Petter Selasky struct linux_idr_cache *lic;
126427cefdeSHans Petter Selasky struct idr_layer *cacheval;
127427cefdeSHans Petter Selasky
128427cefdeSHans Petter Selasky sched_pin();
129427cefdeSHans Petter Selasky
130427cefdeSHans Petter Selasky lic = &DPCPU_GET(linux_idr_cache);
131427cefdeSHans Petter Selasky
132427cefdeSHans Petter Selasky /* fill up cache */
133427cefdeSHans Petter Selasky spin_lock(&lic->lock);
134427cefdeSHans Petter Selasky while (lic->count < MAX_IDR_FREE) {
135427cefdeSHans Petter Selasky spin_unlock(&lic->lock);
136427cefdeSHans Petter Selasky cacheval = malloc(sizeof(*cacheval), M_IDR, M_ZERO | gfp_mask);
137427cefdeSHans Petter Selasky spin_lock(&lic->lock);
138427cefdeSHans Petter Selasky if (cacheval == NULL)
139427cefdeSHans Petter Selasky break;
140427cefdeSHans Petter Selasky cacheval->ary[0] = lic->head;
141427cefdeSHans Petter Selasky lic->head = cacheval;
142427cefdeSHans Petter Selasky lic->count++;
143427cefdeSHans Petter Selasky }
144427cefdeSHans Petter Selasky }
145427cefdeSHans Petter Selasky
146427cefdeSHans Petter Selasky void
idr_preload_end(void)147427cefdeSHans Petter Selasky idr_preload_end(void)
148427cefdeSHans Petter Selasky {
149427cefdeSHans Petter Selasky struct linux_idr_cache *lic;
150427cefdeSHans Petter Selasky
151427cefdeSHans Petter Selasky lic = &DPCPU_GET(linux_idr_cache);
152427cefdeSHans Petter Selasky spin_unlock(&lic->lock);
153427cefdeSHans Petter Selasky sched_unpin();
154427cefdeSHans Petter Selasky }
155427cefdeSHans Petter Selasky
1568d59ecb2SHans Petter Selasky static inline int
idr_max(struct idr * idr)1578d59ecb2SHans Petter Selasky idr_max(struct idr *idr)
1588d59ecb2SHans Petter Selasky {
1598d59ecb2SHans Petter Selasky return (1 << (idr->layers * IDR_BITS)) - 1;
1608d59ecb2SHans Petter Selasky }
1618d59ecb2SHans Petter Selasky
1628d59ecb2SHans Petter Selasky static inline int
idr_pos(int id,int layer)1638d59ecb2SHans Petter Selasky idr_pos(int id, int layer)
1648d59ecb2SHans Petter Selasky {
1658d59ecb2SHans Petter Selasky return (id >> (IDR_BITS * layer)) & IDR_MASK;
1668d59ecb2SHans Petter Selasky }
1678d59ecb2SHans Petter Selasky
1688d59ecb2SHans Petter Selasky void
idr_init(struct idr * idr)1698d59ecb2SHans Petter Selasky idr_init(struct idr *idr)
1708d59ecb2SHans Petter Selasky {
1718d59ecb2SHans Petter Selasky bzero(idr, sizeof(*idr));
1728d59ecb2SHans Petter Selasky mtx_init(&idr->lock, "idr", NULL, MTX_DEF);
1738d59ecb2SHans Petter Selasky }
1748d59ecb2SHans Petter Selasky
1758d59ecb2SHans Petter Selasky /* Only frees cached pages. */
1768d59ecb2SHans Petter Selasky void
idr_destroy(struct idr * idr)1778d59ecb2SHans Petter Selasky idr_destroy(struct idr *idr)
1788d59ecb2SHans Petter Selasky {
1798d59ecb2SHans Petter Selasky struct idr_layer *il, *iln;
1808d59ecb2SHans Petter Selasky
181*613723baSAustin Shafer /*
182*613723baSAustin Shafer * This idr can be reused, and this function might be called multiple times
183*613723baSAustin Shafer * without a idr_init(). Check if this is the case. If we do not do this
184*613723baSAustin Shafer * then the mutex will panic while asserting that it is valid.
185*613723baSAustin Shafer */
186*613723baSAustin Shafer if (mtx_initialized(&idr->lock) == 0)
187*613723baSAustin Shafer return;
188*613723baSAustin Shafer
1898d59ecb2SHans Petter Selasky idr_remove_all(idr);
1908d59ecb2SHans Petter Selasky mtx_lock(&idr->lock);
1918d59ecb2SHans Petter Selasky for (il = idr->free; il != NULL; il = iln) {
1928d59ecb2SHans Petter Selasky iln = il->ary[0];
1938d59ecb2SHans Petter Selasky free(il, M_IDR);
1948d59ecb2SHans Petter Selasky }
1958d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock);
1965d35d777SHans Petter Selasky mtx_destroy(&idr->lock);
1978d59ecb2SHans Petter Selasky }
1988d59ecb2SHans Petter Selasky
1998d59ecb2SHans Petter Selasky static void
idr_remove_layer(struct idr_layer * il,int layer)2008d59ecb2SHans Petter Selasky idr_remove_layer(struct idr_layer *il, int layer)
2018d59ecb2SHans Petter Selasky {
2028d59ecb2SHans Petter Selasky int i;
2038d59ecb2SHans Petter Selasky
2048d59ecb2SHans Petter Selasky if (il == NULL)
2058d59ecb2SHans Petter Selasky return;
2068d59ecb2SHans Petter Selasky if (layer == 0) {
2078d59ecb2SHans Petter Selasky free(il, M_IDR);
2088d59ecb2SHans Petter Selasky return;
2098d59ecb2SHans Petter Selasky }
2108d59ecb2SHans Petter Selasky for (i = 0; i < IDR_SIZE; i++)
2118d59ecb2SHans Petter Selasky if (il->ary[i])
2128d59ecb2SHans Petter Selasky idr_remove_layer(il->ary[i], layer - 1);
2138d59ecb2SHans Petter Selasky }
2148d59ecb2SHans Petter Selasky
2158d59ecb2SHans Petter Selasky void
idr_remove_all(struct idr * idr)2168d59ecb2SHans Petter Selasky idr_remove_all(struct idr *idr)
2178d59ecb2SHans Petter Selasky {
2188d59ecb2SHans Petter Selasky
2198d59ecb2SHans Petter Selasky mtx_lock(&idr->lock);
2208d59ecb2SHans Petter Selasky idr_remove_layer(idr->top, idr->layers - 1);
2218d59ecb2SHans Petter Selasky idr->top = NULL;
2228d59ecb2SHans Petter Selasky idr->layers = 0;
2238d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock);
2248d59ecb2SHans Petter Selasky }
2258d59ecb2SHans Petter Selasky
22669d6653bSHans Petter Selasky static void *
idr_remove_locked(struct idr * idr,int id)2272d1bee65SHans Petter Selasky idr_remove_locked(struct idr *idr, int id)
2288d59ecb2SHans Petter Selasky {
2298d59ecb2SHans Petter Selasky struct idr_layer *il;
23069d6653bSHans Petter Selasky void *res;
2318d59ecb2SHans Petter Selasky int layer;
2328d59ecb2SHans Petter Selasky int idx;
2338d59ecb2SHans Petter Selasky
2348d59ecb2SHans Petter Selasky id &= MAX_ID_MASK;
2358d59ecb2SHans Petter Selasky il = idr->top;
2368d59ecb2SHans Petter Selasky layer = idr->layers - 1;
2372d1bee65SHans Petter Selasky if (il == NULL || id > idr_max(idr))
23869d6653bSHans Petter Selasky return (NULL);
2398d59ecb2SHans Petter Selasky /*
2408d59ecb2SHans Petter Selasky * Walk down the tree to this item setting bitmaps along the way
2418d59ecb2SHans Petter Selasky * as we know at least one item will be free along this path.
2428d59ecb2SHans Petter Selasky */
2438d59ecb2SHans Petter Selasky while (layer && il) {
2448d59ecb2SHans Petter Selasky idx = idr_pos(id, layer);
2458d59ecb2SHans Petter Selasky il->bitmap |= 1 << idx;
2468d59ecb2SHans Petter Selasky il = il->ary[idx];
2478d59ecb2SHans Petter Selasky layer--;
2488d59ecb2SHans Petter Selasky }
2498d59ecb2SHans Petter Selasky idx = id & IDR_MASK;
2508d59ecb2SHans Petter Selasky /*
2518d59ecb2SHans Petter Selasky * At this point we've set free space bitmaps up the whole tree.
2528d59ecb2SHans Petter Selasky * We could make this non-fatal and unwind but linux dumps a stack
2538d59ecb2SHans Petter Selasky * and a warning so I don't think it's necessary.
2548d59ecb2SHans Petter Selasky */
2558d59ecb2SHans Petter Selasky if (il == NULL || (il->bitmap & (1 << idx)) != 0)
2568d59ecb2SHans Petter Selasky panic("idr_remove: Item %d not allocated (%p, %p)\n",
2578d59ecb2SHans Petter Selasky id, idr, il);
25869d6653bSHans Petter Selasky res = il->ary[idx];
2598d59ecb2SHans Petter Selasky il->ary[idx] = NULL;
2608d59ecb2SHans Petter Selasky il->bitmap |= 1 << idx;
26169d6653bSHans Petter Selasky
26269d6653bSHans Petter Selasky return (res);
2632d1bee65SHans Petter Selasky }
2642d1bee65SHans Petter Selasky
26569d6653bSHans Petter Selasky void *
idr_remove(struct idr * idr,int id)2662d1bee65SHans Petter Selasky idr_remove(struct idr *idr, int id)
2672d1bee65SHans Petter Selasky {
26869d6653bSHans Petter Selasky void *res;
26969d6653bSHans Petter Selasky
2702d1bee65SHans Petter Selasky mtx_lock(&idr->lock);
27169d6653bSHans Petter Selasky res = idr_remove_locked(idr, id);
2728d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock);
27369d6653bSHans Petter Selasky
27469d6653bSHans Petter Selasky return (res);
2758d59ecb2SHans Petter Selasky }
2768d59ecb2SHans Petter Selasky
277f8221002SHans Petter Selasky static inline struct idr_layer *
idr_find_layer_locked(struct idr * idr,int id)278f8221002SHans Petter Selasky idr_find_layer_locked(struct idr *idr, int id)
279f8221002SHans Petter Selasky {
280f8221002SHans Petter Selasky struct idr_layer *il;
281f8221002SHans Petter Selasky int layer;
282f8221002SHans Petter Selasky
283f8221002SHans Petter Selasky id &= MAX_ID_MASK;
284f8221002SHans Petter Selasky il = idr->top;
285f8221002SHans Petter Selasky layer = idr->layers - 1;
286f8221002SHans Petter Selasky if (il == NULL || id > idr_max(idr))
287f8221002SHans Petter Selasky return (NULL);
288f8221002SHans Petter Selasky while (layer && il) {
289f8221002SHans Petter Selasky il = il->ary[idr_pos(id, layer)];
290f8221002SHans Petter Selasky layer--;
291f8221002SHans Petter Selasky }
292f8221002SHans Petter Selasky return (il);
293f8221002SHans Petter Selasky }
294f8221002SHans Petter Selasky
2958d59ecb2SHans Petter Selasky void *
idr_replace(struct idr * idr,void * ptr,int id)2968d59ecb2SHans Petter Selasky idr_replace(struct idr *idr, void *ptr, int id)
2978d59ecb2SHans Petter Selasky {
2988d59ecb2SHans Petter Selasky struct idr_layer *il;
2998d59ecb2SHans Petter Selasky void *res;
3008d59ecb2SHans Petter Selasky int idx;
3018d59ecb2SHans Petter Selasky
3028d59ecb2SHans Petter Selasky mtx_lock(&idr->lock);
303f8221002SHans Petter Selasky il = idr_find_layer_locked(idr, id);
3048d59ecb2SHans Petter Selasky idx = id & IDR_MASK;
305f8221002SHans Petter Selasky
306f8221002SHans Petter Selasky /* Replace still returns an error if the item was not allocated. */
307f8221002SHans Petter Selasky if (il == NULL || (il->bitmap & (1 << idx))) {
308f8221002SHans Petter Selasky res = ERR_PTR(-ENOENT);
309f8221002SHans Petter Selasky } else {
3108d59ecb2SHans Petter Selasky res = il->ary[idx];
3118d59ecb2SHans Petter Selasky il->ary[idx] = ptr;
3128d59ecb2SHans Petter Selasky }
3138d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock);
3148d59ecb2SHans Petter Selasky return (res);
3158d59ecb2SHans Petter Selasky }
3168d59ecb2SHans Petter Selasky
3178d59ecb2SHans Petter Selasky static inline void *
idr_find_locked(struct idr * idr,int id)3188d59ecb2SHans Petter Selasky idr_find_locked(struct idr *idr, int id)
3198d59ecb2SHans Petter Selasky {
3208d59ecb2SHans Petter Selasky struct idr_layer *il;
3218d59ecb2SHans Petter Selasky void *res;
3228d59ecb2SHans Petter Selasky
3238d59ecb2SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED);
324f8221002SHans Petter Selasky il = idr_find_layer_locked(idr, id);
3258d59ecb2SHans Petter Selasky if (il != NULL)
3268d59ecb2SHans Petter Selasky res = il->ary[id & IDR_MASK];
327f8221002SHans Petter Selasky else
328f8221002SHans Petter Selasky res = NULL;
3298d59ecb2SHans Petter Selasky return (res);
3308d59ecb2SHans Petter Selasky }
3318d59ecb2SHans Petter Selasky
3328d59ecb2SHans Petter Selasky void *
idr_find(struct idr * idr,int id)3338d59ecb2SHans Petter Selasky idr_find(struct idr *idr, int id)
3348d59ecb2SHans Petter Selasky {
3358d59ecb2SHans Petter Selasky void *res;
3368d59ecb2SHans Petter Selasky
3378d59ecb2SHans Petter Selasky mtx_lock(&idr->lock);
3388d59ecb2SHans Petter Selasky res = idr_find_locked(idr, id);
3398d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock);
3408d59ecb2SHans Petter Selasky return (res);
3418d59ecb2SHans Petter Selasky }
3428d59ecb2SHans Petter Selasky
343fd42d623SHans Petter Selasky void *
idr_get_next(struct idr * idr,int * nextidp)344fd42d623SHans Petter Selasky idr_get_next(struct idr *idr, int *nextidp)
345fd42d623SHans Petter Selasky {
346fd42d623SHans Petter Selasky void *res = NULL;
347fd42d623SHans Petter Selasky int id = *nextidp;
348fd42d623SHans Petter Selasky
349fd42d623SHans Petter Selasky mtx_lock(&idr->lock);
350fd42d623SHans Petter Selasky for (; id <= idr_max(idr); id++) {
351fd42d623SHans Petter Selasky res = idr_find_locked(idr, id);
352fd42d623SHans Petter Selasky if (res == NULL)
353fd42d623SHans Petter Selasky continue;
354fd42d623SHans Petter Selasky *nextidp = id;
355fd42d623SHans Petter Selasky break;
356fd42d623SHans Petter Selasky }
357fd42d623SHans Petter Selasky mtx_unlock(&idr->lock);
358fd42d623SHans Petter Selasky return (res);
359fd42d623SHans Petter Selasky }
360fd42d623SHans Petter Selasky
3618d59ecb2SHans Petter Selasky int
idr_pre_get(struct idr * idr,gfp_t gfp_mask)3628d59ecb2SHans Petter Selasky idr_pre_get(struct idr *idr, gfp_t gfp_mask)
3638d59ecb2SHans Petter Selasky {
3648d59ecb2SHans Petter Selasky struct idr_layer *il, *iln;
3658d59ecb2SHans Petter Selasky struct idr_layer *head;
3668d59ecb2SHans Petter Selasky int need;
3678d59ecb2SHans Petter Selasky
3688d59ecb2SHans Petter Selasky mtx_lock(&idr->lock);
3698d59ecb2SHans Petter Selasky for (;;) {
3708d59ecb2SHans Petter Selasky need = idr->layers + 1;
3718d59ecb2SHans Petter Selasky for (il = idr->free; il != NULL; il = il->ary[0])
3728d59ecb2SHans Petter Selasky need--;
3738d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock);
3748d59ecb2SHans Petter Selasky if (need <= 0)
3758d59ecb2SHans Petter Selasky break;
3768d59ecb2SHans Petter Selasky for (head = NULL; need; need--) {
3778d59ecb2SHans Petter Selasky iln = malloc(sizeof(*il), M_IDR, M_ZERO | gfp_mask);
3788d59ecb2SHans Petter Selasky if (iln == NULL)
3798d59ecb2SHans Petter Selasky break;
3808d59ecb2SHans Petter Selasky bitmap_fill(&iln->bitmap, IDR_SIZE);
3818d59ecb2SHans Petter Selasky if (head != NULL) {
3828d59ecb2SHans Petter Selasky il->ary[0] = iln;
3838d59ecb2SHans Petter Selasky il = iln;
3848d59ecb2SHans Petter Selasky } else
3858d59ecb2SHans Petter Selasky head = il = iln;
3868d59ecb2SHans Petter Selasky }
3878d59ecb2SHans Petter Selasky if (head == NULL)
3888d59ecb2SHans Petter Selasky return (0);
3898d59ecb2SHans Petter Selasky mtx_lock(&idr->lock);
3908d59ecb2SHans Petter Selasky il->ary[0] = idr->free;
3918d59ecb2SHans Petter Selasky idr->free = head;
3928d59ecb2SHans Petter Selasky }
3938d59ecb2SHans Petter Selasky return (1);
3948d59ecb2SHans Petter Selasky }
3958d59ecb2SHans Petter Selasky
396427cefdeSHans Petter Selasky static struct idr_layer *
idr_free_list_get(struct idr * idp)397427cefdeSHans Petter Selasky idr_free_list_get(struct idr *idp)
3988d59ecb2SHans Petter Selasky {
3998d59ecb2SHans Petter Selasky struct idr_layer *il;
4008d59ecb2SHans Petter Selasky
401427cefdeSHans Petter Selasky if ((il = idp->free) != NULL) {
402427cefdeSHans Petter Selasky idp->free = il->ary[0];
4038d59ecb2SHans Petter Selasky il->ary[0] = NULL;
404427cefdeSHans Petter Selasky }
4058d59ecb2SHans Petter Selasky return (il);
4068d59ecb2SHans Petter Selasky }
407427cefdeSHans Petter Selasky
408427cefdeSHans Petter Selasky static inline struct idr_layer *
idr_get(struct idr * idp)409427cefdeSHans Petter Selasky idr_get(struct idr *idp)
410427cefdeSHans Petter Selasky {
411427cefdeSHans Petter Selasky struct idr_layer *il;
412427cefdeSHans Petter Selasky
413427cefdeSHans Petter Selasky if ((il = idr_free_list_get(idp)) != NULL) {
414427cefdeSHans Petter Selasky MPASS(il->bitmap != 0);
415427cefdeSHans Petter Selasky } else if ((il = malloc(sizeof(*il), M_IDR, M_ZERO | M_NOWAIT)) != NULL) {
4168d59ecb2SHans Petter Selasky bitmap_fill(&il->bitmap, IDR_SIZE);
417427cefdeSHans Petter Selasky } else if ((il = idr_preload_dequeue_locked(&DPCPU_GET(linux_idr_cache))) != NULL) {
418427cefdeSHans Petter Selasky bitmap_fill(&il->bitmap, IDR_SIZE);
419427cefdeSHans Petter Selasky } else {
420427cefdeSHans Petter Selasky return (NULL);
421427cefdeSHans Petter Selasky }
4228d59ecb2SHans Petter Selasky return (il);
4238d59ecb2SHans Petter Selasky }
4248d59ecb2SHans Petter Selasky
4258d59ecb2SHans Petter Selasky /*
4268d59ecb2SHans Petter Selasky * Could be implemented as get_new_above(idr, ptr, 0, idp) but written
4278d59ecb2SHans Petter Selasky * first for simplicity sake.
4288d59ecb2SHans Petter Selasky */
4292d1bee65SHans Petter Selasky static int
idr_get_new_locked(struct idr * idr,void * ptr,int * idp)4302d1bee65SHans Petter Selasky idr_get_new_locked(struct idr *idr, void *ptr, int *idp)
4318d59ecb2SHans Petter Selasky {
4328d59ecb2SHans Petter Selasky struct idr_layer *stack[MAX_LEVEL];
4338d59ecb2SHans Petter Selasky struct idr_layer *il;
4348d59ecb2SHans Petter Selasky int error;
4358d59ecb2SHans Petter Selasky int layer;
4368d59ecb2SHans Petter Selasky int idx;
4378d59ecb2SHans Petter Selasky int id;
4388d59ecb2SHans Petter Selasky
4392d1bee65SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED);
4402d1bee65SHans Petter Selasky
4418d59ecb2SHans Petter Selasky error = -EAGAIN;
4428d59ecb2SHans Petter Selasky /*
4438d59ecb2SHans Petter Selasky * Expand the tree until there is free space.
4448d59ecb2SHans Petter Selasky */
4458d59ecb2SHans Petter Selasky if (idr->top == NULL || idr->top->bitmap == 0) {
4468d59ecb2SHans Petter Selasky if (idr->layers == MAX_LEVEL + 1) {
4478d59ecb2SHans Petter Selasky error = -ENOSPC;
4488d59ecb2SHans Petter Selasky goto out;
4498d59ecb2SHans Petter Selasky }
4508d59ecb2SHans Petter Selasky il = idr_get(idr);
4518d59ecb2SHans Petter Selasky if (il == NULL)
4528d59ecb2SHans Petter Selasky goto out;
4538d59ecb2SHans Petter Selasky il->ary[0] = idr->top;
4548d59ecb2SHans Petter Selasky if (idr->top)
4558d59ecb2SHans Petter Selasky il->bitmap &= ~1;
4568d59ecb2SHans Petter Selasky idr->top = il;
4578d59ecb2SHans Petter Selasky idr->layers++;
4588d59ecb2SHans Petter Selasky }
4598d59ecb2SHans Petter Selasky il = idr->top;
4608d59ecb2SHans Petter Selasky id = 0;
4618d59ecb2SHans Petter Selasky /*
4628d59ecb2SHans Petter Selasky * Walk the tree following free bitmaps, record our path.
4638d59ecb2SHans Petter Selasky */
4648d59ecb2SHans Petter Selasky for (layer = idr->layers - 1;; layer--) {
4658d59ecb2SHans Petter Selasky stack[layer] = il;
4668d59ecb2SHans Petter Selasky idx = ffsl(il->bitmap);
4678d59ecb2SHans Petter Selasky if (idx == 0)
4688d59ecb2SHans Petter Selasky panic("idr_get_new: Invalid leaf state (%p, %p)\n",
4698d59ecb2SHans Petter Selasky idr, il);
4708d59ecb2SHans Petter Selasky idx--;
4718d59ecb2SHans Petter Selasky id |= idx << (layer * IDR_BITS);
4728d59ecb2SHans Petter Selasky if (layer == 0)
4738d59ecb2SHans Petter Selasky break;
4748d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) {
4758d59ecb2SHans Petter Selasky il->ary[idx] = idr_get(idr);
4768d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL)
4778d59ecb2SHans Petter Selasky goto out;
4788d59ecb2SHans Petter Selasky }
4798d59ecb2SHans Petter Selasky il = il->ary[idx];
4808d59ecb2SHans Petter Selasky }
4818d59ecb2SHans Petter Selasky /*
4828d59ecb2SHans Petter Selasky * Allocate the leaf to the consumer.
4838d59ecb2SHans Petter Selasky */
4848d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idx);
4858d59ecb2SHans Petter Selasky il->ary[idx] = ptr;
4868d59ecb2SHans Petter Selasky *idp = id;
4878d59ecb2SHans Petter Selasky /*
4888d59ecb2SHans Petter Selasky * Clear bitmaps potentially up to the root.
4898d59ecb2SHans Petter Selasky */
4908d59ecb2SHans Petter Selasky while (il->bitmap == 0 && ++layer < idr->layers) {
4918d59ecb2SHans Petter Selasky il = stack[layer];
4928d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idr_pos(id, layer));
4938d59ecb2SHans Petter Selasky }
4948d59ecb2SHans Petter Selasky error = 0;
4958d59ecb2SHans Petter Selasky out:
4968d59ecb2SHans Petter Selasky #ifdef INVARIANTS
4978d59ecb2SHans Petter Selasky if (error == 0 && idr_find_locked(idr, id) != ptr) {
4988d59ecb2SHans Petter Selasky panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n",
4998d59ecb2SHans Petter Selasky idr, id, ptr);
5008d59ecb2SHans Petter Selasky }
5018d59ecb2SHans Petter Selasky #endif
5028d59ecb2SHans Petter Selasky return (error);
5038d59ecb2SHans Petter Selasky }
5048d59ecb2SHans Petter Selasky
5058d59ecb2SHans Petter Selasky int
idr_get_new(struct idr * idr,void * ptr,int * idp)5062d1bee65SHans Petter Selasky idr_get_new(struct idr *idr, void *ptr, int *idp)
5072d1bee65SHans Petter Selasky {
5082d1bee65SHans Petter Selasky int retval;
5092d1bee65SHans Petter Selasky
5102d1bee65SHans Petter Selasky mtx_lock(&idr->lock);
5112d1bee65SHans Petter Selasky retval = idr_get_new_locked(idr, ptr, idp);
5122d1bee65SHans Petter Selasky mtx_unlock(&idr->lock);
5132d1bee65SHans Petter Selasky return (retval);
5142d1bee65SHans Petter Selasky }
5152d1bee65SHans Petter Selasky
5162d1bee65SHans Petter Selasky static int
idr_get_new_above_locked(struct idr * idr,void * ptr,int starting_id,int * idp)5172d1bee65SHans Petter Selasky idr_get_new_above_locked(struct idr *idr, void *ptr, int starting_id, int *idp)
5188d59ecb2SHans Petter Selasky {
5198d59ecb2SHans Petter Selasky struct idr_layer *stack[MAX_LEVEL];
5208d59ecb2SHans Petter Selasky struct idr_layer *il;
5218d59ecb2SHans Petter Selasky int error;
5228d59ecb2SHans Petter Selasky int layer;
5238d59ecb2SHans Petter Selasky int idx, sidx;
5248d59ecb2SHans Petter Selasky int id;
5258d59ecb2SHans Petter Selasky
5262d1bee65SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED);
5272d1bee65SHans Petter Selasky
5288d59ecb2SHans Petter Selasky error = -EAGAIN;
5298d59ecb2SHans Petter Selasky /*
5308d59ecb2SHans Petter Selasky * Compute the layers required to support starting_id and the mask
5318d59ecb2SHans Petter Selasky * at the top layer.
5328d59ecb2SHans Petter Selasky */
5338d59ecb2SHans Petter Selasky restart:
5348d59ecb2SHans Petter Selasky idx = starting_id;
5358d59ecb2SHans Petter Selasky layer = 0;
5368d59ecb2SHans Petter Selasky while (idx & ~IDR_MASK) {
5378d59ecb2SHans Petter Selasky layer++;
5388d59ecb2SHans Petter Selasky idx >>= IDR_BITS;
5398d59ecb2SHans Petter Selasky }
5408d59ecb2SHans Petter Selasky if (layer == MAX_LEVEL + 1) {
5418d59ecb2SHans Petter Selasky error = -ENOSPC;
5428d59ecb2SHans Petter Selasky goto out;
5438d59ecb2SHans Petter Selasky }
5448d59ecb2SHans Petter Selasky /*
5458d59ecb2SHans Petter Selasky * Expand the tree until there is free space at or beyond starting_id.
5468d59ecb2SHans Petter Selasky */
5478d59ecb2SHans Petter Selasky while (idr->layers <= layer ||
5488d59ecb2SHans Petter Selasky idr->top->bitmap < (1 << idr_pos(starting_id, idr->layers - 1))) {
5498d59ecb2SHans Petter Selasky if (idr->layers == MAX_LEVEL + 1) {
5508d59ecb2SHans Petter Selasky error = -ENOSPC;
5518d59ecb2SHans Petter Selasky goto out;
5528d59ecb2SHans Petter Selasky }
5538d59ecb2SHans Petter Selasky il = idr_get(idr);
5548d59ecb2SHans Petter Selasky if (il == NULL)
5558d59ecb2SHans Petter Selasky goto out;
5568d59ecb2SHans Petter Selasky il->ary[0] = idr->top;
5578d59ecb2SHans Petter Selasky if (idr->top && idr->top->bitmap == 0)
5588d59ecb2SHans Petter Selasky il->bitmap &= ~1;
5598d59ecb2SHans Petter Selasky idr->top = il;
5608d59ecb2SHans Petter Selasky idr->layers++;
5618d59ecb2SHans Petter Selasky }
5628d59ecb2SHans Petter Selasky il = idr->top;
5638d59ecb2SHans Petter Selasky id = 0;
5648d59ecb2SHans Petter Selasky /*
5658d59ecb2SHans Petter Selasky * Walk the tree following free bitmaps, record our path.
5668d59ecb2SHans Petter Selasky */
5678d59ecb2SHans Petter Selasky for (layer = idr->layers - 1;; layer--) {
5688d59ecb2SHans Petter Selasky stack[layer] = il;
5698d59ecb2SHans Petter Selasky sidx = idr_pos(starting_id, layer);
5708d59ecb2SHans Petter Selasky /* Returns index numbered from 0 or size if none exists. */
5718d59ecb2SHans Petter Selasky idx = find_next_bit(&il->bitmap, IDR_SIZE, sidx);
5728d59ecb2SHans Petter Selasky if (idx == IDR_SIZE && sidx == 0)
5738d59ecb2SHans Petter Selasky panic("idr_get_new: Invalid leaf state (%p, %p)\n",
5748d59ecb2SHans Petter Selasky idr, il);
5758d59ecb2SHans Petter Selasky /*
5768d59ecb2SHans Petter Selasky * We may have walked a path where there was a free bit but
5778d59ecb2SHans Petter Selasky * it was lower than what we wanted. Restart the search with
5788d59ecb2SHans Petter Selasky * a larger starting id. id contains the progress we made so
5798d59ecb2SHans Petter Selasky * far. Search the leaf one above this level. This may
5808d59ecb2SHans Petter Selasky * restart as many as MAX_LEVEL times but that is expected
5818d59ecb2SHans Petter Selasky * to be rare.
5828d59ecb2SHans Petter Selasky */
5838d59ecb2SHans Petter Selasky if (idx == IDR_SIZE) {
5848d59ecb2SHans Petter Selasky starting_id = id + (1 << ((layer + 1) * IDR_BITS));
5858d59ecb2SHans Petter Selasky goto restart;
5868d59ecb2SHans Petter Selasky }
5878d59ecb2SHans Petter Selasky if (idx > sidx)
5888d59ecb2SHans Petter Selasky starting_id = 0; /* Search the whole subtree. */
5898d59ecb2SHans Petter Selasky id |= idx << (layer * IDR_BITS);
5908d59ecb2SHans Petter Selasky if (layer == 0)
5918d59ecb2SHans Petter Selasky break;
5928d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) {
5938d59ecb2SHans Petter Selasky il->ary[idx] = idr_get(idr);
5948d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL)
5958d59ecb2SHans Petter Selasky goto out;
5968d59ecb2SHans Petter Selasky }
5978d59ecb2SHans Petter Selasky il = il->ary[idx];
5988d59ecb2SHans Petter Selasky }
5998d59ecb2SHans Petter Selasky /*
6008d59ecb2SHans Petter Selasky * Allocate the leaf to the consumer.
6018d59ecb2SHans Petter Selasky */
6028d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idx);
6038d59ecb2SHans Petter Selasky il->ary[idx] = ptr;
6048d59ecb2SHans Petter Selasky *idp = id;
6058d59ecb2SHans Petter Selasky /*
6068d59ecb2SHans Petter Selasky * Clear bitmaps potentially up to the root.
6078d59ecb2SHans Petter Selasky */
6088d59ecb2SHans Petter Selasky while (il->bitmap == 0 && ++layer < idr->layers) {
6098d59ecb2SHans Petter Selasky il = stack[layer];
6108d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idr_pos(id, layer));
6118d59ecb2SHans Petter Selasky }
6128d59ecb2SHans Petter Selasky error = 0;
6138d59ecb2SHans Petter Selasky out:
6148d59ecb2SHans Petter Selasky #ifdef INVARIANTS
6158d59ecb2SHans Petter Selasky if (error == 0 && idr_find_locked(idr, id) != ptr) {
6168d59ecb2SHans Petter Selasky panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n",
6178d59ecb2SHans Petter Selasky idr, id, ptr);
6188d59ecb2SHans Petter Selasky }
6198d59ecb2SHans Petter Selasky #endif
6208d59ecb2SHans Petter Selasky return (error);
6218d59ecb2SHans Petter Selasky }
6222d1bee65SHans Petter Selasky
6232d1bee65SHans Petter Selasky int
idr_get_new_above(struct idr * idr,void * ptr,int starting_id,int * idp)6242d1bee65SHans Petter Selasky idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp)
6252d1bee65SHans Petter Selasky {
6262d1bee65SHans Petter Selasky int retval;
6272d1bee65SHans Petter Selasky
6282d1bee65SHans Petter Selasky mtx_lock(&idr->lock);
6292d1bee65SHans Petter Selasky retval = idr_get_new_above_locked(idr, ptr, starting_id, idp);
6302d1bee65SHans Petter Selasky mtx_unlock(&idr->lock);
6312d1bee65SHans Petter Selasky return (retval);
6322d1bee65SHans Petter Selasky }
6332d1bee65SHans Petter Selasky
634fd42d623SHans Petter Selasky int
ida_get_new_above(struct ida * ida,int starting_id,int * p_id)635fd42d623SHans Petter Selasky ida_get_new_above(struct ida *ida, int starting_id, int *p_id)
636fd42d623SHans Petter Selasky {
637fd42d623SHans Petter Selasky return (idr_get_new_above(&ida->idr, NULL, starting_id, p_id));
638fd42d623SHans Petter Selasky }
639fd42d623SHans Petter Selasky
6402d1bee65SHans Petter Selasky static int
idr_alloc_locked(struct idr * idr,void * ptr,int start,int end)6412d1bee65SHans Petter Selasky idr_alloc_locked(struct idr *idr, void *ptr, int start, int end)
6422d1bee65SHans Petter Selasky {
6432d1bee65SHans Petter Selasky int max = end > 0 ? end - 1 : INT_MAX;
6442d1bee65SHans Petter Selasky int error;
6452d1bee65SHans Petter Selasky int id;
6462d1bee65SHans Petter Selasky
6472d1bee65SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED);
6482d1bee65SHans Petter Selasky
6492d1bee65SHans Petter Selasky if (unlikely(start < 0))
6502d1bee65SHans Petter Selasky return (-EINVAL);
6512d1bee65SHans Petter Selasky if (unlikely(max < start))
6522d1bee65SHans Petter Selasky return (-ENOSPC);
6532d1bee65SHans Petter Selasky
6542d1bee65SHans Petter Selasky if (start == 0)
6552d1bee65SHans Petter Selasky error = idr_get_new_locked(idr, ptr, &id);
6562d1bee65SHans Petter Selasky else
6572d1bee65SHans Petter Selasky error = idr_get_new_above_locked(idr, ptr, start, &id);
6582d1bee65SHans Petter Selasky
6592d1bee65SHans Petter Selasky if (unlikely(error < 0))
6602d1bee65SHans Petter Selasky return (error);
6612d1bee65SHans Petter Selasky if (unlikely(id > max)) {
6622d1bee65SHans Petter Selasky idr_remove_locked(idr, id);
6632d1bee65SHans Petter Selasky return (-ENOSPC);
6642d1bee65SHans Petter Selasky }
6652d1bee65SHans Petter Selasky return (id);
6662d1bee65SHans Petter Selasky }
6672d1bee65SHans Petter Selasky
6682d1bee65SHans Petter Selasky int
idr_alloc(struct idr * idr,void * ptr,int start,int end,gfp_t gfp_mask)6692d1bee65SHans Petter Selasky idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
6702d1bee65SHans Petter Selasky {
6712d1bee65SHans Petter Selasky int retval;
6722d1bee65SHans Petter Selasky
6732d1bee65SHans Petter Selasky mtx_lock(&idr->lock);
6742d1bee65SHans Petter Selasky retval = idr_alloc_locked(idr, ptr, start, end);
6752d1bee65SHans Petter Selasky mtx_unlock(&idr->lock);
6762d1bee65SHans Petter Selasky return (retval);
6772d1bee65SHans Petter Selasky }
6782d1bee65SHans Petter Selasky
6792d1bee65SHans Petter Selasky int
idr_alloc_cyclic(struct idr * idr,void * ptr,int start,int end,gfp_t gfp_mask)6802d1bee65SHans Petter Selasky idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
6812d1bee65SHans Petter Selasky {
6822d1bee65SHans Petter Selasky int retval;
6832d1bee65SHans Petter Selasky
6842d1bee65SHans Petter Selasky mtx_lock(&idr->lock);
6852d1bee65SHans Petter Selasky retval = idr_alloc_locked(idr, ptr, max(start, idr->next_cyclic_id), end);
6862d1bee65SHans Petter Selasky if (unlikely(retval == -ENOSPC))
6872d1bee65SHans Petter Selasky retval = idr_alloc_locked(idr, ptr, start, end);
6882d1bee65SHans Petter Selasky if (likely(retval >= 0))
6892d1bee65SHans Petter Selasky idr->next_cyclic_id = retval + 1;
6902d1bee65SHans Petter Selasky mtx_unlock(&idr->lock);
6912d1bee65SHans Petter Selasky return (retval);
6922d1bee65SHans Petter Selasky }
693fd42d623SHans Petter Selasky
694fd42d623SHans Petter Selasky static int
idr_for_each_layer(struct idr_layer * il,int offset,int layer,int (* f)(int id,void * p,void * data),void * data)695f885420dSHans Petter Selasky idr_for_each_layer(struct idr_layer *il, int offset, int layer,
696fd42d623SHans Petter Selasky int (*f)(int id, void *p, void *data), void *data)
697fd42d623SHans Petter Selasky {
698fd42d623SHans Petter Selasky int i, err;
699fd42d623SHans Petter Selasky
700fd42d623SHans Petter Selasky if (il == NULL)
701fd42d623SHans Petter Selasky return (0);
702fd42d623SHans Petter Selasky if (layer == 0) {
703fd42d623SHans Petter Selasky for (i = 0; i < IDR_SIZE; i++) {
704fd42d623SHans Petter Selasky if (il->ary[i] == NULL)
705fd42d623SHans Petter Selasky continue;
706f885420dSHans Petter Selasky err = f(i + offset, il->ary[i], data);
707fd42d623SHans Petter Selasky if (err)
708fd42d623SHans Petter Selasky return (err);
709fd42d623SHans Petter Selasky }
710fd42d623SHans Petter Selasky return (0);
711fd42d623SHans Petter Selasky }
712fd42d623SHans Petter Selasky for (i = 0; i < IDR_SIZE; i++) {
713fd42d623SHans Petter Selasky if (il->ary[i] == NULL)
714fd42d623SHans Petter Selasky continue;
715f885420dSHans Petter Selasky err = idr_for_each_layer(il->ary[i],
716f885420dSHans Petter Selasky (i + offset) * IDR_SIZE, layer - 1, f, data);
717fd42d623SHans Petter Selasky if (err)
718fd42d623SHans Petter Selasky return (err);
719fd42d623SHans Petter Selasky }
720fd42d623SHans Petter Selasky return (0);
721fd42d623SHans Petter Selasky }
722fd42d623SHans Petter Selasky
723dacb734eSHans Petter Selasky /* NOTE: It is not allowed to modify the IDR tree while it is being iterated */
724fd42d623SHans Petter Selasky int
idr_for_each(struct idr * idp,int (* f)(int id,void * p,void * data),void * data)725fd42d623SHans Petter Selasky idr_for_each(struct idr *idp, int (*f)(int id, void *p, void *data), void *data)
726fd42d623SHans Petter Selasky {
727f885420dSHans Petter Selasky return (idr_for_each_layer(idp->top, 0, idp->layers - 1, f, data));
728fd42d623SHans Petter Selasky }
729fd42d623SHans Petter Selasky
73069d6653bSHans Petter Selasky static int
idr_has_entry(int id,void * p,void * data)73169d6653bSHans Petter Selasky idr_has_entry(int id, void *p, void *data)
73269d6653bSHans Petter Selasky {
73369d6653bSHans Petter Selasky
73469d6653bSHans Petter Selasky return (1);
73569d6653bSHans Petter Selasky }
73669d6653bSHans Petter Selasky
73769d6653bSHans Petter Selasky bool
idr_is_empty(struct idr * idp)73869d6653bSHans Petter Selasky idr_is_empty(struct idr *idp)
73969d6653bSHans Petter Selasky {
74069d6653bSHans Petter Selasky
74169d6653bSHans Petter Selasky return (idr_for_each(idp, idr_has_entry, NULL) == 0);
74269d6653bSHans Petter Selasky }
74369d6653bSHans Petter Selasky
744fd42d623SHans Petter Selasky int
ida_pre_get(struct ida * ida,gfp_t flags)745fd42d623SHans Petter Selasky ida_pre_get(struct ida *ida, gfp_t flags)
746fd42d623SHans Petter Selasky {
747fd42d623SHans Petter Selasky if (idr_pre_get(&ida->idr, flags) == 0)
748fd42d623SHans Petter Selasky return (0);
749fd42d623SHans Petter Selasky
750fd42d623SHans Petter Selasky if (ida->free_bitmap == NULL) {
751fd42d623SHans Petter Selasky ida->free_bitmap =
752fd42d623SHans Petter Selasky malloc(sizeof(struct ida_bitmap), M_IDR, flags);
753fd42d623SHans Petter Selasky }
754fd42d623SHans Petter Selasky return (ida->free_bitmap != NULL);
755fd42d623SHans Petter Selasky }
756fd42d623SHans Petter Selasky
757fd42d623SHans Petter Selasky int
ida_simple_get(struct ida * ida,unsigned int start,unsigned int end,gfp_t flags)758fd42d623SHans Petter Selasky ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
759fd42d623SHans Petter Selasky gfp_t flags)
760fd42d623SHans Petter Selasky {
761fd42d623SHans Petter Selasky int ret, id;
762fd42d623SHans Petter Selasky unsigned int max;
763fd42d623SHans Petter Selasky
764fd42d623SHans Petter Selasky MPASS((int)start >= 0);
765fd42d623SHans Petter Selasky
766c7312643SVladimir Kondratyev if ((int)end <= 0)
767c7312643SVladimir Kondratyev max = INT_MAX;
768fd42d623SHans Petter Selasky else {
769fd42d623SHans Petter Selasky MPASS(end > start);
770fd42d623SHans Petter Selasky max = end - 1;
771fd42d623SHans Petter Selasky }
772fd42d623SHans Petter Selasky again:
773fd42d623SHans Petter Selasky if (!ida_pre_get(ida, flags))
774fd42d623SHans Petter Selasky return (-ENOMEM);
775fd42d623SHans Petter Selasky
776fd42d623SHans Petter Selasky if ((ret = ida_get_new_above(ida, start, &id)) == 0) {
777fd42d623SHans Petter Selasky if (id > max) {
778fd42d623SHans Petter Selasky ida_remove(ida, id);
779fd42d623SHans Petter Selasky ret = -ENOSPC;
780fd42d623SHans Petter Selasky } else {
781fd42d623SHans Petter Selasky ret = id;
782fd42d623SHans Petter Selasky }
783fd42d623SHans Petter Selasky }
784fd42d623SHans Petter Selasky if (__predict_false(ret == -EAGAIN))
785fd42d623SHans Petter Selasky goto again;
786fd42d623SHans Petter Selasky
787fd42d623SHans Petter Selasky return (ret);
788fd42d623SHans Petter Selasky }
789fd42d623SHans Petter Selasky
790fd42d623SHans Petter Selasky void
ida_simple_remove(struct ida * ida,unsigned int id)791fd42d623SHans Petter Selasky ida_simple_remove(struct ida *ida, unsigned int id)
792fd42d623SHans Petter Selasky {
793fd42d623SHans Petter Selasky idr_remove(&ida->idr, id);
794fd42d623SHans Petter Selasky }
795fd42d623SHans Petter Selasky
796fd42d623SHans Petter Selasky void
ida_remove(struct ida * ida,int id)797fd42d623SHans Petter Selasky ida_remove(struct ida *ida, int id)
798fd42d623SHans Petter Selasky {
799fd42d623SHans Petter Selasky idr_remove(&ida->idr, id);
800fd42d623SHans Petter Selasky }
801fd42d623SHans Petter Selasky
802fd42d623SHans Petter Selasky void
ida_init(struct ida * ida)803fd42d623SHans Petter Selasky ida_init(struct ida *ida)
804fd42d623SHans Petter Selasky {
805fd42d623SHans Petter Selasky idr_init(&ida->idr);
806fd42d623SHans Petter Selasky }
807fd42d623SHans Petter Selasky
808fd42d623SHans Petter Selasky void
ida_destroy(struct ida * ida)809fd42d623SHans Petter Selasky ida_destroy(struct ida *ida)
810fd42d623SHans Petter Selasky {
811fd42d623SHans Petter Selasky idr_destroy(&ida->idr);
812fd42d623SHans Petter Selasky free(ida->free_bitmap, M_IDR);
813*613723baSAustin Shafer ida->free_bitmap = NULL;
814fd42d623SHans Petter Selasky }
815