2 * Copyright (c) 2004 Poul-Henning Kamp
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 /* Unit number allocation functions.
31 * These functions implement a mixed run-length/bitmap management of unit
34 * Allocation is always lowest free number first.
36 * Worst case memory usage (disregarding boundary effects in the low end)
37 * is two bits for each slot in the unit number space. (For a full
38 * [0 ... UINT_MAX] space that is still a lot of course.)
40 * The typical case, where no unit numbers are freed, is managed in a
41 * constant sized memory footprint of:
42 * sizeof(struct unrhdr) + 2 * sizeof (struct unr) == 56 bytes on i386
44 * The caller must provide locking.
46 * A userland test program is included.
50 #include <sys/types.h>
51 #include <sys/queue.h>
52 #include <sys/bitstring.h>
56 #include <sys/param.h>
57 #include <sys/malloc.h>
58 #include <sys/kernel.h>
59 #include <sys/systm.h>
62 * In theory it would be smarter to allocate the individual blocks
63 * with the zone allocator, but at this time the expectation is that
64 * there will typically not even be enough allocations to fill a single
65 * page, so we stick with malloc for now.
67 static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation");
69 #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO)
70 #define Free(foo) free(foo, M_UNIT)
72 #else /* ...USERLAND */
77 #define KASSERT(cond, arg) \
85 #define Malloc(foo) calloc(foo, 1)
86 #define Free(foo) free(foo)
91 * This is our basic building block.
93 * It can be used in three different ways depending on the value of the ptr
95 * If ptr is NULL, it represents a run of free items.
96 * If ptr points to the unrhdr it represents a run of allocated items.
97 * Otherwise it points to an bitstring of allocated items.
99 * For runs the len field is the length of the run.
100 * For bitmaps the len field represents the number of allocated items.
102 * The bitmap is the same size as struct unr to optimize memory management.
105 TAILQ_ENTRY(unr) list;
110 /* Number of bits in the bitmap */
111 #define NBITS (sizeof(struct unr) * 8)
113 /* Header element for a unr number space. */
116 TAILQ_HEAD(unrhd,unr) head;
117 u_int low; /* Lowest item */
118 u_int high; /* Highest item */
119 u_int busy; /* Count of allocated items */
120 u_int alloc; /* Count of memory allocations */
124 #if defined(DIAGNOSTIC) || !defined(_KERNEL)
126 * Consistency check function.
128 * Checks the internal consistency as well as we can.
130 * Called at all boundaries of this API.
133 check_unrhdr(struct unrhdr *uh, int line)
140 TAILQ_FOREACH(up, &uh->head, list) {
142 if (up->ptr != uh && up->ptr != NULL) {
145 for (x = 0; x < NBITS; x++)
146 if (bit_test((bitstr_t *)up->ptr, x))
148 KASSERT (w == up->len,
149 ("UNR inconsistency: bits %u found %u\n",
155 KASSERT (y == uh->busy,
156 ("UNR inconsistency: items %u found %u (line %d)\n",
158 KASSERT (z == uh->alloc,
159 ("UNR inconsistency: chunks %u found %u (line %d)\n",
160 uh->alloc, z, line));
166 check_unrhdr(struct unrhdr *uh, int line)
175 * Userland memory management. Just use calloc and keep track of how
176 * many elements we have allocated for check_unrhdr().
179 static __inline void *
180 new_unr(struct unrhdr *uh)
183 return (Malloc(sizeof (struct unr)));
188 delete_unr(struct unrhdr *uh, void *ptr)
195 * Allocate a new unrheader set.
197 * Highest and lowest valid values given as paramters.
201 new_unrhdr(u_int low, u_int high)
207 ("UNR: use error: new_unrhdr(%u, %u)", low, high));
208 uh = Malloc(sizeof *uh);
209 TAILQ_INIT(&uh->head);
213 up->len = 1 + (high - low);
215 TAILQ_INSERT_HEAD(&uh->head, up, list);
216 check_unrhdr(uh, __LINE__);
221 delete_unrhdr(struct unrhdr *uh)
224 KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy));
226 /* We should have a single un only */
227 delete_unr(uh, TAILQ_FIRST(&uh->head));
228 KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr"));
233 * See if a given unr should be collapsed with a neighbor
236 collapse_unr(struct unrhdr *uh, struct unr *up)
240 upp = TAILQ_PREV(up, unrhd, list);
241 if (upp != NULL && up->ptr == upp->ptr) {
243 TAILQ_REMOVE(&uh->head, upp, list);
246 upp = TAILQ_NEXT(up, list);
247 if (upp != NULL && up->ptr == upp->ptr) {
249 TAILQ_REMOVE(&uh->head, upp, list);
255 * Allocate a free unr.
258 alloc_unr(struct unrhdr *uh)
260 struct unr *up, *upp;
264 check_unrhdr(uh, __LINE__);
267 * We can always allocate from one of the first two unrs on the list.
268 * The first one is likely an allocated run, but the second has to
269 * be a free run or a bitmap.
271 up = TAILQ_FIRST(&uh->head);
272 KASSERT(up != NULL, ("UNR empty list"));
275 up = TAILQ_NEXT(up, list);
277 KASSERT(up != NULL, ("UNR Ran out of numbers")); /* XXX */
278 KASSERT(up->ptr != uh, ("UNR second element allocated"));
280 if (up->ptr != NULL) {
282 KASSERT(up->len < NBITS, ("UNR bitmap confusion"));
283 bit_ffc((bitstr_t *)up->ptr, NBITS, &y);
284 KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap."));
285 bit_set((bitstr_t *)up->ptr, y);
288 if (up->len == NBITS) {
289 /* The unr is all allocated, drop bitmap */
290 delete_unr(uh, up->ptr);
292 collapse_unr(uh, up);
294 check_unrhdr(uh, __LINE__);
299 /* Run of one free item, grab it */
302 collapse_unr(uh, up);
303 check_unrhdr(uh, __LINE__);
308 * Slice first item into an preceeding allocated run, even if we
309 * have to create it. Because allocation is always lowest free
310 * number first, we know the preceeding element (if any) to be
313 upp = TAILQ_PREV(up, unrhd, list);
318 TAILQ_INSERT_BEFORE(up, upp, list);
320 KASSERT(upp->ptr == uh, ("UNR list corruption"));
324 check_unrhdr(uh, __LINE__);
331 * If we can save unrs by using a bitmap, do so.
334 free_unr(struct unrhdr *uh, u_int item)
336 struct unr *up, *upp, *upn, *ul;
337 u_int x, l, xl, n, pl;
339 KASSERT(item >= uh->low && item <= uh->high,
340 ("UNR: free_unr(%u) out of range [%u...%u]",
341 item, uh->low, uh->high));
342 check_unrhdr(uh, __LINE__);
345 /* Find the start of the potential bitmap */
346 l = item - item % NBITS;
348 TAILQ_FOREACH(up, &uh->head, list) {
350 /* Keep track of which unr we'll split if we do */
356 /* Handle bitmap items */
357 if (up->ptr != NULL && up->ptr != uh) {
358 if (x + NBITS <= item) { /* not yet */
362 KASSERT(bit_test((bitstr_t *)up->ptr, item - x) != 0,
363 ("UNR: Freeing free item %d (%d) (bitmap)\n",
365 bit_clear((bitstr_t *)up->ptr, item - x);
369 * XXX: up->len == 1 could possibly be collapsed to
370 * XXX: neighboring runs.
374 /* We have freed all items in bitmap, drop it */
375 delete_unr(uh, up->ptr);
378 collapse_unr(uh, up);
379 check_unrhdr(uh, __LINE__);
383 /* Run length unr's */
385 if (x + up->len <= item) { /* not yet */
390 /* We now have our run length unr */
391 KASSERT(up->ptr == uh,
392 ("UNR Freeing free item %d (run))\n", item));
394 /* Just this one left, reap it */
398 collapse_unr(uh, up);
399 check_unrhdr(uh, __LINE__);
403 /* Check if we can shift the item to the previous run */
404 upp = TAILQ_PREV(up, unrhd, list);
405 if (item == x && upp != NULL && upp->ptr == NULL) {
409 check_unrhdr(uh, __LINE__);
413 /* Check if we can shift the item to the next run */
414 upn = TAILQ_NEXT(up, list);
415 if (item == x + up->len - 1 &&
416 upn != NULL && upn->ptr == NULL) {
420 check_unrhdr(uh, __LINE__);
424 /* Split off the tail end, if any. */
425 pl = up->len - (1 + (item - x));
430 TAILQ_INSERT_AFTER(&uh->head, up, upp, list);
434 /* We are done splitting */
442 TAILQ_INSERT_AFTER(&uh->head, up, upp, list);
443 /* Adjust current unr */
448 check_unrhdr(uh, __LINE__);
450 /* Our ul marker element may have shifted one later */
451 if (ul->len + xl <= l) {
453 ul = TAILQ_NEXT(ul, list);
455 KASSERT(ul != NULL, ("UNR lost bitmap pointer"));
457 /* Count unrs entirely inside potential bitmap */
462 up != NULL && pl + up->len <= item;
463 up = TAILQ_NEXT(up, list)) {
469 /* If less than three, a bitmap does not pay off */
473 /* Allocate bitmap */
475 upp->ptr = new_unr(uh);
477 /* Insert bitmap after ul element */
478 TAILQ_INSERT_AFTER(&uh->head, ul, upp, list);
480 /* Slice off the tail from the ul element */
481 pl = ul->len - (l - xl);
482 if (ul->ptr != NULL) {
483 bit_nset(upp->ptr, 0, pl - 1);
488 /* Ditch ul if it got reduced to zero size */
490 TAILQ_REMOVE(&uh->head, ul, list);
494 /* Soak up run length unrs until we have absorbed NBITS */
495 while (pl != NBITS) {
497 /* Grab first one in line */
498 upn = TAILQ_NEXT(upp, list);
500 /* We may not have a multiple of NBITS totally */
504 /* Run may extend past our new bitmap */
509 if (upn->ptr != NULL) {
510 bit_nset(upp->ptr, pl, pl + n - 1);
516 /* We did not absorb the entire run */
520 TAILQ_REMOVE(&uh->head, upn, list);
523 check_unrhdr(uh, __LINE__);
526 KASSERT(0 != 1, ("UNR: Fell off the end in free_unr()"));
529 #ifndef _KERNEL /* USERLAND test driver */
532 * Simple stochastic test driver for the above functions
536 print_unr(struct unrhdr *uh, struct unr *up)
540 printf(" %p len = %5u ", up, up->len);
543 else if (up->ptr == uh)
547 for (x = 0; x < NBITS; x++) {
548 if (bit_test((bitstr_t *)up->ptr, x))
558 print_unrhdr(struct unrhdr *uh)
563 printf("%p low = %u high = %u busy %u\n",
564 uh, uh->low, uh->high, uh->busy);
566 TAILQ_FOREACH(up, &uh->head, list) {
567 printf(" from = %5u", x);
569 if (up->ptr == NULL || up->ptr == uh)
576 /* Number of unrs to test */
580 main(int argc __unused, const char **argv __unused)
586 uh = new_unrhdr(0, NN - 1);
588 memset(a, 0, sizeof a);
590 fprintf(stderr, "sizeof(struct unr) %d\n", sizeof (struct unr));
591 fprintf(stderr, "sizeof(struct unrhdr) %d\n", sizeof (struct unrhdr));
593 for (m = 0; m < NN; m++) {
604 if (1) /* XXX: change this for detailed debug printout */
606 check_unrhdr(uh, __LINE__);
608 for (i = 0; i < NN; i++)