]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_unit.c
Merge llvm trunk r321017 to contrib/llvm.
[FreeBSD/FreeBSD.git] / sys / kern / subr_unit.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004 Poul-Henning Kamp
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  *
30  *
31  * Unit number allocation functions.
32  *
33  * These functions implement a mixed run-length/bitmap management of unit
34  * number spaces in a very memory efficient manner.
35  *
36  * Allocation policy is always lowest free number first.
37  *
38  * A return value of -1 signals that no more unit numbers are available.
39  *
40  * There is no cost associated with the range of unitnumbers, so unless
41  * the resource really is finite, specify INT_MAX to new_unrhdr() and
42  * forget about checking the return value.
43  *
44  * If a mutex is not provided when the unit number space is created, a
45  * default global mutex is used.  The advantage to passing a mutex in, is
46  * that the alloc_unrl() function can be called with the mutex already
47  * held (it will not be released by alloc_unrl()).
48  *
49  * The allocation function alloc_unr{l}() never sleeps (but it may block on
50  * the mutex of course).
51  *
52  * Freeing a unit number may require allocating memory, and can therefore
53  * sleep so the free_unr() function does not come in a pre-locked variant.
54  *
55  * A userland test program is included.
56  *
57  * Memory usage is a very complex function of the exact allocation
58  * pattern, but always very compact:
59  *    * For the very typical case where a single unbroken run of unit
60  *      numbers are allocated 44 bytes are used on i386.
61  *    * For a unit number space of 1000 units and the random pattern
62  *      in the usermode test program included, the worst case usage
63  *      was 252 bytes on i386 for 500 allocated and 500 free units.
64  *    * For a unit number space of 10000 units and the random pattern
65  *      in the usermode test program included, the worst case usage
66  *      was 798 bytes on i386 for 5000 allocated and 5000 free units.
67  *    * The worst case is where every other unit number is allocated and
68  *      the rest are free.  In that case 44 + N/4 bytes are used where
69  *      N is the number of the highest unit allocated.
70  */
71
72 #include <sys/param.h>
73 #include <sys/types.h>
74 #include <sys/_unrhdr.h>
75
76 #ifdef _KERNEL
77
78 #include <sys/bitstring.h>
79 #include <sys/malloc.h>
80 #include <sys/kernel.h>
81 #include <sys/systm.h>
82 #include <sys/limits.h>
83 #include <sys/lock.h>
84 #include <sys/mutex.h>
85
86 /*
87  * In theory it would be smarter to allocate the individual blocks
88  * with the zone allocator, but at this time the expectation is that
89  * there will typically not even be enough allocations to fill a single
90  * page, so we stick with malloc for now.
91  */
92 static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation");
93
94 #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO)
95 #define Free(foo) free(foo, M_UNIT)
96
97 static struct mtx unitmtx;
98
99 MTX_SYSINIT(unit, &unitmtx, "unit# allocation", MTX_DEF);
100
101 #else /* ...USERLAND */
102
103 #include <bitstring.h>
104 #include <err.h>
105 #include <errno.h>
106 #include <getopt.h>
107 #include <stdbool.h>
108 #include <stdio.h>
109 #include <stdlib.h>
110 #include <string.h>
111
112 #define KASSERT(cond, arg) \
113         do { \
114                 if (!(cond)) { \
115                         printf arg; \
116                         abort(); \
117                 } \
118         } while (0)
119
120 static int no_alloc;
121 #define Malloc(foo) _Malloc(foo, __LINE__)
122 static void *
123 _Malloc(size_t foo, int line)
124 {
125
126         KASSERT(no_alloc == 0, ("malloc in wrong place() line %d", line));
127         return (calloc(foo, 1));
128 }
129 #define Free(foo) free(foo)
130
131 struct unrhdr;
132
133
134 struct mtx {
135         int     state;
136 } unitmtx;
137
138 static void
139 mtx_lock(struct mtx *mp)
140 {
141         KASSERT(mp->state == 0, ("mutex already locked"));
142         mp->state = 1;
143 }
144
145 static void
146 mtx_unlock(struct mtx *mp)
147 {
148         KASSERT(mp->state == 1, ("mutex not locked"));
149         mp->state = 0;
150 }
151
152 #define MA_OWNED        9
153
154 static void
155 mtx_assert(struct mtx *mp, int flag)
156 {
157         if (flag == MA_OWNED) {
158                 KASSERT(mp->state == 1, ("mtx_assert(MA_OWNED) not true"));
159         }
160 }
161
162 #define CTASSERT(foo)
163 #define WITNESS_WARN(flags, lock, fmt, ...)     (void)0
164
165 #endif /* USERLAND */
166
167 /*
168  * This is our basic building block.
169  *
170  * It can be used in three different ways depending on the value of the ptr
171  * element:
172  *     If ptr is NULL, it represents a run of free items.
173  *     If ptr points to the unrhdr it represents a run of allocated items.
174  *     Otherwise it points to a bitstring of allocated items.
175  *
176  * For runs the len field is the length of the run.
177  * For bitmaps the len field represents the number of allocated items.
178  *
179  * The bitmap is the same size as struct unr to optimize memory management.
180  */
181 struct unr {
182         TAILQ_ENTRY(unr)        list;
183         u_int                   len;
184         void                    *ptr;
185 };
186
187 struct unrb {
188         bitstr_t                map[sizeof(struct unr) / sizeof(bitstr_t)];
189 };
190
191 CTASSERT((sizeof(struct unr) % sizeof(bitstr_t)) == 0);
192
193 /* Number of bits we can store in the bitmap */
194 #define NBITS (8 * sizeof(((struct unrb*)NULL)->map))
195
196 /* Is the unrb empty in at least the first len bits? */
197 static inline bool
198 ub_empty(struct unrb *ub, int len) {
199         int first_set;
200
201         bit_ffs(ub->map, len, &first_set);
202         return (first_set == -1);
203 }
204
205 /* Is the unrb full?  That is, is the number of set elements equal to len? */
206 static inline bool
207 ub_full(struct unrb *ub, int len)
208 {
209         int first_clear;
210
211         bit_ffc(ub->map, len, &first_clear);
212         return (first_clear == -1);
213 }
214
215
216 #if defined(DIAGNOSTIC) || !defined(_KERNEL)
217 /*
218  * Consistency check function.
219  *
220  * Checks the internal consistency as well as we can.
221  *
222  * Called at all boundaries of this API.
223  */
224 static void
225 check_unrhdr(struct unrhdr *uh, int line)
226 {
227         struct unr *up;
228         struct unrb *ub;
229         int w;
230         u_int y, z;
231
232         y = uh->first;
233         z = 0;
234         TAILQ_FOREACH(up, &uh->head, list) {
235                 z++;
236                 if (up->ptr != uh && up->ptr != NULL) {
237                         ub = up->ptr;
238                         KASSERT (up->len <= NBITS,
239                             ("UNR inconsistency: len %u max %zd (line %d)\n",
240                             up->len, NBITS, line));
241                         z++;
242                         w = 0;
243                         bit_count(ub->map, 0, up->len, &w);
244                         y += w;
245                 } else if (up->ptr != NULL)
246                         y += up->len;
247         }
248         KASSERT (y == uh->busy,
249             ("UNR inconsistency: items %u found %u (line %d)\n",
250             uh->busy, y, line));
251         KASSERT (z == uh->alloc,
252             ("UNR inconsistency: chunks %u found %u (line %d)\n",
253             uh->alloc, z, line));
254 }
255
256 #else
257
258 static __inline void
259 check_unrhdr(struct unrhdr *uh __unused, int line __unused)
260 {
261
262 }
263
264 #endif
265
266
267 /*
268  * Userland memory management.  Just use calloc and keep track of how
269  * many elements we have allocated for check_unrhdr().
270  */
271
272 static __inline void *
273 new_unr(struct unrhdr *uh, void **p1, void **p2)
274 {
275         void *p;
276
277         uh->alloc++;
278         KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory"));
279         if (*p1 != NULL) {
280                 p = *p1;
281                 *p1 = NULL;
282                 return (p);
283         } else {
284                 p = *p2;
285                 *p2 = NULL;
286                 return (p);
287         }
288 }
289
290 static __inline void
291 delete_unr(struct unrhdr *uh, void *ptr)
292 {
293         struct unr *up;
294
295         uh->alloc--;
296         up = ptr;
297         TAILQ_INSERT_TAIL(&uh->ppfree, up, list);
298 }
299
300 void
301 clean_unrhdrl(struct unrhdr *uh)
302 {
303         struct unr *up;
304
305         mtx_assert(uh->mtx, MA_OWNED);
306         while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) {
307                 TAILQ_REMOVE(&uh->ppfree, up, list);
308                 mtx_unlock(uh->mtx);
309                 Free(up);
310                 mtx_lock(uh->mtx);
311         }
312
313 }
314
315 void
316 clean_unrhdr(struct unrhdr *uh)
317 {
318
319         mtx_lock(uh->mtx);
320         clean_unrhdrl(uh);
321         mtx_unlock(uh->mtx);
322 }
323
324 void
325 init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex)
326 {
327
328         KASSERT(low >= 0 && low <= high,
329             ("UNR: use error: new_unrhdr(%d, %d)", low, high));
330         if (mutex != NULL)
331                 uh->mtx = mutex;
332         else
333                 uh->mtx = &unitmtx;
334         TAILQ_INIT(&uh->head);
335         TAILQ_INIT(&uh->ppfree);
336         uh->low = low;
337         uh->high = high;
338         uh->first = 0;
339         uh->last = 1 + (high - low);
340         check_unrhdr(uh, __LINE__);
341 }
342
343 /*
344  * Allocate a new unrheader set.
345  *
346  * Highest and lowest valid values given as parameters.
347  */
348
349 struct unrhdr *
350 new_unrhdr(int low, int high, struct mtx *mutex)
351 {
352         struct unrhdr *uh;
353
354         uh = Malloc(sizeof *uh);
355         init_unrhdr(uh, low, high, mutex);
356         return (uh);
357 }
358
359 void
360 delete_unrhdr(struct unrhdr *uh)
361 {
362
363         check_unrhdr(uh, __LINE__);
364         KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy));
365         KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr"));
366         KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL,
367             ("unrhdr has postponed item for free"));
368         Free(uh);
369 }
370
371 void
372 clear_unrhdr(struct unrhdr *uh)
373 {
374         struct unr *up, *uq;
375
376         KASSERT(TAILQ_EMPTY(&uh->ppfree),
377             ("unrhdr has postponed item for free"));
378         TAILQ_FOREACH_SAFE(up, &uh->head, list, uq) {
379                 if (up->ptr != uh) {
380                         Free(up->ptr);
381                 }
382                 Free(up);
383         }
384         uh->busy = 0;
385         uh->alloc = 0;
386         init_unrhdr(uh, uh->low, uh->high, uh->mtx);
387
388         check_unrhdr(uh, __LINE__);
389 }
390
391 static __inline int
392 is_bitmap(struct unrhdr *uh, struct unr *up)
393 {
394         return (up->ptr != uh && up->ptr != NULL);
395 }
396
397 /*
398  * Look for sequence of items which can be combined into a bitmap, if
399  * multiple are present, take the one which saves most memory.
400  *
401  * Return (1) if a sequence was found to indicate that another call
402  * might be able to do more.  Return (0) if we found no suitable sequence.
403  *
404  * NB: called from alloc_unr(), no new memory allocation allowed.
405  */
406 static int
407 optimize_unr(struct unrhdr *uh)
408 {
409         struct unr *up, *uf, *us;
410         struct unrb *ub, *ubf;
411         u_int a, l, ba;
412
413         /*
414          * Look for the run of items (if any) which when collapsed into
415          * a bitmap would save most memory.
416          */
417         us = NULL;
418         ba = 0;
419         TAILQ_FOREACH(uf, &uh->head, list) {
420                 if (uf->len >= NBITS)
421                         continue;
422                 a = 1;
423                 if (is_bitmap(uh, uf))
424                         a++;
425                 l = uf->len;
426                 up = uf;
427                 while (1) {
428                         up = TAILQ_NEXT(up, list);
429                         if (up == NULL)
430                                 break;
431                         if ((up->len + l) > NBITS)
432                                 break;
433                         a++;
434                         if (is_bitmap(uh, up))
435                                 a++;
436                         l += up->len;
437                 }
438                 if (a > ba) {
439                         ba = a;
440                         us = uf;
441                 }
442         }
443         if (ba < 3)
444                 return (0);
445
446         /*
447          * If the first element is not a bitmap, make it one.
448          * Trying to do so without allocating more memory complicates things
449          * a bit
450          */
451         if (!is_bitmap(uh, us)) {
452                 uf = TAILQ_NEXT(us, list);
453                 TAILQ_REMOVE(&uh->head, us, list);
454                 a = us->len;
455                 l = us->ptr == uh ? 1 : 0;
456                 ub = (void *)us;
457                 bit_nclear(ub->map, 0, NBITS - 1);
458                 if (l)
459                         bit_nset(ub->map, 0, a);
460                 if (!is_bitmap(uh, uf)) {
461                         if (uf->ptr == NULL)
462                                 bit_nclear(ub->map, a, a + uf->len - 1);
463                         else
464                                 bit_nset(ub->map, a, a + uf->len - 1);
465                         uf->ptr = ub;
466                         uf->len += a;
467                         us = uf;
468                 } else {
469                         ubf = uf->ptr;
470                         for (l = 0; l < uf->len; l++, a++) {
471                                 if (bit_test(ubf->map, l))
472                                         bit_set(ub->map, a);
473                                 else
474                                         bit_clear(ub->map, a);
475                         }
476                         uf->len = a;
477                         delete_unr(uh, uf->ptr);
478                         uf->ptr = ub;
479                         us = uf;
480                 }
481         }
482         ub = us->ptr;
483         while (1) {
484                 uf = TAILQ_NEXT(us, list);
485                 if (uf == NULL)
486                         return (1);
487                 if (uf->len + us->len > NBITS)
488                         return (1);
489                 if (uf->ptr == NULL) {
490                         bit_nclear(ub->map, us->len, us->len + uf->len - 1);
491                         us->len += uf->len;
492                         TAILQ_REMOVE(&uh->head, uf, list);
493                         delete_unr(uh, uf);
494                 } else if (uf->ptr == uh) {
495                         bit_nset(ub->map, us->len, us->len + uf->len - 1);
496                         us->len += uf->len;
497                         TAILQ_REMOVE(&uh->head, uf, list);
498                         delete_unr(uh, uf);
499                 } else {
500                         ubf = uf->ptr;
501                         for (l = 0; l < uf->len; l++, us->len++) {
502                                 if (bit_test(ubf->map, l))
503                                         bit_set(ub->map, us->len);
504                                 else
505                                         bit_clear(ub->map, us->len);
506                         }
507                         TAILQ_REMOVE(&uh->head, uf, list);
508                         delete_unr(uh, ubf);
509                         delete_unr(uh, uf);
510                 }
511         }
512 }
513
514 /*
515  * See if a given unr should be collapsed with a neighbor.
516  *
517  * NB: called from alloc_unr(), no new memory allocation allowed.
518  */
519 static void
520 collapse_unr(struct unrhdr *uh, struct unr *up)
521 {
522         struct unr *upp;
523         struct unrb *ub;
524
525         /* If bitmap is all set or clear, change it to runlength */
526         if (is_bitmap(uh, up)) {
527                 ub = up->ptr;
528                 if (ub_full(ub, up->len)) {
529                         delete_unr(uh, up->ptr);
530                         up->ptr = uh;
531                 } else if (ub_empty(ub, up->len)) {
532                         delete_unr(uh, up->ptr);
533                         up->ptr = NULL;
534                 }
535         }
536
537         /* If nothing left in runlength, delete it */
538         if (up->len == 0) {
539                 upp = TAILQ_PREV(up, unrhd, list);
540                 if (upp == NULL)
541                         upp = TAILQ_NEXT(up, list);
542                 TAILQ_REMOVE(&uh->head, up, list);
543                 delete_unr(uh, up);
544                 up = upp;
545         }
546
547         /* If we have "hot-spot" still, merge with neighbor if possible */
548         if (up != NULL) {
549                 upp = TAILQ_PREV(up, unrhd, list);
550                 if (upp != NULL && up->ptr == upp->ptr) {
551                         up->len += upp->len;
552                         TAILQ_REMOVE(&uh->head, upp, list);
553                         delete_unr(uh, upp);
554                         }
555                 upp = TAILQ_NEXT(up, list);
556                 if (upp != NULL && up->ptr == upp->ptr) {
557                         up->len += upp->len;
558                         TAILQ_REMOVE(&uh->head, upp, list);
559                         delete_unr(uh, upp);
560                 }
561         }
562
563         /* Merge into ->first if possible */
564         upp = TAILQ_FIRST(&uh->head);
565         if (upp != NULL && upp->ptr == uh) {
566                 uh->first += upp->len;
567                 TAILQ_REMOVE(&uh->head, upp, list);
568                 delete_unr(uh, upp);
569                 if (up == upp)
570                         up = NULL;
571         }
572
573         /* Merge into ->last if possible */
574         upp = TAILQ_LAST(&uh->head, unrhd);
575         if (upp != NULL && upp->ptr == NULL) {
576                 uh->last += upp->len;
577                 TAILQ_REMOVE(&uh->head, upp, list);
578                 delete_unr(uh, upp);
579                 if (up == upp)
580                         up = NULL;
581         }
582
583         /* Try to make bitmaps */
584         while (optimize_unr(uh))
585                 continue;
586 }
587
588 /*
589  * Allocate a free unr.
590  */
591 int
592 alloc_unrl(struct unrhdr *uh)
593 {
594         struct unr *up;
595         struct unrb *ub;
596         u_int x;
597         int y;
598
599         mtx_assert(uh->mtx, MA_OWNED);
600         check_unrhdr(uh, __LINE__);
601         x = uh->low + uh->first;
602
603         up = TAILQ_FIRST(&uh->head);
604
605         /*
606          * If we have an ideal split, just adjust the first+last
607          */
608         if (up == NULL && uh->last > 0) {
609                 uh->first++;
610                 uh->last--;
611                 uh->busy++;
612                 return (x);
613         }
614
615         /*
616          * We can always allocate from the first list element, so if we have
617          * nothing on the list, we must have run out of unit numbers.
618          */
619         if (up == NULL)
620                 return (-1);
621
622         KASSERT(up->ptr != uh, ("UNR first element is allocated"));
623
624         if (up->ptr == NULL) {  /* free run */
625                 uh->first++;
626                 up->len--;
627         } else {                /* bitmap */
628                 ub = up->ptr;
629                 bit_ffc(ub->map, up->len, &y);
630                 KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap."));
631                 bit_set(ub->map, y);
632                 x += y;
633         }
634         uh->busy++;
635         collapse_unr(uh, up);
636         return (x);
637 }
638
639 int
640 alloc_unr(struct unrhdr *uh)
641 {
642         int i;
643
644         mtx_lock(uh->mtx);
645         i = alloc_unrl(uh);
646         clean_unrhdrl(uh);
647         mtx_unlock(uh->mtx);
648         return (i);
649 }
650
651 static int
652 alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2)
653 {
654         struct unr *up, *upn;
655         struct unrb *ub;
656         u_int i, last, tl;
657
658         mtx_assert(uh->mtx, MA_OWNED);
659
660         if (item < uh->low + uh->first || item > uh->high)
661                 return (-1);
662
663         up = TAILQ_FIRST(&uh->head);
664         /* Ideal split. */
665         if (up == NULL && item - uh->low == uh->first) {
666                 uh->first++;
667                 uh->last--;
668                 uh->busy++;
669                 check_unrhdr(uh, __LINE__);
670                 return (item);
671         }
672
673         i = item - uh->low - uh->first;
674
675         if (up == NULL) {
676                 up = new_unr(uh, p1, p2);
677                 up->ptr = NULL;
678                 up->len = i;
679                 TAILQ_INSERT_TAIL(&uh->head, up, list);
680                 up = new_unr(uh, p1, p2);
681                 up->ptr = uh;
682                 up->len = 1;
683                 TAILQ_INSERT_TAIL(&uh->head, up, list);
684                 uh->last = uh->high - uh->low - i;
685                 uh->busy++;
686                 check_unrhdr(uh, __LINE__);
687                 return (item);
688         } else {
689                 /* Find the item which contains the unit we want to allocate. */
690                 TAILQ_FOREACH(up, &uh->head, list) {
691                         if (up->len > i)
692                                 break;
693                         i -= up->len;
694                 }
695         }
696
697         if (up == NULL) {
698                 if (i > 0) {
699                         up = new_unr(uh, p1, p2);
700                         up->ptr = NULL;
701                         up->len = i;
702                         TAILQ_INSERT_TAIL(&uh->head, up, list);
703                 }
704                 up = new_unr(uh, p1, p2);
705                 up->ptr = uh;
706                 up->len = 1;
707                 TAILQ_INSERT_TAIL(&uh->head, up, list);
708                 goto done;
709         }
710
711         if (is_bitmap(uh, up)) {
712                 ub = up->ptr;
713                 if (bit_test(ub->map, i) == 0) {
714                         bit_set(ub->map, i);
715                         goto done;
716                 } else
717                         return (-1);
718         } else if (up->ptr == uh)
719                 return (-1);
720
721         KASSERT(up->ptr == NULL,
722             ("alloc_unr_specificl: up->ptr != NULL (up=%p)", up));
723
724         /* Split off the tail end, if any. */
725         tl = up->len - (1 + i);
726         if (tl > 0) {
727                 upn = new_unr(uh, p1, p2);
728                 upn->ptr = NULL;
729                 upn->len = tl;
730                 TAILQ_INSERT_AFTER(&uh->head, up, upn, list);
731         }
732
733         /* Split off head end, if any */
734         if (i > 0) {
735                 upn = new_unr(uh, p1, p2);
736                 upn->len = i;
737                 upn->ptr = NULL;
738                 TAILQ_INSERT_BEFORE(up, upn, list);
739         }
740         up->len = 1;
741         up->ptr = uh;
742
743 done:
744         last = uh->high - uh->low - (item - uh->low);
745         if (uh->last > last)
746                 uh->last = last;
747         uh->busy++;
748         collapse_unr(uh, up);
749         check_unrhdr(uh, __LINE__);
750         return (item);
751 }
752
753 int
754 alloc_unr_specific(struct unrhdr *uh, u_int item)
755 {
756         void *p1, *p2;
757         int i;
758
759         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific");
760
761         p1 = Malloc(sizeof(struct unr));
762         p2 = Malloc(sizeof(struct unr));
763
764         mtx_lock(uh->mtx);
765         i = alloc_unr_specificl(uh, item, &p1, &p2);
766         mtx_unlock(uh->mtx);
767
768         if (p1 != NULL)
769                 Free(p1);
770         if (p2 != NULL)
771                 Free(p2);
772
773         return (i);
774 }
775
776 /*
777  * Free a unr.
778  *
779  * If we can save unrs by using a bitmap, do so.
780  */
781 static void
782 free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2)
783 {
784         struct unr *up, *upp, *upn;
785         struct unrb *ub;
786         u_int pl;
787
788         KASSERT(item >= uh->low && item <= uh->high,
789             ("UNR: free_unr(%u) out of range [%u...%u]",
790              item, uh->low, uh->high));
791         check_unrhdr(uh, __LINE__);
792         item -= uh->low;
793         upp = TAILQ_FIRST(&uh->head);
794         /*
795          * Freeing in the ideal split case
796          */
797         if (item + 1 == uh->first && upp == NULL) {
798                 uh->last++;
799                 uh->first--;
800                 uh->busy--;
801                 check_unrhdr(uh, __LINE__);
802                 return;
803         }
804         /*
805          * Freeing in the ->first section.  Create a run starting at the
806          * freed item.  The code below will subdivide it.
807          */
808         if (item < uh->first) {
809                 up = new_unr(uh, p1, p2);
810                 up->ptr = uh;
811                 up->len = uh->first - item;
812                 TAILQ_INSERT_HEAD(&uh->head, up, list);
813                 uh->first -= up->len;
814         }
815
816         item -= uh->first;
817
818         /* Find the item which contains the unit we want to free */
819         TAILQ_FOREACH(up, &uh->head, list) {
820                 if (up->len > item)
821                         break;
822                 item -= up->len;
823         }
824
825         /* Handle bitmap items */
826         if (is_bitmap(uh, up)) {
827                 ub = up->ptr;
828
829                 KASSERT(bit_test(ub->map, item) != 0,
830                     ("UNR: Freeing free item %d (bitmap)\n", item));
831                 bit_clear(ub->map, item);
832                 uh->busy--;
833                 collapse_unr(uh, up);
834                 return;
835         }
836
837         KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item));
838
839         /* Just this one left, reap it */
840         if (up->len == 1) {
841                 up->ptr = NULL;
842                 uh->busy--;
843                 collapse_unr(uh, up);
844                 return;
845         }
846
847         /* Check if we can shift the item into the previous 'free' run */
848         upp = TAILQ_PREV(up, unrhd, list);
849         if (item == 0 && upp != NULL && upp->ptr == NULL) {
850                 upp->len++;
851                 up->len--;
852                 uh->busy--;
853                 collapse_unr(uh, up);
854                 return;
855         }
856
857         /* Check if we can shift the item to the next 'free' run */
858         upn = TAILQ_NEXT(up, list);
859         if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) {
860                 upn->len++;
861                 up->len--;
862                 uh->busy--;
863                 collapse_unr(uh, up);
864                 return;
865         }
866
867         /* Split off the tail end, if any. */
868         pl = up->len - (1 + item);
869         if (pl > 0) {
870                 upp = new_unr(uh, p1, p2);
871                 upp->ptr = uh;
872                 upp->len = pl;
873                 TAILQ_INSERT_AFTER(&uh->head, up, upp, list);
874         }
875
876         /* Split off head end, if any */
877         if (item > 0) {
878                 upp = new_unr(uh, p1, p2);
879                 upp->len = item;
880                 upp->ptr = uh;
881                 TAILQ_INSERT_BEFORE(up, upp, list);
882         }
883         up->len = 1;
884         up->ptr = NULL;
885         uh->busy--;
886         collapse_unr(uh, up);
887 }
888
889 void
890 free_unr(struct unrhdr *uh, u_int item)
891 {
892         void *p1, *p2;
893
894         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "free_unr");
895         p1 = Malloc(sizeof(struct unr));
896         p2 = Malloc(sizeof(struct unr));
897         mtx_lock(uh->mtx);
898         free_unrl(uh, item, &p1, &p2);
899         clean_unrhdrl(uh);
900         mtx_unlock(uh->mtx);
901         if (p1 != NULL)
902                 Free(p1);
903         if (p2 != NULL)
904                 Free(p2);
905 }
906
907 #ifndef _KERNEL /* USERLAND test driver */
908
909 /*
910  * Simple stochastic test driver for the above functions.  The code resides
911  * here so that it can access static functions and structures.
912  */
913
914 static bool verbose;
915 #define VPRINTF(...)    {if (verbose) printf(__VA_ARGS__);}
916
917 static void
918 print_unr(struct unrhdr *uh, struct unr *up)
919 {
920         u_int x;
921         struct unrb *ub;
922
923         printf("  %p len = %5u ", up, up->len);
924         if (up->ptr == NULL)
925                 printf("free\n");
926         else if (up->ptr == uh)
927                 printf("alloc\n");
928         else {
929                 ub = up->ptr;
930                 printf("bitmap [");
931                 for (x = 0; x < up->len; x++) {
932                         if (bit_test(ub->map, x))
933                                 printf("#");
934                         else
935                                 printf(" ");
936                 }
937                 printf("]\n");
938         }
939 }
940
941 static void
942 print_unrhdr(struct unrhdr *uh)
943 {
944         struct unr *up;
945         u_int x;
946
947         printf(
948             "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n",
949             uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc);
950         x = uh->low + uh->first;
951         TAILQ_FOREACH(up, &uh->head, list) {
952                 printf("  from = %5u", x);
953                 print_unr(uh, up);
954                 if (up->ptr == NULL || up->ptr == uh)
955                         x += up->len;
956                 else
957                         x += NBITS;
958         }
959 }
960
961 static void
962 test_alloc_unr(struct unrhdr *uh, u_int i, char a[])
963 {
964         int j;
965
966         if (a[i]) {
967                 VPRINTF("F %u\n", i);
968                 free_unr(uh, i);
969                 a[i] = 0;
970         } else {
971                 no_alloc = 1;
972                 j = alloc_unr(uh);
973                 if (j != -1) {
974                         a[j] = 1;
975                         VPRINTF("A %d\n", j);
976                 }
977                 no_alloc = 0;
978         }
979 }
980
981 static void
982 test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[])
983 {
984         int j;
985
986         j = alloc_unr_specific(uh, i);
987         if (j == -1) {
988                 VPRINTF("F %u\n", i);
989                 a[i] = 0;
990                 free_unr(uh, i);
991         } else {
992                 a[i] = 1;
993                 VPRINTF("A %d\n", j);
994         }
995 }
996
997 static void
998 usage(char** argv)
999 {
1000         printf("%s [-h] [-r REPETITIONS] [-v]\n", argv[0]);
1001 }
1002
1003 int
1004 main(int argc, char **argv)
1005 {
1006         struct unrhdr *uh;
1007         char *a;
1008         long count = 10000;     /* Number of unrs to test */
1009         long reps = 1, m;
1010         int ch;
1011         u_int i, j;
1012
1013         verbose = false;
1014
1015         while ((ch = getopt(argc, argv, "hr:v")) != -1) {
1016                 switch (ch) {
1017                 case 'r':
1018                         errno = 0;
1019                         reps = strtol(optarg, NULL, 0);
1020                         if (errno == ERANGE || errno == EINVAL) {
1021                                 usage(argv);
1022                                 exit(2);
1023                         }
1024
1025                         break;
1026                 case 'v':
1027                         verbose = true;
1028                         break;
1029                 case 'h':
1030                 default:
1031                         usage(argv);
1032                         exit(2);
1033                 }
1034
1035
1036         }
1037
1038         setbuf(stdout, NULL);
1039         uh = new_unrhdr(0, count - 1, NULL);
1040         print_unrhdr(uh);
1041
1042         a = calloc(count, sizeof(char));
1043         if (a == NULL)
1044                 err(1, "calloc failed");
1045         srandomdev();
1046
1047         printf("sizeof(struct unr) %zu\n", sizeof(struct unr));
1048         printf("sizeof(struct unrb) %zu\n", sizeof(struct unrb));
1049         printf("sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr));
1050         printf("NBITS %lu\n", (unsigned long)NBITS);
1051         for (m = 0; m < count * reps; m++) {
1052                 j = random();
1053                 i = (j >> 1) % count;
1054 #if 0
1055                 if (a[i] && (j & 1))
1056                         continue;
1057 #endif
1058                 if ((random() & 1) != 0)
1059                         test_alloc_unr(uh, i, a);
1060                 else
1061                         test_alloc_unr_specific(uh, i, a);
1062
1063                 if (verbose)
1064                         print_unrhdr(uh);
1065                 check_unrhdr(uh, __LINE__);
1066         }
1067         for (i = 0; i < (u_int)count; i++) {
1068                 if (a[i]) {
1069                         if (verbose) {
1070                                 printf("C %u\n", i);
1071                                 print_unrhdr(uh);
1072                         }
1073                         free_unr(uh, i);
1074                 }
1075         }
1076         print_unrhdr(uh);
1077         delete_unrhdr(uh);
1078         free(a);
1079         return (0);
1080 }
1081 #endif