2 * Copyright (c) 2005-2012 The DragonFly Project.
3 * Copyright (c) 2013 François Tigeot
6 * This code is derived from software contributed to The DragonFly Project
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
19 * 3. Neither the name of The DragonFly Project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific, prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <sys/kernel.h>
40 #include <sys/libkern.h>
41 #include <sys/malloc.h>
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/spinlock2.h>
45 #include <sys/limits.h>
47 #define IDR_DEFAULT_SIZE 256
49 MALLOC_DEFINE(M_IDR, "idr", "Integer ID management");
51 static void idr_grow(struct idr *idp, int want);
52 static void idr_reserve(struct idr *idp, int id, int incr);
53 static void idr_set(struct idr *idp, int id, void *ptr);
54 static int idr_find_free(struct idr *idp, int want, int lim);
55 static int idr_pre_get1(struct idr *idp, int want, int lim);
58 * Number of nodes in right subtree, including the root.
61 right_subtree_size(int n)
63 return (n ^ (n | (n + 1)));
81 return ((n & (n + 1)) - 1);
85 idrfixup(struct idr *idp, int id)
87 if (id < idp->idr_freeindex) {
88 idp->idr_freeindex = id;
90 while (idp->idr_lastindex >= 0 &&
91 idp->idr_nodes[idp->idr_lastindex].data == NULL &&
92 idp->idr_nodes[idp->idr_lastindex].reserved == 0
98 static __inline struct idr_node *
99 idr_get_node(struct idr *idp, int id)
101 struct idr_node *idrnp;
102 if (id >= idp->idr_count)
104 idrnp = &idp->idr_nodes[id];
105 if (idrnp->allocated == 0)
111 idr_reserve(struct idr *idp, int id, int incr)
114 idp->idr_nodes[id].allocated += incr;
115 KKASSERT(idp->idr_nodes[id].allocated >= 0);
116 id = left_ancestor(id);
121 idr_find_free(struct idr *idp, int want, int lim)
123 int id, rsum, rsize, node;
126 * Search for a free descriptor starting at the higher
127 * of want or fd_freefile. If that fails, consider
128 * expanding the ofile array.
130 * NOTE! the 'allocated' field is a cumulative recursive allocation
131 * count. If we happen to see a value of 0 then we can shortcut
132 * our search. Otherwise we run through through the tree going
133 * down branches we know have free descriptor(s) until we hit a
134 * leaf node. The leaf node will be free but will not necessarily
135 * have an allocated field of 0.
138 /* move up the tree looking for a subtree with a free node */
139 for (id = max(want, idp->idr_freeindex); id < min(idp->idr_count, lim);
140 id = right_ancestor(id)) {
141 if (idp->idr_nodes[id].allocated == 0)
144 rsize = right_subtree_size(id);
145 if (idp->idr_nodes[id].allocated == rsize)
146 continue; /* right subtree full */
149 * Free fd is in the right subtree of the tree rooted at fd.
150 * Call that subtree R. Look for the smallest (leftmost)
151 * subtree of R with an unallocated fd: continue moving
152 * down the left branch until encountering a full left
153 * subtree, then move to the right.
155 for (rsum = 0, rsize /= 2; rsize > 0; rsize /= 2) {
157 rsum += idp->idr_nodes[node].allocated;
158 if (idp->idr_nodes[id].allocated == rsum + rsize) {
159 id = node; /* move to the right */
160 if (idp->idr_nodes[node].allocated == 0)
171 idr_pre_get1(struct idr *idp, int want, int lim)
175 if (want >= idp->idr_count)
179 id = idr_find_free(idp, want, lim);
184 * No space in current array. Expand?
186 if (idp->idr_count >= lim) {
197 idr_pre_get(struct idr *idp)
199 lwkt_gettoken(&idp->idr_token);
200 int error = idr_pre_get1(idp, idp->idr_maxwant, INT_MAX);
201 lwkt_reltoken(&idp->idr_token);
206 idr_get_new(struct idr *idp, void *ptr, int *id)
213 lwkt_gettoken(&idp->idr_token);
214 resid = idr_find_free(idp, 0, INT_MAX);
216 lwkt_reltoken(&idp->idr_token);
220 if (resid > idp->idr_lastindex)
221 idp->idr_lastindex = resid;
222 idp->idr_freeindex = resid;
224 KKASSERT(idp->idr_nodes[resid].reserved == 0);
225 idp->idr_nodes[resid].reserved = 1;
226 idr_reserve(idp, resid, 1);
227 idr_set(idp, resid, ptr);
229 lwkt_reltoken(&idp->idr_token);
234 idr_get_new_above(struct idr *idp, void *ptr, int sid, int *id)
241 lwkt_gettoken(&idp->idr_token);
242 if (sid >= idp->idr_count) {
243 idp->idr_maxwant = max(idp->idr_maxwant, sid);
244 lwkt_reltoken(&idp->idr_token);
248 resid = idr_find_free(idp, sid, INT_MAX);
250 lwkt_reltoken(&idp->idr_token);
254 if (resid >= idp->idr_count)
255 idr_grow(idp, resid);
256 if (resid > idp->idr_lastindex)
257 idp->idr_lastindex = resid;
258 if (sid <= idp->idr_freeindex)
259 idp->idr_freeindex = resid;
261 KKASSERT(idp->idr_nodes[resid].reserved == 0);
262 idp->idr_nodes[resid].reserved = 1;
263 idr_reserve(idp, resid, 1);
264 idr_set(idp, resid, ptr);
266 lwkt_reltoken(&idp->idr_token);
271 * Grow the file table so it can hold through descriptor (want).
274 idr_grow(struct idr *idp, int want)
276 struct idr_node *newnodes;
277 struct idr_node *oldnodes;
282 /* nf has to be of the form 2^n - 1 */
284 } while (nf <= want);
286 newnodes = kmalloc(nf * sizeof(struct idr_node), M_IDR, M_WAITOK);
289 * Copy the existing ofile and ofileflags arrays
290 * and zero the new portion of each array.
292 extra = nf - idp->idr_count;
293 if (idp->idr_nodes != NULL)
294 bcopy(idp->idr_nodes, newnodes, idp->idr_count * sizeof(struct idr_node));
295 bzero(&newnodes[idp->idr_count], extra * sizeof(struct idr_node));
297 oldnodes = idp->idr_nodes;
298 idp->idr_nodes = newnodes;
301 if (oldnodes != NULL) {
302 kfree(oldnodes, M_IDR);
309 idr_remove(struct idr *idp, int id)
313 lwkt_gettoken(&idp->idr_token);
315 if (id >= idp->idr_count)
317 if ((ptr = idp->idr_nodes[id].data) == NULL)
319 idp->idr_nodes[id].data = NULL;
321 idr_reserve(idp, id, -1);
325 lwkt_reltoken(&idp->idr_token);
329 idr_remove_all(struct idr *idp)
331 kfree(idp->idr_nodes, M_IDR);
332 idp->idr_nodes = kmalloc(idp->idr_count * sizeof *idp, M_IDR, M_WAITOK | M_ZERO);
333 idp->idr_lastindex = -1;
334 idp->idr_freeindex = 0;
335 idp->idr_nexpands = 0;
336 idp->idr_maxwant = 0;
340 idr_destroy(struct idr *idp)
342 lwkt_token_uninit(&idp->idr_token);
343 kfree(idp->idr_nodes, M_IDR);
344 memset(idp, 0, sizeof(struct idr));
348 idr_find(struct idr *idp, int id)
352 lwkt_gettoken(&idp->idr_token);
354 if (id > idp->idr_count) {
356 } else if (idp->idr_nodes[id].allocated == 0) {
359 KKASSERT(idp->idr_nodes[id].data != NULL);
360 ret = idp->idr_nodes[id].data;
363 lwkt_reltoken(&idp->idr_token);
368 idr_set(struct idr *idp, int id, void *ptr)
370 KKASSERT(id < idp->idr_count);
371 KKASSERT(idp->idr_nodes[id].reserved != 0);
373 idp->idr_nodes[id].data = ptr;
374 idp->idr_nodes[id].reserved = 0;
376 idp->idr_nodes[id].reserved = 0;
377 idr_reserve(idp, id, -1);
383 idr_for_each(struct idr *idp, int (*fn)(int id, void *p, void *data), void *data)
386 struct idr_node *nodes = idp->idr_nodes;
388 lwkt_gettoken(&idp->idr_token);
389 for (i = 0; i < idp->idr_count; i++) {
390 if (nodes[i].data != NULL && nodes[i].allocated > 0) {
391 error = fn(i, nodes[i].data, data);
397 lwkt_reltoken(&idp->idr_token);
402 idr_replace(struct idr *idp, void *ptr, int id)
404 struct idr_node *idrnp;
407 lwkt_gettoken(&idp->idr_token);
409 idrnp = idr_get_node(idp, id);
410 if (idrnp == NULL || ptr == NULL)
417 lwkt_reltoken(&idp->idr_token);
422 idr_init(struct idr *idp)
424 bzero(idp, sizeof(struct idr));
425 idp->idr_nodes = kmalloc(IDR_DEFAULT_SIZE * sizeof(*idp),
426 M_IDR, M_WAITOK | M_ZERO);
427 idp->idr_count = IDR_DEFAULT_SIZE;
428 idp->idr_lastindex = -1;
429 idp->idr_maxwant = 0;
430 lwkt_token_init(&idp->idr_token, "idr token");