]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_unit.c
libevent: Import libevent 2.1.12
[FreeBSD/FreeBSD.git] / sys / kern / subr_unit.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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  *
29  * Unit number allocation functions.
30  *
31  * These functions implement a mixed run-length/bitmap management of unit
32  * number spaces in a very memory efficient manner.
33  *
34  * Allocation policy is always lowest free number first.
35  *
36  * A return value of -1 signals that no more unit numbers are available.
37  *
38  * There is no cost associated with the range of unitnumbers, so unless
39  * the resource really is finite, specify INT_MAX to new_unrhdr() and
40  * forget about checking the return value.
41  *
42  * If a mutex is not provided when the unit number space is created, a
43  * default global mutex is used.  The advantage to passing a mutex in, is
44  * that the alloc_unrl() function can be called with the mutex already
45  * held (it will not be released by alloc_unrl()).
46  *
47  * The allocation function alloc_unr{l}() never sleeps (but it may block on
48  * the mutex of course).
49  *
50  * Freeing a unit number may require allocating memory, and can therefore
51  * sleep so the free_unr() function does not come in a pre-locked variant.
52  *
53  * A userland test program is included.
54  *
55  * Memory usage is a very complex function of the exact allocation
56  * pattern, but always very compact:
57  *    * For the very typical case where a single unbroken run of unit
58  *      numbers are allocated 44 bytes are used on i386.
59  *    * For a unit number space of 1000 units and the random pattern
60  *      in the usermode test program included, the worst case usage
61  *      was 252 bytes on i386 for 500 allocated and 500 free units.
62  *    * For a unit number space of 10000 units and the random pattern
63  *      in the usermode test program included, the worst case usage
64  *      was 798 bytes on i386 for 5000 allocated and 5000 free units.
65  *    * The worst case is where every other unit number is allocated and
66  *      the rest are free.  In that case 44 + N/4 bytes are used where
67  *      N is the number of the highest unit allocated.
68  */
69
70 #include <sys/param.h>
71 #include <sys/types.h>
72 #include <sys/_unrhdr.h>
73
74 #ifdef _KERNEL
75
76 #include <sys/bitstring.h>
77 #include <sys/malloc.h>
78 #include <sys/kernel.h>
79 #include <sys/systm.h>
80 #include <sys/limits.h>
81 #include <sys/lock.h>
82 #include <sys/mutex.h>
83
84 /*
85  * In theory it would be smarter to allocate the individual blocks
86  * with the zone allocator, but at this time the expectation is that
87  * there will typically not even be enough allocations to fill a single
88  * page, so we stick with malloc for now.
89  */
90 static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation");
91
92 #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO)
93 #define Free(foo) free(foo, M_UNIT)
94
95 static struct mtx unitmtx;
96
97 MTX_SYSINIT(unit, &unitmtx, "unit# allocation", MTX_DEF);
98
99 #else /* ...USERLAND */
100
101 #include <bitstring.h>
102 #include <err.h>
103 #include <errno.h>
104 #include <getopt.h>
105 #include <stdbool.h>
106 #include <stdio.h>
107 #include <stdlib.h>
108 #include <string.h>
109
110 #define KASSERT(cond, arg) \
111         do { \
112                 if (!(cond)) { \
113                         printf arg; \
114                         abort(); \
115                 } \
116         } while (0)
117
118 static int no_alloc;
119 #define Malloc(foo) _Malloc(foo, __LINE__)
120 static void *
121 _Malloc(size_t foo, int line)
122 {
123
124         KASSERT(no_alloc == 0, ("malloc in wrong place() line %d", line));
125         return (calloc(foo, 1));
126 }
127 #define Free(foo) free(foo)
128
129 struct unrhdr;
130
131 #define UNR_NO_MTX      ((void *)(uintptr_t)-1)
132
133 struct mtx {
134         int     state;
135 } unitmtx;
136
137 static void
138 mtx_lock(struct mtx *mp)
139 {
140         KASSERT(mp->state == 0, ("mutex already locked"));
141         mp->state = 1;
142 }
143
144 static void
145 mtx_unlock(struct mtx *mp)
146 {
147         KASSERT(mp->state == 1, ("mutex not locked"));
148         mp->state = 0;
149 }
150
151 #define MA_OWNED        9
152
153 static void
154 mtx_assert(struct mtx *mp, int flag)
155 {
156         if (flag == MA_OWNED) {
157                 KASSERT(mp->state == 1, ("mtx_assert(MA_OWNED) not true"));
158         }
159 }
160
161 #define CTASSERT(foo)
162 #define WITNESS_WARN(flags, lock, fmt, ...)     (void)0
163
164 #endif /* USERLAND */
165
166 /*
167  * This is our basic building block.
168  *
169  * It can be used in three different ways depending on the value of the ptr
170  * element:
171  *     If ptr is NULL, it represents a run of free items.
172  *     If ptr points to the unrhdr it represents a run of allocated items.
173  *     Otherwise it points to a bitstring of allocated items.
174  *
175  * For runs the len field is the length of the run.
176  * For bitmaps the len field represents the number of allocated items.
177  *
178  * The bitmap is the same size as struct unr to optimize memory management.
179  *
180  * Two special ranges are not covered by unrs:
181  * - at the start of the allocator space, all elements in [low, low + first)
182  *   are allocated;
183  * - at the end of the allocator space, all elements in [high - last, high]
184  *   are free.
185  */
186 struct unr {
187         TAILQ_ENTRY(unr)        list;
188         u_int                   len;
189         void                    *ptr;
190 };
191
192 struct unrb {
193         bitstr_t                map[sizeof(struct unr) / sizeof(bitstr_t)];
194 };
195
196 CTASSERT((sizeof(struct unr) % sizeof(bitstr_t)) == 0);
197
198 /* Number of bits we can store in the bitmap */
199 #define NBITS (NBBY * sizeof(((struct unrb *)NULL)->map))
200
201 static inline bool
202 is_bitmap(struct unrhdr *uh, struct unr *up)
203 {
204         return (up->ptr != uh && up->ptr != NULL);
205 }
206
207 /* Is the unrb empty in at least the first len bits? */
208 static inline bool
209 ub_empty(struct unrb *ub, int len) {
210         int first_set;
211
212         bit_ffs(ub->map, len, &first_set);
213         return (first_set == -1);
214 }
215
216 /* Is the unrb full?  That is, is the number of set elements equal to len? */
217 static inline bool
218 ub_full(struct unrb *ub, int len)
219 {
220         int first_clear;
221
222         bit_ffc(ub->map, len, &first_clear);
223         return (first_clear == -1);
224 }
225
226 /*
227  * start: ipos = -1, upos = NULL;
228  * end:   ipos = -1, upos = uh
229  */
230 struct unrhdr_iter {
231         struct unrhdr *uh;
232         int ipos;
233         int upos_first_item;
234         void *upos;
235 };
236
237 void *
238 create_iter_unr(struct unrhdr *uh)
239 {
240         struct unrhdr_iter *iter;
241
242         iter = Malloc(sizeof(*iter));
243         iter->ipos = -1;
244         iter->uh = uh;
245         iter->upos = NULL;
246         iter->upos_first_item = -1;
247         return (iter);
248 }
249
250 static void
251 next_iter_unrl(struct unrhdr *uh, struct unrhdr_iter *iter)
252 {
253         struct unr *up;
254         struct unrb *ub;
255         u_int y;
256         int c;
257
258         if (iter->ipos == -1) {
259                 if (iter->upos == uh)
260                         return;
261                 y = uh->low - 1;
262                 if (uh->first == 0) {
263                         up = TAILQ_FIRST(&uh->head);
264                         if (up == NULL) {
265                                 iter->upos = uh;
266                                 return;
267                         }
268                         iter->upos = up;
269                         if (up->ptr == NULL)
270                                 iter->upos = NULL;
271                         else
272                                 iter->upos_first_item = uh->low;
273                 }
274         } else {
275                 y = iter->ipos;
276         }
277
278         up = iter->upos;
279
280         /* Special case for the compacted [low, first) run. */
281         if (up == NULL) {
282                 if (y + 1 < uh->low + uh->first) {
283                         iter->ipos = y + 1;
284                         return;
285                 }
286                 up = iter->upos = TAILQ_FIRST(&uh->head);
287                 iter->upos_first_item = uh->low + uh->first;
288         }
289
290         for (;;) {
291                 if (y + 1 < iter->upos_first_item + up->len) {
292                         if (up->ptr == uh) {
293                                 iter->ipos = y + 1;
294                                 return;
295                         } else if (is_bitmap(uh, up)) {
296                                 ub = up->ptr;
297                                 bit_ffs_at(&ub->map[0],
298                                     y + 1 - iter->upos_first_item,
299                                     up->len, &c);
300                                 if (c != -1) {
301                                         iter->ipos = iter->upos_first_item + c;
302                                         return;
303                                 }
304                         }
305                 }
306                 iter->upos_first_item += up->len;
307                 y = iter->upos_first_item - 1;
308                 up = iter->upos = TAILQ_NEXT((struct unr *)iter->upos, list);
309                 if (iter->upos == NULL) {
310                         iter->ipos = -1;
311                         iter->upos = uh;
312                         return;
313                 }
314         }
315 }
316
317 /*
318  * returns -1 on end, otherwise the next element
319  */
320 int
321 next_iter_unr(void *handle)
322 {
323         struct unrhdr *uh;
324         struct unrhdr_iter *iter;
325
326         iter = handle;
327         uh = iter->uh;
328         if (uh->mtx != NULL)
329                 mtx_lock(uh->mtx);
330         next_iter_unrl(uh, iter);
331         if (uh->mtx != NULL)
332                 mtx_unlock(uh->mtx);
333         return (iter->ipos);
334 }
335
336 void
337 free_iter_unr(void *handle)
338 {
339         Free(handle);
340 }
341
342 #if defined(DIAGNOSTIC) || !defined(_KERNEL)
343 #ifndef __diagused
344 #define __diagused
345 #endif
346
347 /*
348  * Consistency check function.
349  *
350  * Checks the internal consistency as well as we can.
351  *
352  * Called at all boundaries of this API.
353  */
354 static void
355 check_unrhdr(struct unrhdr *uh, int line)
356 {
357         struct unr *up;
358         struct unrb *ub;
359         int w;
360         u_int y __diagused, z __diagused;
361
362         y = uh->first;
363         z = 0;
364         TAILQ_FOREACH(up, &uh->head, list) {
365                 z++;
366                 if (is_bitmap(uh, up)) {
367                         ub = up->ptr;
368                         KASSERT (up->len <= NBITS,
369                             ("UNR inconsistency: len %u max %zd (line %d)\n",
370                             up->len, NBITS, line));
371                         z++;
372                         w = 0;
373                         bit_count(ub->map, 0, up->len, &w);
374                         y += w;
375                 } else if (up->ptr != NULL)
376                         y += up->len;
377         }
378         KASSERT (y == uh->busy,
379             ("UNR inconsistency: items %u found %u (line %d)\n",
380             uh->busy, y, line));
381         KASSERT (z == uh->alloc,
382             ("UNR inconsistency: chunks %u found %u (line %d)\n",
383             uh->alloc, z, line));
384 }
385
386 #else
387
388 static __inline void
389 check_unrhdr(struct unrhdr *uh __unused, int line __unused)
390 {
391
392 }
393
394 #endif
395
396 /*
397  * Userland memory management.  Just use calloc and keep track of how
398  * many elements we have allocated for check_unrhdr().
399  */
400
401 static __inline void *
402 new_unr(struct unrhdr *uh, void **p1, void **p2)
403 {
404         void *p;
405
406         uh->alloc++;
407         KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory"));
408         if (*p1 != NULL) {
409                 p = *p1;
410                 *p1 = NULL;
411                 return (p);
412         } else {
413                 p = *p2;
414                 *p2 = NULL;
415                 return (p);
416         }
417 }
418
419 static __inline void
420 delete_unr(struct unrhdr *uh, void *ptr)
421 {
422         struct unr *up;
423
424         uh->alloc--;
425         up = ptr;
426         TAILQ_INSERT_TAIL(&uh->ppfree, up, list);
427 }
428
429 void
430 clean_unrhdrl(struct unrhdr *uh)
431 {
432         struct unr *up;
433
434         if (uh->mtx != NULL)
435                 mtx_assert(uh->mtx, MA_OWNED);
436         while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) {
437                 TAILQ_REMOVE(&uh->ppfree, up, list);
438                 if (uh->mtx != NULL)
439                         mtx_unlock(uh->mtx);
440                 Free(up);
441                 if (uh->mtx != NULL)
442                         mtx_lock(uh->mtx);
443         }
444
445 }
446
447 void
448 clean_unrhdr(struct unrhdr *uh)
449 {
450
451         if (uh->mtx != NULL)
452                 mtx_lock(uh->mtx);
453         clean_unrhdrl(uh);
454         if (uh->mtx != NULL)
455                 mtx_unlock(uh->mtx);
456 }
457
458 void
459 init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex)
460 {
461
462         KASSERT(low >= 0 && low <= high,
463             ("UNR: use error: new_unrhdr(%d, %d)", low, high));
464         if (mutex == UNR_NO_MTX)
465                 uh->mtx = NULL;
466         else if (mutex != NULL)
467                 uh->mtx = mutex;
468         else
469                 uh->mtx = &unitmtx;
470         TAILQ_INIT(&uh->head);
471         TAILQ_INIT(&uh->ppfree);
472         uh->low = low;
473         uh->high = high;
474         uh->first = 0;
475         uh->last = 1 + (high - low);
476         uh->busy = 0;
477         uh->alloc = 0;
478         check_unrhdr(uh, __LINE__);
479 }
480
481 /*
482  * Allocate a new unrheader set.
483  *
484  * Highest and lowest valid values given as parameters.
485  */
486
487 struct unrhdr *
488 new_unrhdr(int low, int high, struct mtx *mutex)
489 {
490         struct unrhdr *uh;
491
492         uh = Malloc(sizeof *uh);
493         init_unrhdr(uh, low, high, mutex);
494         return (uh);
495 }
496
497 void
498 delete_unrhdr(struct unrhdr *uh)
499 {
500
501         check_unrhdr(uh, __LINE__);
502         KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy));
503         KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr"));
504         KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL,
505             ("unrhdr has postponed item for free"));
506         Free(uh);
507 }
508
509 void
510 clear_unrhdr(struct unrhdr *uh)
511 {
512         struct unr *up, *uq;
513
514         KASSERT(TAILQ_EMPTY(&uh->ppfree),
515             ("unrhdr has postponed item for free"));
516         TAILQ_FOREACH_SAFE(up, &uh->head, list, uq) {
517                 if (up->ptr != uh) {
518                         Free(up->ptr);
519                 }
520                 Free(up);
521         }
522         uh->busy = 0;
523         uh->alloc = 0;
524         init_unrhdr(uh, uh->low, uh->high, uh->mtx);
525
526         check_unrhdr(uh, __LINE__);
527 }
528
529 /*
530  * Look for sequence of items which can be combined into a bitmap, if
531  * multiple are present, take the one which saves most memory.
532  *
533  * Return (1) if a sequence was found to indicate that another call
534  * might be able to do more.  Return (0) if we found no suitable sequence.
535  *
536  * NB: called from alloc_unr(), no new memory allocation allowed.
537  */
538 static int
539 optimize_unr(struct unrhdr *uh)
540 {
541         struct unr *up, *uf, *us;
542         struct unrb *ub, *ubf;
543         u_int a, l, ba;
544
545         /*
546          * Look for the run of items (if any) which when collapsed into
547          * a bitmap would save most memory.
548          */
549         us = NULL;
550         ba = 0;
551         TAILQ_FOREACH(uf, &uh->head, list) {
552                 if (uf->len >= NBITS)
553                         continue;
554                 a = 1;
555                 if (is_bitmap(uh, uf))
556                         a++;
557                 l = uf->len;
558                 up = uf;
559                 while (1) {
560                         up = TAILQ_NEXT(up, list);
561                         if (up == NULL)
562                                 break;
563                         if ((up->len + l) > NBITS)
564                                 break;
565                         a++;
566                         if (is_bitmap(uh, up))
567                                 a++;
568                         l += up->len;
569                 }
570                 if (a > ba) {
571                         ba = a;
572                         us = uf;
573                 }
574         }
575         if (ba < 3)
576                 return (0);
577
578         /*
579          * If the first element is not a bitmap, make it one.
580          * Trying to do so without allocating more memory complicates things
581          * a bit
582          */
583         if (!is_bitmap(uh, us)) {
584                 uf = TAILQ_NEXT(us, list);
585                 TAILQ_REMOVE(&uh->head, us, list);
586                 a = us->len;
587                 l = us->ptr == uh ? 1 : 0;
588                 ub = (void *)us;
589                 bit_nclear(ub->map, 0, NBITS - 1);
590                 if (l)
591                         bit_nset(ub->map, 0, a);
592                 if (!is_bitmap(uh, uf)) {
593                         if (uf->ptr == NULL)
594                                 bit_nclear(ub->map, a, a + uf->len - 1);
595                         else
596                                 bit_nset(ub->map, a, a + uf->len - 1);
597                         uf->ptr = ub;
598                         uf->len += a;
599                         us = uf;
600                 } else {
601                         ubf = uf->ptr;
602                         for (l = 0; l < uf->len; l++, a++) {
603                                 if (bit_test(ubf->map, l))
604                                         bit_set(ub->map, a);
605                                 else
606                                         bit_clear(ub->map, a);
607                         }
608                         uf->len = a;
609                         delete_unr(uh, uf->ptr);
610                         uf->ptr = ub;
611                         us = uf;
612                 }
613         }
614         ub = us->ptr;
615         while (1) {
616                 uf = TAILQ_NEXT(us, list);
617                 if (uf == NULL)
618                         return (1);
619                 if (uf->len + us->len > NBITS)
620                         return (1);
621                 if (uf->ptr == NULL) {
622                         bit_nclear(ub->map, us->len, us->len + uf->len - 1);
623                         us->len += uf->len;
624                         TAILQ_REMOVE(&uh->head, uf, list);
625                         delete_unr(uh, uf);
626                 } else if (uf->ptr == uh) {
627                         bit_nset(ub->map, us->len, us->len + uf->len - 1);
628                         us->len += uf->len;
629                         TAILQ_REMOVE(&uh->head, uf, list);
630                         delete_unr(uh, uf);
631                 } else {
632                         ubf = uf->ptr;
633                         for (l = 0; l < uf->len; l++, us->len++) {
634                                 if (bit_test(ubf->map, l))
635                                         bit_set(ub->map, us->len);
636                                 else
637                                         bit_clear(ub->map, us->len);
638                         }
639                         TAILQ_REMOVE(&uh->head, uf, list);
640                         delete_unr(uh, ubf);
641                         delete_unr(uh, uf);
642                 }
643         }
644 }
645
646 /*
647  * See if a given unr should be collapsed with a neighbor.
648  *
649  * NB: called from alloc_unr(), no new memory allocation allowed.
650  */
651 static void
652 collapse_unr(struct unrhdr *uh, struct unr *up)
653 {
654         struct unr *upp;
655         struct unrb *ub;
656
657         /* If bitmap is all set or clear, change it to runlength */
658         if (is_bitmap(uh, up)) {
659                 ub = up->ptr;
660                 if (ub_full(ub, up->len)) {
661                         delete_unr(uh, up->ptr);
662                         up->ptr = uh;
663                 } else if (ub_empty(ub, up->len)) {
664                         delete_unr(uh, up->ptr);
665                         up->ptr = NULL;
666                 }
667         }
668
669         /* If nothing left in runlength, delete it */
670         if (up->len == 0) {
671                 upp = TAILQ_PREV(up, unrhd, list);
672                 if (upp == NULL)
673                         upp = TAILQ_NEXT(up, list);
674                 TAILQ_REMOVE(&uh->head, up, list);
675                 delete_unr(uh, up);
676                 up = upp;
677         }
678
679         /* If we have "hot-spot" still, merge with neighbor if possible */
680         if (up != NULL) {
681                 upp = TAILQ_PREV(up, unrhd, list);
682                 if (upp != NULL && up->ptr == upp->ptr) {
683                         up->len += upp->len;
684                         TAILQ_REMOVE(&uh->head, upp, list);
685                         delete_unr(uh, upp);
686                         }
687                 upp = TAILQ_NEXT(up, list);
688                 if (upp != NULL && up->ptr == upp->ptr) {
689                         up->len += upp->len;
690                         TAILQ_REMOVE(&uh->head, upp, list);
691                         delete_unr(uh, upp);
692                 }
693         }
694
695         /* Merge into ->first if possible */
696         upp = TAILQ_FIRST(&uh->head);
697         if (upp != NULL && upp->ptr == uh) {
698                 uh->first += upp->len;
699                 TAILQ_REMOVE(&uh->head, upp, list);
700                 delete_unr(uh, upp);
701                 if (up == upp)
702                         up = NULL;
703         }
704
705         /* Merge into ->last if possible */
706         upp = TAILQ_LAST(&uh->head, unrhd);
707         if (upp != NULL && upp->ptr == NULL) {
708                 uh->last += upp->len;
709                 TAILQ_REMOVE(&uh->head, upp, list);
710                 delete_unr(uh, upp);
711                 if (up == upp)
712                         up = NULL;
713         }
714
715         /* Try to make bitmaps */
716         while (optimize_unr(uh))
717                 continue;
718 }
719
720 /*
721  * Allocate a free unr.
722  */
723 int
724 alloc_unrl(struct unrhdr *uh)
725 {
726         struct unr *up;
727         struct unrb *ub;
728         u_int x;
729         int y;
730
731         if (uh->mtx != NULL)
732                 mtx_assert(uh->mtx, MA_OWNED);
733         check_unrhdr(uh, __LINE__);
734         x = uh->low + uh->first;
735
736         up = TAILQ_FIRST(&uh->head);
737
738         /*
739          * If we have an ideal split, just adjust the first+last
740          */
741         if (up == NULL && uh->last > 0) {
742                 uh->first++;
743                 uh->last--;
744                 uh->busy++;
745                 return (x);
746         }
747
748         /*
749          * We can always allocate from the first list element, so if we have
750          * nothing on the list, we must have run out of unit numbers.
751          */
752         if (up == NULL)
753                 return (-1);
754
755         KASSERT(up->ptr != uh, ("UNR first element is allocated"));
756
757         if (up->ptr == NULL) {  /* free run */
758                 uh->first++;
759                 up->len--;
760         } else {                /* bitmap */
761                 ub = up->ptr;
762                 bit_ffc(ub->map, up->len, &y);
763                 KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap."));
764                 bit_set(ub->map, y);
765                 x += y;
766         }
767         uh->busy++;
768         collapse_unr(uh, up);
769         return (x);
770 }
771
772 int
773 alloc_unr(struct unrhdr *uh)
774 {
775         int i;
776
777         if (uh->mtx != NULL)
778                 mtx_lock(uh->mtx);
779         i = alloc_unrl(uh);
780         clean_unrhdrl(uh);
781         if (uh->mtx != NULL)
782                 mtx_unlock(uh->mtx);
783         return (i);
784 }
785
786 static int
787 alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2)
788 {
789         struct unr *up, *upn;
790         struct unrb *ub;
791         u_int i, last, tl;
792
793         if (uh->mtx != NULL)
794                 mtx_assert(uh->mtx, MA_OWNED);
795
796         if (item < uh->low + uh->first || item > uh->high)
797                 return (-1);
798
799         up = TAILQ_FIRST(&uh->head);
800         /* Ideal split. */
801         if (up == NULL && item - uh->low == uh->first) {
802                 uh->first++;
803                 uh->last--;
804                 uh->busy++;
805                 check_unrhdr(uh, __LINE__);
806                 return (item);
807         }
808
809         i = item - uh->low - uh->first;
810
811         if (up == NULL) {
812                 up = new_unr(uh, p1, p2);
813                 up->ptr = NULL;
814                 up->len = i;
815                 TAILQ_INSERT_TAIL(&uh->head, up, list);
816                 up = new_unr(uh, p1, p2);
817                 up->ptr = uh;
818                 up->len = 1;
819                 TAILQ_INSERT_TAIL(&uh->head, up, list);
820                 uh->last = uh->high - uh->low - i;
821                 uh->busy++;
822                 check_unrhdr(uh, __LINE__);
823                 return (item);
824         } else {
825                 /* Find the item which contains the unit we want to allocate. */
826                 TAILQ_FOREACH(up, &uh->head, list) {
827                         if (up->len > i)
828                                 break;
829                         i -= up->len;
830                 }
831         }
832
833         if (up == NULL) {
834                 if (i > 0) {
835                         up = new_unr(uh, p1, p2);
836                         up->ptr = NULL;
837                         up->len = i;
838                         TAILQ_INSERT_TAIL(&uh->head, up, list);
839                 }
840                 up = new_unr(uh, p1, p2);
841                 up->ptr = uh;
842                 up->len = 1;
843                 TAILQ_INSERT_TAIL(&uh->head, up, list);
844                 goto done;
845         }
846
847         if (is_bitmap(uh, up)) {
848                 ub = up->ptr;
849                 if (bit_test(ub->map, i) == 0) {
850                         bit_set(ub->map, i);
851                         goto done;
852                 } else
853                         return (-1);
854         } else if (up->ptr == uh)
855                 return (-1);
856
857         KASSERT(up->ptr == NULL,
858             ("alloc_unr_specificl: up->ptr != NULL (up=%p)", up));
859
860         /* Split off the tail end, if any. */
861         tl = up->len - (1 + i);
862         if (tl > 0) {
863                 upn = new_unr(uh, p1, p2);
864                 upn->ptr = NULL;
865                 upn->len = tl;
866                 TAILQ_INSERT_AFTER(&uh->head, up, upn, list);
867         }
868
869         /* Split off head end, if any */
870         if (i > 0) {
871                 upn = new_unr(uh, p1, p2);
872                 upn->len = i;
873                 upn->ptr = NULL;
874                 TAILQ_INSERT_BEFORE(up, upn, list);
875         }
876         up->len = 1;
877         up->ptr = uh;
878
879 done:
880         last = uh->high - uh->low - (item - uh->low);
881         if (uh->last > last)
882                 uh->last = last;
883         uh->busy++;
884         collapse_unr(uh, up);
885         check_unrhdr(uh, __LINE__);
886         return (item);
887 }
888
889 int
890 alloc_unr_specific(struct unrhdr *uh, u_int item)
891 {
892         void *p1, *p2;
893         int i;
894
895         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific");
896
897         p1 = Malloc(sizeof(struct unr));
898         p2 = Malloc(sizeof(struct unr));
899
900         if (uh->mtx != NULL)
901                 mtx_lock(uh->mtx);
902         i = alloc_unr_specificl(uh, item, &p1, &p2);
903         if (uh->mtx != NULL)
904                 mtx_unlock(uh->mtx);
905
906         if (p1 != NULL)
907                 Free(p1);
908         if (p2 != NULL)
909                 Free(p2);
910
911         return (i);
912 }
913
914 /*
915  * Free a unr.
916  *
917  * If we can save unrs by using a bitmap, do so.
918  */
919 static void
920 free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2)
921 {
922         struct unr *up, *upp, *upn;
923         struct unrb *ub;
924         u_int pl;
925
926         KASSERT(item >= uh->low && item <= uh->high,
927             ("UNR: free_unr(%u) out of range [%u...%u]",
928              item, uh->low, uh->high));
929         check_unrhdr(uh, __LINE__);
930         item -= uh->low;
931         upp = TAILQ_FIRST(&uh->head);
932         /*
933          * Freeing in the ideal split case
934          */
935         if (item + 1 == uh->first && upp == NULL) {
936                 uh->last++;
937                 uh->first--;
938                 uh->busy--;
939                 check_unrhdr(uh, __LINE__);
940                 return;
941         }
942         /*
943          * Freeing in the ->first section.  Create a run starting at the
944          * freed item.  The code below will subdivide it.
945          */
946         if (item < uh->first) {
947                 up = new_unr(uh, p1, p2);
948                 up->ptr = uh;
949                 up->len = uh->first - item;
950                 TAILQ_INSERT_HEAD(&uh->head, up, list);
951                 uh->first -= up->len;
952         }
953
954         item -= uh->first;
955
956         /* Find the item which contains the unit we want to free */
957         TAILQ_FOREACH(up, &uh->head, list) {
958                 if (up->len > item)
959                         break;
960                 item -= up->len;
961         }
962
963         /* Handle bitmap items */
964         if (is_bitmap(uh, up)) {
965                 ub = up->ptr;
966
967                 KASSERT(bit_test(ub->map, item) != 0,
968                     ("UNR: Freeing free item %d (bitmap)\n", item));
969                 bit_clear(ub->map, item);
970                 uh->busy--;
971                 collapse_unr(uh, up);
972                 return;
973         }
974
975         KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item));
976
977         /* Just this one left, reap it */
978         if (up->len == 1) {
979                 up->ptr = NULL;
980                 uh->busy--;
981                 collapse_unr(uh, up);
982                 return;
983         }
984
985         /* Check if we can shift the item into the previous 'free' run */
986         upp = TAILQ_PREV(up, unrhd, list);
987         if (item == 0 && upp != NULL && upp->ptr == NULL) {
988                 upp->len++;
989                 up->len--;
990                 uh->busy--;
991                 collapse_unr(uh, up);
992                 return;
993         }
994
995         /* Check if we can shift the item to the next 'free' run */
996         upn = TAILQ_NEXT(up, list);
997         if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) {
998                 upn->len++;
999                 up->len--;
1000                 uh->busy--;
1001                 collapse_unr(uh, up);
1002                 return;
1003         }
1004
1005         /* Split off the tail end, if any. */
1006         pl = up->len - (1 + item);
1007         if (pl > 0) {
1008                 upp = new_unr(uh, p1, p2);
1009                 upp->ptr = uh;
1010                 upp->len = pl;
1011                 TAILQ_INSERT_AFTER(&uh->head, up, upp, list);
1012         }
1013
1014         /* Split off head end, if any */
1015         if (item > 0) {
1016                 upp = new_unr(uh, p1, p2);
1017                 upp->len = item;
1018                 upp->ptr = uh;
1019                 TAILQ_INSERT_BEFORE(up, upp, list);
1020         }
1021         up->len = 1;
1022         up->ptr = NULL;
1023         uh->busy--;
1024         collapse_unr(uh, up);
1025 }
1026
1027 void
1028 free_unr(struct unrhdr *uh, u_int item)
1029 {
1030         void *p1, *p2;
1031
1032         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "free_unr");
1033         p1 = Malloc(sizeof(struct unr));
1034         p2 = Malloc(sizeof(struct unr));
1035         if (uh->mtx != NULL)
1036                 mtx_lock(uh->mtx);
1037         free_unrl(uh, item, &p1, &p2);
1038         clean_unrhdrl(uh);
1039         if (uh->mtx != NULL)
1040                 mtx_unlock(uh->mtx);
1041         if (p1 != NULL)
1042                 Free(p1);
1043         if (p2 != NULL)
1044                 Free(p2);
1045 }
1046
1047 #ifdef _KERNEL
1048 #include "opt_ddb.h"
1049 #ifdef DDB
1050 #include <ddb/ddb.h>
1051 #endif
1052 #endif
1053
1054 #if (defined(_KERNEL) && defined(DDB)) || !defined(_KERNEL)
1055
1056 #if !defined(_KERNEL)
1057 #define db_printf printf
1058 #endif
1059
1060 static void
1061 print_unr(struct unrhdr *uh, struct unr *up)
1062 {
1063         u_int x;
1064         struct unrb *ub;
1065
1066         db_printf("  %p len = %5u ", up, up->len);
1067         if (up->ptr == NULL)
1068                 db_printf("free\n");
1069         else if (up->ptr == uh)
1070                 db_printf("alloc\n");
1071         else {
1072                 ub = up->ptr;
1073                 db_printf("bitmap [");
1074                 for (x = 0; x < up->len; x++) {
1075                         if (bit_test(ub->map, x))
1076                                 db_printf("#");
1077                         else
1078                                 db_printf(" ");
1079                 }
1080                 db_printf("]\n");
1081         }
1082 }
1083
1084 static void
1085 print_unrhdr(struct unrhdr *uh)
1086 {
1087         struct unr *up;
1088         u_int x;
1089
1090         db_printf(
1091             "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n",
1092             uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc);
1093         x = uh->low + uh->first;
1094         TAILQ_FOREACH(up, &uh->head, list) {
1095                 db_printf("  from = %5u", x);
1096                 print_unr(uh, up);
1097                 if (up->ptr == NULL || up->ptr == uh)
1098                         x += up->len;
1099                 else
1100                         x += NBITS;
1101         }
1102 }
1103
1104 #endif
1105
1106 #if defined(_KERNEL) && defined(DDB)
1107 DB_SHOW_COMMAND(unrhdr, unrhdr_print_unrhdr)
1108 {
1109         if (!have_addr) {
1110                 db_printf("show unrhdr addr\n");
1111                 return;
1112         }
1113
1114         print_unrhdr((struct unrhdr *)addr);
1115 }
1116
1117 static void
1118 print_unrhdr_iter(struct unrhdr_iter *iter)
1119 {
1120         db_printf("iter %p unrhdr %p ipos %d upos %p ufi %d\n",
1121             iter, iter->uh, iter->ipos, iter->upos, iter->upos_first_item);
1122 }
1123
1124 DB_SHOW_COMMAND(unrhdr_iter, unrhdr_print_iter)
1125 {
1126         if (!have_addr) {
1127                 db_printf("show unrhdr_iter addr\n");
1128                 return;
1129         }
1130
1131         print_unrhdr_iter((struct unrhdr_iter *)addr);
1132 }
1133 #endif
1134
1135 #ifndef _KERNEL /* USERLAND test driver */
1136
1137 /*
1138  * Simple stochastic test driver for the above functions.  The code resides
1139  * here so that it can access static functions and structures.
1140  */
1141
1142 static bool verbose;
1143 #define VPRINTF(...)    {if (verbose) printf(__VA_ARGS__);}
1144
1145 static void
1146 test_alloc_unr(struct unrhdr *uh, u_int i, char a[])
1147 {
1148         int j;
1149
1150         if (a[i]) {
1151                 VPRINTF("F %u\n", i);
1152                 free_unr(uh, i);
1153                 a[i] = 0;
1154         } else {
1155                 no_alloc = 1;
1156                 j = alloc_unr(uh);
1157                 if (j != -1) {
1158                         a[j] = 1;
1159                         VPRINTF("A %d\n", j);
1160                 }
1161                 no_alloc = 0;
1162         }
1163 }
1164
1165 static void
1166 test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[])
1167 {
1168         int j;
1169
1170         j = alloc_unr_specific(uh, i);
1171         if (j == -1) {
1172                 VPRINTF("F %u\n", i);
1173                 a[i] = 0;
1174                 free_unr(uh, i);
1175         } else {
1176                 a[i] = 1;
1177                 VPRINTF("A %d\n", j);
1178         }
1179 }
1180
1181 #define TBASE   7
1182 #define XSIZE   10
1183 #define ISIZE   1000
1184
1185 static int
1186 test_iter_compar(const void *a, const void *b)
1187 {
1188         return (*(const int *)a - *(const int *)b);
1189 }
1190
1191 static void
1192 test_iter_fill(int *vals, struct unrhdr *uh, int i, int v, int *res)
1193 {
1194         int x;
1195
1196         vals[i] = v;
1197         x = alloc_unr_specific(uh, v);
1198         if (x != v) {
1199                 VPRINTF("alloc_unr_specific failed %d %d\n", x, v);
1200                 *res = 1;
1201         }
1202 }
1203
1204 static void
1205 test_iter(void)
1206 {
1207         struct unrhdr *uh;
1208         void *ihandle;
1209         int vals[ISIZE];
1210         int i, j, v, x, res;
1211
1212         res = 0;
1213         uh = new_unrhdr(TBASE, INT_MAX, NULL);
1214         for (i = 0; i < XSIZE; i++) {
1215                 vals[i] = i + TBASE;
1216                 x = alloc_unr_specific(uh, i + TBASE);
1217                 if (x != i + TBASE) {
1218                         VPRINTF("alloc_unr_specific failed %d %d\n", x,
1219                             i + TBASE);
1220                         res = 1;
1221                 }
1222         }
1223         for (; i < ISIZE; i++) {
1224                 for (;;) {
1225 again:
1226                         v = arc4random_uniform(INT_MAX);
1227                         if (v < TBASE)
1228                                 goto again;
1229                         for (j = 0; j < i; j++) {
1230                                 if (v == vals[j] || v + 1 == vals[j])
1231                                         goto again;
1232                         }
1233                         break;
1234                 }
1235                 test_iter_fill(vals, uh, i, v, &res);
1236                 i++, v++;
1237                 if (i < ISIZE)
1238                         test_iter_fill(vals, uh, i, v, &res);
1239         }
1240         qsort(vals, ISIZE, sizeof(vals[0]), test_iter_compar);
1241
1242         ihandle = create_iter_unr(uh);
1243         i = 0;
1244         while ((v = next_iter_unr(ihandle)) != -1) {
1245                 if (vals[i] != v) {
1246                         VPRINTF("iter %d: iter %d != val %d\n", i, v, vals[i]);
1247                         if (res == 0) {
1248                                 if (verbose)
1249                                         print_unrhdr(uh);
1250                                 res = 1;
1251                         }
1252                 } else {
1253                         VPRINTF("iter %d: val %d\n", i, v);
1254                 }
1255                 i++;
1256         }
1257         free_iter_unr(ihandle);
1258         clean_unrhdr(uh);
1259         clear_unrhdr(uh);
1260         delete_unrhdr(uh);
1261         exit(res);
1262 }
1263
1264 static void
1265 usage(char **argv)
1266 {
1267         printf("%s [-h] [-i] [-r REPETITIONS] [-v]\n", argv[0]);
1268 }
1269
1270 int
1271 main(int argc, char **argv)
1272 {
1273         struct unrhdr *uh;
1274         char *a;
1275         long count = 10000;     /* Number of unrs to test */
1276         long reps = 1, m;
1277         int ch;
1278         u_int i;
1279         bool testing_iter;
1280
1281         verbose = false;
1282         testing_iter = false;
1283
1284         while ((ch = getopt(argc, argv, "hir:v")) != -1) {
1285                 switch (ch) {
1286                 case 'i':
1287                         testing_iter = true;
1288                         break;
1289                 case 'r':
1290                         errno = 0;
1291                         reps = strtol(optarg, NULL, 0);
1292                         if (errno == ERANGE || errno == EINVAL) {
1293                                 usage(argv);
1294                                 exit(2);
1295                         }
1296
1297                         break;
1298                 case 'v':
1299                         verbose = true;
1300                         break;
1301                 case 'h':
1302                 default:
1303                         usage(argv);
1304                         exit(2);
1305                 }
1306         }
1307
1308         setbuf(stdout, NULL);
1309
1310         if (testing_iter)
1311                 test_iter();
1312
1313         uh = new_unrhdr(0, count - 1, NULL);
1314         print_unrhdr(uh);
1315
1316         a = calloc(count, sizeof(char));
1317         if (a == NULL)
1318                 err(1, "calloc failed");
1319
1320         printf("sizeof(struct unr) %zu\n", sizeof(struct unr));
1321         printf("sizeof(struct unrb) %zu\n", sizeof(struct unrb));
1322         printf("sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr));
1323         printf("NBITS %lu\n", (unsigned long)NBITS);
1324         for (m = 0; m < count * reps; m++) {
1325                 i = arc4random_uniform(count);
1326 #if 0
1327                 if (a[i] && (j & 1))
1328                         continue;
1329 #endif
1330                 if ((arc4random() & 1) != 0)
1331                         test_alloc_unr(uh, i, a);
1332                 else
1333                         test_alloc_unr_specific(uh, i, a);
1334
1335                 if (verbose)
1336                         print_unrhdr(uh);
1337                 check_unrhdr(uh, __LINE__);
1338         }
1339         for (i = 0; i < (u_int)count; i++) {
1340                 if (a[i]) {
1341                         if (verbose) {
1342                                 printf("C %u\n", i);
1343                                 print_unrhdr(uh);
1344                         }
1345                         free_unr(uh, i);
1346                 }
1347         }
1348         print_unrhdr(uh);
1349         delete_unrhdr(uh);
1350         free(a);
1351         return (0);
1352 }
1353 #endif