xref: /freebsd/sys/kern/subr_unit.c (revision 6469bdcdb6a5968dc7edfcfb495d427b4bfdb3dd)
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
1082