xref: /freebsd/sys/compat/linuxkpi/common/src/linux_idr.c (revision 8d59ecb214f7e078e57d35b865f33efc5d7cdf4d)
1*8d59ecb2SHans Petter Selasky /*-
2*8d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Isilon Systems, Inc.
3*8d59ecb2SHans Petter Selasky  * Copyright (c) 2010 iX Systems, Inc.
4*8d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Panasas, Inc.
5*8d59ecb2SHans Petter Selasky  * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
6*8d59ecb2SHans Petter Selasky  * All rights reserved.
7*8d59ecb2SHans Petter Selasky  *
8*8d59ecb2SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
9*8d59ecb2SHans Petter Selasky  * modification, are permitted provided that the following conditions
10*8d59ecb2SHans Petter Selasky  * are met:
11*8d59ecb2SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
12*8d59ecb2SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
13*8d59ecb2SHans Petter Selasky  *    disclaimer.
14*8d59ecb2SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
15*8d59ecb2SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
16*8d59ecb2SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
17*8d59ecb2SHans Petter Selasky  *
18*8d59ecb2SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19*8d59ecb2SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20*8d59ecb2SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21*8d59ecb2SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22*8d59ecb2SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23*8d59ecb2SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*8d59ecb2SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*8d59ecb2SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*8d59ecb2SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27*8d59ecb2SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*8d59ecb2SHans Petter Selasky  */
29*8d59ecb2SHans Petter Selasky 
30*8d59ecb2SHans Petter Selasky #include <sys/cdefs.h>
31*8d59ecb2SHans Petter Selasky __FBSDID("$FreeBSD$");
32*8d59ecb2SHans Petter Selasky 
33*8d59ecb2SHans Petter Selasky #include <sys/param.h>
34*8d59ecb2SHans Petter Selasky #include <sys/systm.h>
35*8d59ecb2SHans Petter Selasky #include <sys/malloc.h>
36*8d59ecb2SHans Petter Selasky #include <sys/kernel.h>
37*8d59ecb2SHans Petter Selasky #include <sys/sysctl.h>
38*8d59ecb2SHans Petter Selasky #include <sys/lock.h>
39*8d59ecb2SHans Petter Selasky #include <sys/mutex.h>
40*8d59ecb2SHans Petter Selasky 
41*8d59ecb2SHans Petter Selasky #include <machine/stdarg.h>
42*8d59ecb2SHans Petter Selasky 
43*8d59ecb2SHans Petter Selasky #include <linux/bitops.h>
44*8d59ecb2SHans Petter Selasky #include <linux/kobject.h>
45*8d59ecb2SHans Petter Selasky #include <linux/slab.h>
46*8d59ecb2SHans Petter Selasky #include <linux/idr.h>
47*8d59ecb2SHans Petter Selasky #include <linux/err.h>
48*8d59ecb2SHans Petter Selasky 
49*8d59ecb2SHans Petter Selasky /*
50*8d59ecb2SHans Petter Selasky  * IDR Implementation.
51*8d59ecb2SHans Petter Selasky  *
52*8d59ecb2SHans Petter Selasky  * This is quick and dirty and not as re-entrant as the linux version
53*8d59ecb2SHans Petter Selasky  * however it should be fairly fast.  It is basically a radix tree with
54*8d59ecb2SHans Petter Selasky  * a builtin bitmap for allocation.
55*8d59ecb2SHans Petter Selasky  */
56*8d59ecb2SHans Petter Selasky static MALLOC_DEFINE(M_IDR, "idr", "Linux IDR compat");
57*8d59ecb2SHans Petter Selasky 
58*8d59ecb2SHans Petter Selasky static inline int
59*8d59ecb2SHans Petter Selasky idr_max(struct idr *idr)
60*8d59ecb2SHans Petter Selasky {
61*8d59ecb2SHans Petter Selasky 	return (1 << (idr->layers * IDR_BITS)) - 1;
62*8d59ecb2SHans Petter Selasky }
63*8d59ecb2SHans Petter Selasky 
64*8d59ecb2SHans Petter Selasky static inline int
65*8d59ecb2SHans Petter Selasky idr_pos(int id, int layer)
66*8d59ecb2SHans Petter Selasky {
67*8d59ecb2SHans Petter Selasky 	return (id >> (IDR_BITS * layer)) & IDR_MASK;
68*8d59ecb2SHans Petter Selasky }
69*8d59ecb2SHans Petter Selasky 
70*8d59ecb2SHans Petter Selasky void
71*8d59ecb2SHans Petter Selasky idr_init(struct idr *idr)
72*8d59ecb2SHans Petter Selasky {
73*8d59ecb2SHans Petter Selasky 	bzero(idr, sizeof(*idr));
74*8d59ecb2SHans Petter Selasky 	mtx_init(&idr->lock, "idr", NULL, MTX_DEF);
75*8d59ecb2SHans Petter Selasky }
76*8d59ecb2SHans Petter Selasky 
77*8d59ecb2SHans Petter Selasky /* Only frees cached pages. */
78*8d59ecb2SHans Petter Selasky void
79*8d59ecb2SHans Petter Selasky idr_destroy(struct idr *idr)
80*8d59ecb2SHans Petter Selasky {
81*8d59ecb2SHans Petter Selasky 	struct idr_layer *il, *iln;
82*8d59ecb2SHans Petter Selasky 
83*8d59ecb2SHans Petter Selasky 	idr_remove_all(idr);
84*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
85*8d59ecb2SHans Petter Selasky 	for (il = idr->free; il != NULL; il = iln) {
86*8d59ecb2SHans Petter Selasky 		iln = il->ary[0];
87*8d59ecb2SHans Petter Selasky 		free(il, M_IDR);
88*8d59ecb2SHans Petter Selasky 	}
89*8d59ecb2SHans Petter Selasky 	mtx_unlock(&idr->lock);
90*8d59ecb2SHans Petter Selasky }
91*8d59ecb2SHans Petter Selasky 
92*8d59ecb2SHans Petter Selasky static void
93*8d59ecb2SHans Petter Selasky idr_remove_layer(struct idr_layer *il, int layer)
94*8d59ecb2SHans Petter Selasky {
95*8d59ecb2SHans Petter Selasky 	int i;
96*8d59ecb2SHans Petter Selasky 
97*8d59ecb2SHans Petter Selasky 	if (il == NULL)
98*8d59ecb2SHans Petter Selasky 		return;
99*8d59ecb2SHans Petter Selasky 	if (layer == 0) {
100*8d59ecb2SHans Petter Selasky 		free(il, M_IDR);
101*8d59ecb2SHans Petter Selasky 		return;
102*8d59ecb2SHans Petter Selasky 	}
103*8d59ecb2SHans Petter Selasky 	for (i = 0; i < IDR_SIZE; i++)
104*8d59ecb2SHans Petter Selasky 		if (il->ary[i])
105*8d59ecb2SHans Petter Selasky 			idr_remove_layer(il->ary[i], layer - 1);
106*8d59ecb2SHans Petter Selasky }
107*8d59ecb2SHans Petter Selasky 
108*8d59ecb2SHans Petter Selasky void
109*8d59ecb2SHans Petter Selasky idr_remove_all(struct idr *idr)
110*8d59ecb2SHans Petter Selasky {
111*8d59ecb2SHans Petter Selasky 
112*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
113*8d59ecb2SHans Petter Selasky 	idr_remove_layer(idr->top, idr->layers - 1);
114*8d59ecb2SHans Petter Selasky 	idr->top = NULL;
115*8d59ecb2SHans Petter Selasky 	idr->layers = 0;
116*8d59ecb2SHans Petter Selasky 	mtx_unlock(&idr->lock);
117*8d59ecb2SHans Petter Selasky }
118*8d59ecb2SHans Petter Selasky 
119*8d59ecb2SHans Petter Selasky void
120*8d59ecb2SHans Petter Selasky idr_remove(struct idr *idr, int id)
121*8d59ecb2SHans Petter Selasky {
122*8d59ecb2SHans Petter Selasky 	struct idr_layer *il;
123*8d59ecb2SHans Petter Selasky 	int layer;
124*8d59ecb2SHans Petter Selasky 	int idx;
125*8d59ecb2SHans Petter Selasky 
126*8d59ecb2SHans Petter Selasky 	id &= MAX_ID_MASK;
127*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
128*8d59ecb2SHans Petter Selasky 	il = idr->top;
129*8d59ecb2SHans Petter Selasky 	layer = idr->layers - 1;
130*8d59ecb2SHans Petter Selasky 	if (il == NULL || id > idr_max(idr)) {
131*8d59ecb2SHans Petter Selasky 		mtx_unlock(&idr->lock);
132*8d59ecb2SHans Petter Selasky 		return;
133*8d59ecb2SHans Petter Selasky 	}
134*8d59ecb2SHans Petter Selasky 	/*
135*8d59ecb2SHans Petter Selasky 	 * Walk down the tree to this item setting bitmaps along the way
136*8d59ecb2SHans Petter Selasky 	 * as we know at least one item will be free along this path.
137*8d59ecb2SHans Petter Selasky 	 */
138*8d59ecb2SHans Petter Selasky 	while (layer && il) {
139*8d59ecb2SHans Petter Selasky 		idx = idr_pos(id, layer);
140*8d59ecb2SHans Petter Selasky 		il->bitmap |= 1 << idx;
141*8d59ecb2SHans Petter Selasky 		il = il->ary[idx];
142*8d59ecb2SHans Petter Selasky 		layer--;
143*8d59ecb2SHans Petter Selasky 	}
144*8d59ecb2SHans Petter Selasky 	idx = id & IDR_MASK;
145*8d59ecb2SHans Petter Selasky 	/*
146*8d59ecb2SHans Petter Selasky 	 * At this point we've set free space bitmaps up the whole tree.
147*8d59ecb2SHans Petter Selasky 	 * We could make this non-fatal and unwind but linux dumps a stack
148*8d59ecb2SHans Petter Selasky 	 * and a warning so I don't think it's necessary.
149*8d59ecb2SHans Petter Selasky 	 */
150*8d59ecb2SHans Petter Selasky 	if (il == NULL || (il->bitmap & (1 << idx)) != 0)
151*8d59ecb2SHans Petter Selasky 		panic("idr_remove: Item %d not allocated (%p, %p)\n",
152*8d59ecb2SHans Petter Selasky 		    id, idr, il);
153*8d59ecb2SHans Petter Selasky 	il->ary[idx] = NULL;
154*8d59ecb2SHans Petter Selasky 	il->bitmap |= 1 << idx;
155*8d59ecb2SHans Petter Selasky 	mtx_unlock(&idr->lock);
156*8d59ecb2SHans Petter Selasky 	return;
157*8d59ecb2SHans Petter Selasky }
158*8d59ecb2SHans Petter Selasky 
159*8d59ecb2SHans Petter Selasky void *
160*8d59ecb2SHans Petter Selasky idr_replace(struct idr *idr, void *ptr, int id)
161*8d59ecb2SHans Petter Selasky {
162*8d59ecb2SHans Petter Selasky 	struct idr_layer *il;
163*8d59ecb2SHans Petter Selasky 	void *res;
164*8d59ecb2SHans Petter Selasky 	int layer;
165*8d59ecb2SHans Petter Selasky 	int idx;
166*8d59ecb2SHans Petter Selasky 
167*8d59ecb2SHans Petter Selasky 	res = ERR_PTR(-EINVAL);
168*8d59ecb2SHans Petter Selasky 	id &= MAX_ID_MASK;
169*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
170*8d59ecb2SHans Petter Selasky 	il = idr->top;
171*8d59ecb2SHans Petter Selasky 	layer = idr->layers - 1;
172*8d59ecb2SHans Petter Selasky 	if (il == NULL || id > idr_max(idr))
173*8d59ecb2SHans Petter Selasky 		goto out;
174*8d59ecb2SHans Petter Selasky 	while (layer && il) {
175*8d59ecb2SHans Petter Selasky 		il = il->ary[idr_pos(id, layer)];
176*8d59ecb2SHans Petter Selasky 		layer--;
177*8d59ecb2SHans Petter Selasky 	}
178*8d59ecb2SHans Petter Selasky 	idx = id & IDR_MASK;
179*8d59ecb2SHans Petter Selasky 	/*
180*8d59ecb2SHans Petter Selasky 	 * Replace still returns an error if the item was not allocated.
181*8d59ecb2SHans Petter Selasky 	 */
182*8d59ecb2SHans Petter Selasky 	if (il != NULL && (il->bitmap & (1 << idx)) != 0) {
183*8d59ecb2SHans Petter Selasky 		res = il->ary[idx];
184*8d59ecb2SHans Petter Selasky 		il->ary[idx] = ptr;
185*8d59ecb2SHans Petter Selasky 	}
186*8d59ecb2SHans Petter Selasky out:
187*8d59ecb2SHans Petter Selasky 	mtx_unlock(&idr->lock);
188*8d59ecb2SHans Petter Selasky 	return (res);
189*8d59ecb2SHans Petter Selasky }
190*8d59ecb2SHans Petter Selasky 
191*8d59ecb2SHans Petter Selasky static inline void *
192*8d59ecb2SHans Petter Selasky idr_find_locked(struct idr *idr, int id)
193*8d59ecb2SHans Petter Selasky {
194*8d59ecb2SHans Petter Selasky 	struct idr_layer *il;
195*8d59ecb2SHans Petter Selasky 	void *res;
196*8d59ecb2SHans Petter Selasky 	int layer;
197*8d59ecb2SHans Petter Selasky 
198*8d59ecb2SHans Petter Selasky 	mtx_assert(&idr->lock, MA_OWNED);
199*8d59ecb2SHans Petter Selasky 
200*8d59ecb2SHans Petter Selasky 	id &= MAX_ID_MASK;
201*8d59ecb2SHans Petter Selasky 	res = NULL;
202*8d59ecb2SHans Petter Selasky 	il = idr->top;
203*8d59ecb2SHans Petter Selasky 	layer = idr->layers - 1;
204*8d59ecb2SHans Petter Selasky 	if (il == NULL || id > idr_max(idr))
205*8d59ecb2SHans Petter Selasky 		return (NULL);
206*8d59ecb2SHans Petter Selasky 	while (layer && il) {
207*8d59ecb2SHans Petter Selasky 		il = il->ary[idr_pos(id, layer)];
208*8d59ecb2SHans Petter Selasky 		layer--;
209*8d59ecb2SHans Petter Selasky 	}
210*8d59ecb2SHans Petter Selasky 	if (il != NULL)
211*8d59ecb2SHans Petter Selasky 		res = il->ary[id & IDR_MASK];
212*8d59ecb2SHans Petter Selasky 	return (res);
213*8d59ecb2SHans Petter Selasky }
214*8d59ecb2SHans Petter Selasky 
215*8d59ecb2SHans Petter Selasky void *
216*8d59ecb2SHans Petter Selasky idr_find(struct idr *idr, int id)
217*8d59ecb2SHans Petter Selasky {
218*8d59ecb2SHans Petter Selasky 	void *res;
219*8d59ecb2SHans Petter Selasky 
220*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
221*8d59ecb2SHans Petter Selasky 	res = idr_find_locked(idr, id);
222*8d59ecb2SHans Petter Selasky 	mtx_unlock(&idr->lock);
223*8d59ecb2SHans Petter Selasky 	return (res);
224*8d59ecb2SHans Petter Selasky }
225*8d59ecb2SHans Petter Selasky 
226*8d59ecb2SHans Petter Selasky int
227*8d59ecb2SHans Petter Selasky idr_pre_get(struct idr *idr, gfp_t gfp_mask)
228*8d59ecb2SHans Petter Selasky {
229*8d59ecb2SHans Petter Selasky 	struct idr_layer *il, *iln;
230*8d59ecb2SHans Petter Selasky 	struct idr_layer *head;
231*8d59ecb2SHans Petter Selasky 	int need;
232*8d59ecb2SHans Petter Selasky 
233*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
234*8d59ecb2SHans Petter Selasky 	for (;;) {
235*8d59ecb2SHans Petter Selasky 		need = idr->layers + 1;
236*8d59ecb2SHans Petter Selasky 		for (il = idr->free; il != NULL; il = il->ary[0])
237*8d59ecb2SHans Petter Selasky 			need--;
238*8d59ecb2SHans Petter Selasky 		mtx_unlock(&idr->lock);
239*8d59ecb2SHans Petter Selasky 		if (need <= 0)
240*8d59ecb2SHans Petter Selasky 			break;
241*8d59ecb2SHans Petter Selasky 		for (head = NULL; need; need--) {
242*8d59ecb2SHans Petter Selasky 			iln = malloc(sizeof(*il), M_IDR, M_ZERO | gfp_mask);
243*8d59ecb2SHans Petter Selasky 			if (iln == NULL)
244*8d59ecb2SHans Petter Selasky 				break;
245*8d59ecb2SHans Petter Selasky 			bitmap_fill(&iln->bitmap, IDR_SIZE);
246*8d59ecb2SHans Petter Selasky 			if (head != NULL) {
247*8d59ecb2SHans Petter Selasky 				il->ary[0] = iln;
248*8d59ecb2SHans Petter Selasky 				il = iln;
249*8d59ecb2SHans Petter Selasky 			} else
250*8d59ecb2SHans Petter Selasky 				head = il = iln;
251*8d59ecb2SHans Petter Selasky 		}
252*8d59ecb2SHans Petter Selasky 		if (head == NULL)
253*8d59ecb2SHans Petter Selasky 			return (0);
254*8d59ecb2SHans Petter Selasky 		mtx_lock(&idr->lock);
255*8d59ecb2SHans Petter Selasky 		il->ary[0] = idr->free;
256*8d59ecb2SHans Petter Selasky 		idr->free = head;
257*8d59ecb2SHans Petter Selasky 	}
258*8d59ecb2SHans Petter Selasky 	return (1);
259*8d59ecb2SHans Petter Selasky }
260*8d59ecb2SHans Petter Selasky 
261*8d59ecb2SHans Petter Selasky static inline struct idr_layer *
262*8d59ecb2SHans Petter Selasky idr_get(struct idr *idr)
263*8d59ecb2SHans Petter Selasky {
264*8d59ecb2SHans Petter Selasky 	struct idr_layer *il;
265*8d59ecb2SHans Petter Selasky 
266*8d59ecb2SHans Petter Selasky 	il = idr->free;
267*8d59ecb2SHans Petter Selasky 	if (il) {
268*8d59ecb2SHans Petter Selasky 		idr->free = il->ary[0];
269*8d59ecb2SHans Petter Selasky 		il->ary[0] = NULL;
270*8d59ecb2SHans Petter Selasky 		return (il);
271*8d59ecb2SHans Petter Selasky 	}
272*8d59ecb2SHans Petter Selasky 	il = malloc(sizeof(*il), M_IDR, M_ZERO | M_NOWAIT);
273*8d59ecb2SHans Petter Selasky 	bitmap_fill(&il->bitmap, IDR_SIZE);
274*8d59ecb2SHans Petter Selasky 	return (il);
275*8d59ecb2SHans Petter Selasky }
276*8d59ecb2SHans Petter Selasky 
277*8d59ecb2SHans Petter Selasky /*
278*8d59ecb2SHans Petter Selasky  * Could be implemented as get_new_above(idr, ptr, 0, idp) but written
279*8d59ecb2SHans Petter Selasky  * first for simplicity sake.
280*8d59ecb2SHans Petter Selasky  */
281*8d59ecb2SHans Petter Selasky int
282*8d59ecb2SHans Petter Selasky idr_get_new(struct idr *idr, void *ptr, int *idp)
283*8d59ecb2SHans Petter Selasky {
284*8d59ecb2SHans Petter Selasky 	struct idr_layer *stack[MAX_LEVEL];
285*8d59ecb2SHans Petter Selasky 	struct idr_layer *il;
286*8d59ecb2SHans Petter Selasky 	int error;
287*8d59ecb2SHans Petter Selasky 	int layer;
288*8d59ecb2SHans Petter Selasky 	int idx;
289*8d59ecb2SHans Petter Selasky 	int id;
290*8d59ecb2SHans Petter Selasky 
291*8d59ecb2SHans Petter Selasky 	error = -EAGAIN;
292*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
293*8d59ecb2SHans Petter Selasky 	/*
294*8d59ecb2SHans Petter Selasky 	 * Expand the tree until there is free space.
295*8d59ecb2SHans Petter Selasky 	 */
296*8d59ecb2SHans Petter Selasky 	if (idr->top == NULL || idr->top->bitmap == 0) {
297*8d59ecb2SHans Petter Selasky 		if (idr->layers == MAX_LEVEL + 1) {
298*8d59ecb2SHans Petter Selasky 			error = -ENOSPC;
299*8d59ecb2SHans Petter Selasky 			goto out;
300*8d59ecb2SHans Petter Selasky 		}
301*8d59ecb2SHans Petter Selasky 		il = idr_get(idr);
302*8d59ecb2SHans Petter Selasky 		if (il == NULL)
303*8d59ecb2SHans Petter Selasky 			goto out;
304*8d59ecb2SHans Petter Selasky 		il->ary[0] = idr->top;
305*8d59ecb2SHans Petter Selasky 		if (idr->top)
306*8d59ecb2SHans Petter Selasky 			il->bitmap &= ~1;
307*8d59ecb2SHans Petter Selasky 		idr->top = il;
308*8d59ecb2SHans Petter Selasky 		idr->layers++;
309*8d59ecb2SHans Petter Selasky 	}
310*8d59ecb2SHans Petter Selasky 	il = idr->top;
311*8d59ecb2SHans Petter Selasky 	id = 0;
312*8d59ecb2SHans Petter Selasky 	/*
313*8d59ecb2SHans Petter Selasky 	 * Walk the tree following free bitmaps, record our path.
314*8d59ecb2SHans Petter Selasky 	 */
315*8d59ecb2SHans Petter Selasky 	for (layer = idr->layers - 1;; layer--) {
316*8d59ecb2SHans Petter Selasky 		stack[layer] = il;
317*8d59ecb2SHans Petter Selasky 		idx = ffsl(il->bitmap);
318*8d59ecb2SHans Petter Selasky 		if (idx == 0)
319*8d59ecb2SHans Petter Selasky 			panic("idr_get_new: Invalid leaf state (%p, %p)\n",
320*8d59ecb2SHans Petter Selasky 			    idr, il);
321*8d59ecb2SHans Petter Selasky 		idx--;
322*8d59ecb2SHans Petter Selasky 		id |= idx << (layer * IDR_BITS);
323*8d59ecb2SHans Petter Selasky 		if (layer == 0)
324*8d59ecb2SHans Petter Selasky 			break;
325*8d59ecb2SHans Petter Selasky 		if (il->ary[idx] == NULL) {
326*8d59ecb2SHans Petter Selasky 			il->ary[idx] = idr_get(idr);
327*8d59ecb2SHans Petter Selasky 			if (il->ary[idx] == NULL)
328*8d59ecb2SHans Petter Selasky 				goto out;
329*8d59ecb2SHans Petter Selasky 		}
330*8d59ecb2SHans Petter Selasky 		il = il->ary[idx];
331*8d59ecb2SHans Petter Selasky 	}
332*8d59ecb2SHans Petter Selasky 	/*
333*8d59ecb2SHans Petter Selasky 	 * Allocate the leaf to the consumer.
334*8d59ecb2SHans Petter Selasky 	 */
335*8d59ecb2SHans Petter Selasky 	il->bitmap &= ~(1 << idx);
336*8d59ecb2SHans Petter Selasky 	il->ary[idx] = ptr;
337*8d59ecb2SHans Petter Selasky 	*idp = id;
338*8d59ecb2SHans Petter Selasky 	/*
339*8d59ecb2SHans Petter Selasky 	 * Clear bitmaps potentially up to the root.
340*8d59ecb2SHans Petter Selasky 	 */
341*8d59ecb2SHans Petter Selasky 	while (il->bitmap == 0 && ++layer < idr->layers) {
342*8d59ecb2SHans Petter Selasky 		il = stack[layer];
343*8d59ecb2SHans Petter Selasky 		il->bitmap &= ~(1 << idr_pos(id, layer));
344*8d59ecb2SHans Petter Selasky 	}
345*8d59ecb2SHans Petter Selasky 	error = 0;
346*8d59ecb2SHans Petter Selasky out:
347*8d59ecb2SHans Petter Selasky #ifdef INVARIANTS
348*8d59ecb2SHans Petter Selasky 	if (error == 0 && idr_find_locked(idr, id) != ptr) {
349*8d59ecb2SHans Petter Selasky 		panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n",
350*8d59ecb2SHans Petter Selasky 		    idr, id, ptr);
351*8d59ecb2SHans Petter Selasky 	}
352*8d59ecb2SHans Petter Selasky #endif
353*8d59ecb2SHans Petter Selasky 	mtx_unlock(&idr->lock);
354*8d59ecb2SHans Petter Selasky 	return (error);
355*8d59ecb2SHans Petter Selasky }
356*8d59ecb2SHans Petter Selasky 
357*8d59ecb2SHans Petter Selasky int
358*8d59ecb2SHans Petter Selasky idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp)
359*8d59ecb2SHans Petter Selasky {
360*8d59ecb2SHans Petter Selasky 	struct idr_layer *stack[MAX_LEVEL];
361*8d59ecb2SHans Petter Selasky 	struct idr_layer *il;
362*8d59ecb2SHans Petter Selasky 	int error;
363*8d59ecb2SHans Petter Selasky 	int layer;
364*8d59ecb2SHans Petter Selasky 	int idx, sidx;
365*8d59ecb2SHans Petter Selasky 	int id;
366*8d59ecb2SHans Petter Selasky 
367*8d59ecb2SHans Petter Selasky 	error = -EAGAIN;
368*8d59ecb2SHans Petter Selasky 	mtx_lock(&idr->lock);
369*8d59ecb2SHans Petter Selasky 	/*
370*8d59ecb2SHans Petter Selasky 	 * Compute the layers required to support starting_id and the mask
371*8d59ecb2SHans Petter Selasky 	 * at the top layer.
372*8d59ecb2SHans Petter Selasky 	 */
373*8d59ecb2SHans Petter Selasky restart:
374*8d59ecb2SHans Petter Selasky 	idx = starting_id;
375*8d59ecb2SHans Petter Selasky 	layer = 0;
376*8d59ecb2SHans Petter Selasky 	while (idx & ~IDR_MASK) {
377*8d59ecb2SHans Petter Selasky 		layer++;
378*8d59ecb2SHans Petter Selasky 		idx >>= IDR_BITS;
379*8d59ecb2SHans Petter Selasky 	}
380*8d59ecb2SHans Petter Selasky 	if (layer == MAX_LEVEL + 1) {
381*8d59ecb2SHans Petter Selasky 		error = -ENOSPC;
382*8d59ecb2SHans Petter Selasky 		goto out;
383*8d59ecb2SHans Petter Selasky 	}
384*8d59ecb2SHans Petter Selasky 	/*
385*8d59ecb2SHans Petter Selasky 	 * Expand the tree until there is free space at or beyond starting_id.
386*8d59ecb2SHans Petter Selasky 	 */
387*8d59ecb2SHans Petter Selasky 	while (idr->layers <= layer ||
388*8d59ecb2SHans Petter Selasky 	    idr->top->bitmap < (1 << idr_pos(starting_id, idr->layers - 1))) {
389*8d59ecb2SHans Petter Selasky 		if (idr->layers == MAX_LEVEL + 1) {
390*8d59ecb2SHans Petter Selasky 			error = -ENOSPC;
391*8d59ecb2SHans Petter Selasky 			goto out;
392*8d59ecb2SHans Petter Selasky 		}
393*8d59ecb2SHans Petter Selasky 		il = idr_get(idr);
394*8d59ecb2SHans Petter Selasky 		if (il == NULL)
395*8d59ecb2SHans Petter Selasky 			goto out;
396*8d59ecb2SHans Petter Selasky 		il->ary[0] = idr->top;
397*8d59ecb2SHans Petter Selasky 		if (idr->top && idr->top->bitmap == 0)
398*8d59ecb2SHans Petter Selasky 			il->bitmap &= ~1;
399*8d59ecb2SHans Petter Selasky 		idr->top = il;
400*8d59ecb2SHans Petter Selasky 		idr->layers++;
401*8d59ecb2SHans Petter Selasky 	}
402*8d59ecb2SHans Petter Selasky 	il = idr->top;
403*8d59ecb2SHans Petter Selasky 	id = 0;
404*8d59ecb2SHans Petter Selasky 	/*
405*8d59ecb2SHans Petter Selasky 	 * Walk the tree following free bitmaps, record our path.
406*8d59ecb2SHans Petter Selasky 	 */
407*8d59ecb2SHans Petter Selasky 	for (layer = idr->layers - 1;; layer--) {
408*8d59ecb2SHans Petter Selasky 		stack[layer] = il;
409*8d59ecb2SHans Petter Selasky 		sidx = idr_pos(starting_id, layer);
410*8d59ecb2SHans Petter Selasky 		/* Returns index numbered from 0 or size if none exists. */
411*8d59ecb2SHans Petter Selasky 		idx = find_next_bit(&il->bitmap, IDR_SIZE, sidx);
412*8d59ecb2SHans Petter Selasky 		if (idx == IDR_SIZE && sidx == 0)
413*8d59ecb2SHans Petter Selasky 			panic("idr_get_new: Invalid leaf state (%p, %p)\n",
414*8d59ecb2SHans Petter Selasky 			    idr, il);
415*8d59ecb2SHans Petter Selasky 		/*
416*8d59ecb2SHans Petter Selasky 		 * We may have walked a path where there was a free bit but
417*8d59ecb2SHans Petter Selasky 		 * it was lower than what we wanted.  Restart the search with
418*8d59ecb2SHans Petter Selasky 		 * a larger starting id.  id contains the progress we made so
419*8d59ecb2SHans Petter Selasky 		 * far.  Search the leaf one above this level.  This may
420*8d59ecb2SHans Petter Selasky 		 * restart as many as MAX_LEVEL times but that is expected
421*8d59ecb2SHans Petter Selasky 		 * to be rare.
422*8d59ecb2SHans Petter Selasky 		 */
423*8d59ecb2SHans Petter Selasky 		if (idx == IDR_SIZE) {
424*8d59ecb2SHans Petter Selasky 			starting_id = id + (1 << ((layer + 1) * IDR_BITS));
425*8d59ecb2SHans Petter Selasky 			goto restart;
426*8d59ecb2SHans Petter Selasky 		}
427*8d59ecb2SHans Petter Selasky 		if (idx > sidx)
428*8d59ecb2SHans Petter Selasky 			starting_id = 0;	/* Search the whole subtree. */
429*8d59ecb2SHans Petter Selasky 		id |= idx << (layer * IDR_BITS);
430*8d59ecb2SHans Petter Selasky 		if (layer == 0)
431*8d59ecb2SHans Petter Selasky 			break;
432*8d59ecb2SHans Petter Selasky 		if (il->ary[idx] == NULL) {
433*8d59ecb2SHans Petter Selasky 			il->ary[idx] = idr_get(idr);
434*8d59ecb2SHans Petter Selasky 			if (il->ary[idx] == NULL)
435*8d59ecb2SHans Petter Selasky 				goto out;
436*8d59ecb2SHans Petter Selasky 		}
437*8d59ecb2SHans Petter Selasky 		il = il->ary[idx];
438*8d59ecb2SHans Petter Selasky 	}
439*8d59ecb2SHans Petter Selasky 	/*
440*8d59ecb2SHans Petter Selasky 	 * Allocate the leaf to the consumer.
441*8d59ecb2SHans Petter Selasky 	 */
442*8d59ecb2SHans Petter Selasky 	il->bitmap &= ~(1 << idx);
443*8d59ecb2SHans Petter Selasky 	il->ary[idx] = ptr;
444*8d59ecb2SHans Petter Selasky 	*idp = id;
445*8d59ecb2SHans Petter Selasky 	/*
446*8d59ecb2SHans Petter Selasky 	 * Clear bitmaps potentially up to the root.
447*8d59ecb2SHans Petter Selasky 	 */
448*8d59ecb2SHans Petter Selasky 	while (il->bitmap == 0 && ++layer < idr->layers) {
449*8d59ecb2SHans Petter Selasky 		il = stack[layer];
450*8d59ecb2SHans Petter Selasky 		il->bitmap &= ~(1 << idr_pos(id, layer));
451*8d59ecb2SHans Petter Selasky 	}
452*8d59ecb2SHans Petter Selasky 	error = 0;
453*8d59ecb2SHans Petter Selasky out:
454*8d59ecb2SHans Petter Selasky #ifdef INVARIANTS
455*8d59ecb2SHans Petter Selasky 	if (error == 0 && idr_find_locked(idr, id) != ptr) {
456*8d59ecb2SHans Petter Selasky 		panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n",
457*8d59ecb2SHans Petter Selasky 		    idr, id, ptr);
458*8d59ecb2SHans Petter Selasky 	}
459*8d59ecb2SHans Petter Selasky #endif
460*8d59ecb2SHans Petter Selasky 	mtx_unlock(&idr->lock);
461*8d59ecb2SHans Petter Selasky 	return (error);
462*8d59ecb2SHans Petter Selasky }
463