xref: /freebsd/sys/kern/subr_unit.c (revision 1d386b48)
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 /*
344  * Consistency check function.
345  *
346  * Checks the internal consistency as well as we can.
347  *
348  * Called at all boundaries of this API.
349  */
350 static void
351 check_unrhdr(struct unrhdr *uh, int line)
352 {
353 	struct unr *up;
354 	struct unrb *ub;
355 	int w;
356 	u_int y, z;
357 
358 	y = uh->first;
359 	z = 0;
360 	TAILQ_FOREACH(up, &uh->head, list) {
361 		z++;
362 		if (is_bitmap(uh, up)) {
363 			ub = up->ptr;
364 			KASSERT (up->len <= NBITS,
365 			    ("UNR inconsistency: len %u max %zd (line %d)\n",
366 			    up->len, NBITS, line));
367 			z++;
368 			w = 0;
369 			bit_count(ub->map, 0, up->len, &w);
370 			y += w;
371 		} else if (up->ptr != NULL)
372 			y += up->len;
373 	}
374 	KASSERT (y == uh->busy,
375 	    ("UNR inconsistency: items %u found %u (line %d)\n",
376 	    uh->busy, y, line));
377 	KASSERT (z == uh->alloc,
378 	    ("UNR inconsistency: chunks %u found %u (line %d)\n",
379 	    uh->alloc, z, line));
380 }
381 
382 #else
383 
384 static __inline void
385 check_unrhdr(struct unrhdr *uh __unused, int line __unused)
386 {
387 
388 }
389 
390 #endif
391 
392 /*
393  * Userland memory management.  Just use calloc and keep track of how
394  * many elements we have allocated for check_unrhdr().
395  */
396 
397 static __inline void *
398 new_unr(struct unrhdr *uh, void **p1, void **p2)
399 {
400 	void *p;
401 
402 	uh->alloc++;
403 	KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory"));
404 	if (*p1 != NULL) {
405 		p = *p1;
406 		*p1 = NULL;
407 		return (p);
408 	} else {
409 		p = *p2;
410 		*p2 = NULL;
411 		return (p);
412 	}
413 }
414 
415 static __inline void
416 delete_unr(struct unrhdr *uh, void *ptr)
417 {
418 	struct unr *up;
419 
420 	uh->alloc--;
421 	up = ptr;
422 	TAILQ_INSERT_TAIL(&uh->ppfree, up, list);
423 }
424 
425 void
426 clean_unrhdrl(struct unrhdr *uh)
427 {
428 	struct unr *up;
429 
430 	if (uh->mtx != NULL)
431 		mtx_assert(uh->mtx, MA_OWNED);
432 	while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) {
433 		TAILQ_REMOVE(&uh->ppfree, up, list);
434 		if (uh->mtx != NULL)
435 			mtx_unlock(uh->mtx);
436 		Free(up);
437 		if (uh->mtx != NULL)
438 			mtx_lock(uh->mtx);
439 	}
440 
441 }
442 
443 void
444 clean_unrhdr(struct unrhdr *uh)
445 {
446 
447 	if (uh->mtx != NULL)
448 		mtx_lock(uh->mtx);
449 	clean_unrhdrl(uh);
450 	if (uh->mtx != NULL)
451 		mtx_unlock(uh->mtx);
452 }
453 
454 void
455 init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex)
456 {
457 
458 	KASSERT(low >= 0 && low <= high,
459 	    ("UNR: use error: new_unrhdr(%d, %d)", low, high));
460 	if (mutex == UNR_NO_MTX)
461 		uh->mtx = NULL;
462 	else if (mutex != NULL)
463 		uh->mtx = mutex;
464 	else
465 		uh->mtx = &unitmtx;
466 	TAILQ_INIT(&uh->head);
467 	TAILQ_INIT(&uh->ppfree);
468 	uh->low = low;
469 	uh->high = high;
470 	uh->first = 0;
471 	uh->last = 1 + (high - low);
472 	uh->busy = 0;
473 	uh->alloc = 0;
474 	check_unrhdr(uh, __LINE__);
475 }
476 
477 /*
478  * Allocate a new unrheader set.
479  *
480  * Highest and lowest valid values given as parameters.
481  */
482 
483 struct unrhdr *
484 new_unrhdr(int low, int high, struct mtx *mutex)
485 {
486 	struct unrhdr *uh;
487 
488 	uh = Malloc(sizeof *uh);
489 	init_unrhdr(uh, low, high, mutex);
490 	return (uh);
491 }
492 
493 void
494 delete_unrhdr(struct unrhdr *uh)
495 {
496 
497 	check_unrhdr(uh, __LINE__);
498 	KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy));
499 	KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr"));
500 	KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL,
501 	    ("unrhdr has postponed item for free"));
502 	Free(uh);
503 }
504 
505 void
506 clear_unrhdr(struct unrhdr *uh)
507 {
508 	struct unr *up, *uq;
509 
510 	KASSERT(TAILQ_EMPTY(&uh->ppfree),
511 	    ("unrhdr has postponed item for free"));
512 	TAILQ_FOREACH_SAFE(up, &uh->head, list, uq) {
513 		if (up->ptr != uh) {
514 			Free(up->ptr);
515 		}
516 		Free(up);
517 	}
518 	uh->busy = 0;
519 	uh->alloc = 0;
520 	init_unrhdr(uh, uh->low, uh->high, uh->mtx);
521 
522 	check_unrhdr(uh, __LINE__);
523 }
524 
525 /*
526  * Look for sequence of items which can be combined into a bitmap, if
527  * multiple are present, take the one which saves most memory.
528  *
529  * Return (1) if a sequence was found to indicate that another call
530  * might be able to do more.  Return (0) if we found no suitable sequence.
531  *
532  * NB: called from alloc_unr(), no new memory allocation allowed.
533  */
534 static int
535 optimize_unr(struct unrhdr *uh)
536 {
537 	struct unr *up, *uf, *us;
538 	struct unrb *ub, *ubf;
539 	u_int a, l, ba;
540 
541 	/*
542 	 * Look for the run of items (if any) which when collapsed into
543 	 * a bitmap would save most memory.
544 	 */
545 	us = NULL;
546 	ba = 0;
547 	TAILQ_FOREACH(uf, &uh->head, list) {
548 		if (uf->len >= NBITS)
549 			continue;
550 		a = 1;
551 		if (is_bitmap(uh, uf))
552 			a++;
553 		l = uf->len;
554 		up = uf;
555 		while (1) {
556 			up = TAILQ_NEXT(up, list);
557 			if (up == NULL)
558 				break;
559 			if ((up->len + l) > NBITS)
560 				break;
561 			a++;
562 			if (is_bitmap(uh, up))
563 				a++;
564 			l += up->len;
565 		}
566 		if (a > ba) {
567 			ba = a;
568 			us = uf;
569 		}
570 	}
571 	if (ba < 3)
572 		return (0);
573 
574 	/*
575 	 * If the first element is not a bitmap, make it one.
576 	 * Trying to do so without allocating more memory complicates things
577 	 * a bit
578 	 */
579 	if (!is_bitmap(uh, us)) {
580 		uf = TAILQ_NEXT(us, list);
581 		TAILQ_REMOVE(&uh->head, us, list);
582 		a = us->len;
583 		l = us->ptr == uh ? 1 : 0;
584 		ub = (void *)us;
585 		bit_nclear(ub->map, 0, NBITS - 1);
586 		if (l)
587 			bit_nset(ub->map, 0, a);
588 		if (!is_bitmap(uh, uf)) {
589 			if (uf->ptr == NULL)
590 				bit_nclear(ub->map, a, a + uf->len - 1);
591 			else
592 				bit_nset(ub->map, a, a + uf->len - 1);
593 			uf->ptr = ub;
594 			uf->len += a;
595 			us = uf;
596 		} else {
597 			ubf = uf->ptr;
598 			for (l = 0; l < uf->len; l++, a++) {
599 				if (bit_test(ubf->map, l))
600 					bit_set(ub->map, a);
601 				else
602 					bit_clear(ub->map, a);
603 			}
604 			uf->len = a;
605 			delete_unr(uh, uf->ptr);
606 			uf->ptr = ub;
607 			us = uf;
608 		}
609 	}
610 	ub = us->ptr;
611 	while (1) {
612 		uf = TAILQ_NEXT(us, list);
613 		if (uf == NULL)
614 			return (1);
615 		if (uf->len + us->len > NBITS)
616 			return (1);
617 		if (uf->ptr == NULL) {
618 			bit_nclear(ub->map, us->len, us->len + uf->len - 1);
619 			us->len += uf->len;
620 			TAILQ_REMOVE(&uh->head, uf, list);
621 			delete_unr(uh, uf);
622 		} else if (uf->ptr == uh) {
623 			bit_nset(ub->map, us->len, us->len + uf->len - 1);
624 			us->len += uf->len;
625 			TAILQ_REMOVE(&uh->head, uf, list);
626 			delete_unr(uh, uf);
627 		} else {
628 			ubf = uf->ptr;
629 			for (l = 0; l < uf->len; l++, us->len++) {
630 				if (bit_test(ubf->map, l))
631 					bit_set(ub->map, us->len);
632 				else
633 					bit_clear(ub->map, us->len);
634 			}
635 			TAILQ_REMOVE(&uh->head, uf, list);
636 			delete_unr(uh, ubf);
637 			delete_unr(uh, uf);
638 		}
639 	}
640 }
641 
642 /*
643  * See if a given unr should be collapsed with a neighbor.
644  *
645  * NB: called from alloc_unr(), no new memory allocation allowed.
646  */
647 static void
648 collapse_unr(struct unrhdr *uh, struct unr *up)
649 {
650 	struct unr *upp;
651 	struct unrb *ub;
652 
653 	/* If bitmap is all set or clear, change it to runlength */
654 	if (is_bitmap(uh, up)) {
655 		ub = up->ptr;
656 		if (ub_full(ub, up->len)) {
657 			delete_unr(uh, up->ptr);
658 			up->ptr = uh;
659 		} else if (ub_empty(ub, up->len)) {
660 			delete_unr(uh, up->ptr);
661 			up->ptr = NULL;
662 		}
663 	}
664 
665 	/* If nothing left in runlength, delete it */
666 	if (up->len == 0) {
667 		upp = TAILQ_PREV(up, unrhd, list);
668 		if (upp == NULL)
669 			upp = TAILQ_NEXT(up, list);
670 		TAILQ_REMOVE(&uh->head, up, list);
671 		delete_unr(uh, up);
672 		up = upp;
673 	}
674 
675 	/* If we have "hot-spot" still, merge with neighbor if possible */
676 	if (up != NULL) {
677 		upp = TAILQ_PREV(up, unrhd, list);
678 		if (upp != NULL && up->ptr == upp->ptr) {
679 			up->len += upp->len;
680 			TAILQ_REMOVE(&uh->head, upp, list);
681 			delete_unr(uh, upp);
682 			}
683 		upp = TAILQ_NEXT(up, list);
684 		if (upp != NULL && up->ptr == upp->ptr) {
685 			up->len += upp->len;
686 			TAILQ_REMOVE(&uh->head, upp, list);
687 			delete_unr(uh, upp);
688 		}
689 	}
690 
691 	/* Merge into ->first if possible */
692 	upp = TAILQ_FIRST(&uh->head);
693 	if (upp != NULL && upp->ptr == uh) {
694 		uh->first += upp->len;
695 		TAILQ_REMOVE(&uh->head, upp, list);
696 		delete_unr(uh, upp);
697 		if (up == upp)
698 			up = NULL;
699 	}
700 
701 	/* Merge into ->last if possible */
702 	upp = TAILQ_LAST(&uh->head, unrhd);
703 	if (upp != NULL && upp->ptr == NULL) {
704 		uh->last += upp->len;
705 		TAILQ_REMOVE(&uh->head, upp, list);
706 		delete_unr(uh, upp);
707 		if (up == upp)
708 			up = NULL;
709 	}
710 
711 	/* Try to make bitmaps */
712 	while (optimize_unr(uh))
713 		continue;
714 }
715 
716 /*
717  * Allocate a free unr.
718  */
719 int
720 alloc_unrl(struct unrhdr *uh)
721 {
722 	struct unr *up;
723 	struct unrb *ub;
724 	u_int x;
725 	int y;
726 
727 	if (uh->mtx != NULL)
728 		mtx_assert(uh->mtx, MA_OWNED);
729 	check_unrhdr(uh, __LINE__);
730 	x = uh->low + uh->first;
731 
732 	up = TAILQ_FIRST(&uh->head);
733 
734 	/*
735 	 * If we have an ideal split, just adjust the first+last
736 	 */
737 	if (up == NULL && uh->last > 0) {
738 		uh->first++;
739 		uh->last--;
740 		uh->busy++;
741 		return (x);
742 	}
743 
744 	/*
745 	 * We can always allocate from the first list element, so if we have
746 	 * nothing on the list, we must have run out of unit numbers.
747 	 */
748 	if (up == NULL)
749 		return (-1);
750 
751 	KASSERT(up->ptr != uh, ("UNR first element is allocated"));
752 
753 	if (up->ptr == NULL) {	/* free run */
754 		uh->first++;
755 		up->len--;
756 	} else {		/* bitmap */
757 		ub = up->ptr;
758 		bit_ffc(ub->map, up->len, &y);
759 		KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap."));
760 		bit_set(ub->map, y);
761 		x += y;
762 	}
763 	uh->busy++;
764 	collapse_unr(uh, up);
765 	return (x);
766 }
767 
768 int
769 alloc_unr(struct unrhdr *uh)
770 {
771 	int i;
772 
773 	if (uh->mtx != NULL)
774 		mtx_lock(uh->mtx);
775 	i = alloc_unrl(uh);
776 	clean_unrhdrl(uh);
777 	if (uh->mtx != NULL)
778 		mtx_unlock(uh->mtx);
779 	return (i);
780 }
781 
782 static int
783 alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2)
784 {
785 	struct unr *up, *upn;
786 	struct unrb *ub;
787 	u_int i, last, tl;
788 
789 	if (uh->mtx != NULL)
790 		mtx_assert(uh->mtx, MA_OWNED);
791 
792 	if (item < uh->low + uh->first || item > uh->high)
793 		return (-1);
794 
795 	up = TAILQ_FIRST(&uh->head);
796 	/* Ideal split. */
797 	if (up == NULL && item - uh->low == uh->first) {
798 		uh->first++;
799 		uh->last--;
800 		uh->busy++;
801 		check_unrhdr(uh, __LINE__);
802 		return (item);
803 	}
804 
805 	i = item - uh->low - uh->first;
806 
807 	if (up == NULL) {
808 		up = new_unr(uh, p1, p2);
809 		up->ptr = NULL;
810 		up->len = i;
811 		TAILQ_INSERT_TAIL(&uh->head, up, list);
812 		up = new_unr(uh, p1, p2);
813 		up->ptr = uh;
814 		up->len = 1;
815 		TAILQ_INSERT_TAIL(&uh->head, up, list);
816 		uh->last = uh->high - uh->low - i;
817 		uh->busy++;
818 		check_unrhdr(uh, __LINE__);
819 		return (item);
820 	} else {
821 		/* Find the item which contains the unit we want to allocate. */
822 		TAILQ_FOREACH(up, &uh->head, list) {
823 			if (up->len > i)
824 				break;
825 			i -= up->len;
826 		}
827 	}
828 
829 	if (up == NULL) {
830 		if (i > 0) {
831 			up = new_unr(uh, p1, p2);
832 			up->ptr = NULL;
833 			up->len = i;
834 			TAILQ_INSERT_TAIL(&uh->head, up, list);
835 		}
836 		up = new_unr(uh, p1, p2);
837 		up->ptr = uh;
838 		up->len = 1;
839 		TAILQ_INSERT_TAIL(&uh->head, up, list);
840 		goto done;
841 	}
842 
843 	if (is_bitmap(uh, up)) {
844 		ub = up->ptr;
845 		if (bit_test(ub->map, i) == 0) {
846 			bit_set(ub->map, i);
847 			goto done;
848 		} else
849 			return (-1);
850 	} else if (up->ptr == uh)
851 		return (-1);
852 
853 	KASSERT(up->ptr == NULL,
854 	    ("alloc_unr_specificl: up->ptr != NULL (up=%p)", up));
855 
856 	/* Split off the tail end, if any. */
857 	tl = up->len - (1 + i);
858 	if (tl > 0) {
859 		upn = new_unr(uh, p1, p2);
860 		upn->ptr = NULL;
861 		upn->len = tl;
862 		TAILQ_INSERT_AFTER(&uh->head, up, upn, list);
863 	}
864 
865 	/* Split off head end, if any */
866 	if (i > 0) {
867 		upn = new_unr(uh, p1, p2);
868 		upn->len = i;
869 		upn->ptr = NULL;
870 		TAILQ_INSERT_BEFORE(up, upn, list);
871 	}
872 	up->len = 1;
873 	up->ptr = uh;
874 
875 done:
876 	last = uh->high - uh->low - (item - uh->low);
877 	if (uh->last > last)
878 		uh->last = last;
879 	uh->busy++;
880 	collapse_unr(uh, up);
881 	check_unrhdr(uh, __LINE__);
882 	return (item);
883 }
884 
885 int
886 alloc_unr_specific(struct unrhdr *uh, u_int item)
887 {
888 	void *p1, *p2;
889 	int i;
890 
891 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific");
892 
893 	p1 = Malloc(sizeof(struct unr));
894 	p2 = Malloc(sizeof(struct unr));
895 
896 	if (uh->mtx != NULL)
897 		mtx_lock(uh->mtx);
898 	i = alloc_unr_specificl(uh, item, &p1, &p2);
899 	if (uh->mtx != NULL)
900 		mtx_unlock(uh->mtx);
901 
902 	if (p1 != NULL)
903 		Free(p1);
904 	if (p2 != NULL)
905 		Free(p2);
906 
907 	return (i);
908 }
909 
910 /*
911  * Free a unr.
912  *
913  * If we can save unrs by using a bitmap, do so.
914  */
915 static void
916 free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2)
917 {
918 	struct unr *up, *upp, *upn;
919 	struct unrb *ub;
920 	u_int pl;
921 
922 	KASSERT(item >= uh->low && item <= uh->high,
923 	    ("UNR: free_unr(%u) out of range [%u...%u]",
924 	     item, uh->low, uh->high));
925 	check_unrhdr(uh, __LINE__);
926 	item -= uh->low;
927 	upp = TAILQ_FIRST(&uh->head);
928 	/*
929 	 * Freeing in the ideal split case
930 	 */
931 	if (item + 1 == uh->first && upp == NULL) {
932 		uh->last++;
933 		uh->first--;
934 		uh->busy--;
935 		check_unrhdr(uh, __LINE__);
936 		return;
937 	}
938 	/*
939  	 * Freeing in the ->first section.  Create a run starting at the
940 	 * freed item.  The code below will subdivide it.
941 	 */
942 	if (item < uh->first) {
943 		up = new_unr(uh, p1, p2);
944 		up->ptr = uh;
945 		up->len = uh->first - item;
946 		TAILQ_INSERT_HEAD(&uh->head, up, list);
947 		uh->first -= up->len;
948 	}
949 
950 	item -= uh->first;
951 
952 	/* Find the item which contains the unit we want to free */
953 	TAILQ_FOREACH(up, &uh->head, list) {
954 		if (up->len > item)
955 			break;
956 		item -= up->len;
957 	}
958 
959 	/* Handle bitmap items */
960 	if (is_bitmap(uh, up)) {
961 		ub = up->ptr;
962 
963 		KASSERT(bit_test(ub->map, item) != 0,
964 		    ("UNR: Freeing free item %d (bitmap)\n", item));
965 		bit_clear(ub->map, item);
966 		uh->busy--;
967 		collapse_unr(uh, up);
968 		return;
969 	}
970 
971 	KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item));
972 
973 	/* Just this one left, reap it */
974 	if (up->len == 1) {
975 		up->ptr = NULL;
976 		uh->busy--;
977 		collapse_unr(uh, up);
978 		return;
979 	}
980 
981 	/* Check if we can shift the item into the previous 'free' run */
982 	upp = TAILQ_PREV(up, unrhd, list);
983 	if (item == 0 && upp != NULL && upp->ptr == NULL) {
984 		upp->len++;
985 		up->len--;
986 		uh->busy--;
987 		collapse_unr(uh, up);
988 		return;
989 	}
990 
991 	/* Check if we can shift the item to the next 'free' run */
992 	upn = TAILQ_NEXT(up, list);
993 	if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) {
994 		upn->len++;
995 		up->len--;
996 		uh->busy--;
997 		collapse_unr(uh, up);
998 		return;
999 	}
1000 
1001 	/* Split off the tail end, if any. */
1002 	pl = up->len - (1 + item);
1003 	if (pl > 0) {
1004 		upp = new_unr(uh, p1, p2);
1005 		upp->ptr = uh;
1006 		upp->len = pl;
1007 		TAILQ_INSERT_AFTER(&uh->head, up, upp, list);
1008 	}
1009 
1010 	/* Split off head end, if any */
1011 	if (item > 0) {
1012 		upp = new_unr(uh, p1, p2);
1013 		upp->len = item;
1014 		upp->ptr = uh;
1015 		TAILQ_INSERT_BEFORE(up, upp, list);
1016 	}
1017 	up->len = 1;
1018 	up->ptr = NULL;
1019 	uh->busy--;
1020 	collapse_unr(uh, up);
1021 }
1022 
1023 void
1024 free_unr(struct unrhdr *uh, u_int item)
1025 {
1026 	void *p1, *p2;
1027 
1028 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "free_unr");
1029 	p1 = Malloc(sizeof(struct unr));
1030 	p2 = Malloc(sizeof(struct unr));
1031 	if (uh->mtx != NULL)
1032 		mtx_lock(uh->mtx);
1033 	free_unrl(uh, item, &p1, &p2);
1034 	clean_unrhdrl(uh);
1035 	if (uh->mtx != NULL)
1036 		mtx_unlock(uh->mtx);
1037 	if (p1 != NULL)
1038 		Free(p1);
1039 	if (p2 != NULL)
1040 		Free(p2);
1041 }
1042 
1043 #ifdef _KERNEL
1044 #include "opt_ddb.h"
1045 #ifdef DDB
1046 #include <ddb/ddb.h>
1047 #endif
1048 #endif
1049 
1050 #if (defined(_KERNEL) && defined(DDB)) || !defined(_KERNEL)
1051 
1052 #if !defined(_KERNEL)
1053 #define db_printf printf
1054 #endif
1055 
1056 static void
1057 print_unr(struct unrhdr *uh, struct unr *up)
1058 {
1059 	u_int x;
1060 	struct unrb *ub;
1061 
1062 	db_printf("  %p len = %5u ", up, up->len);
1063 	if (up->ptr == NULL)
1064 		db_printf("free\n");
1065 	else if (up->ptr == uh)
1066 		db_printf("alloc\n");
1067 	else {
1068 		ub = up->ptr;
1069 		db_printf("bitmap [");
1070 		for (x = 0; x < up->len; x++) {
1071 			if (bit_test(ub->map, x))
1072 				db_printf("#");
1073 			else
1074 				db_printf(" ");
1075 		}
1076 		db_printf("]\n");
1077 	}
1078 }
1079 
1080 static void
1081 print_unrhdr(struct unrhdr *uh)
1082 {
1083 	struct unr *up;
1084 	u_int x;
1085 
1086 	db_printf(
1087 	    "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n",
1088 	    uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc);
1089 	x = uh->low + uh->first;
1090 	TAILQ_FOREACH(up, &uh->head, list) {
1091 		db_printf("  from = %5u", x);
1092 		print_unr(uh, up);
1093 		if (up->ptr == NULL || up->ptr == uh)
1094 			x += up->len;
1095 		else
1096 			x += NBITS;
1097 	}
1098 }
1099 
1100 #endif
1101 
1102 #if defined(_KERNEL) && defined(DDB)
1103 DB_SHOW_COMMAND(unrhdr, unrhdr_print_unrhdr)
1104 {
1105 	if (!have_addr) {
1106 		db_printf("show unrhdr addr\n");
1107 		return;
1108 	}
1109 
1110 	print_unrhdr((struct unrhdr *)addr);
1111 }
1112 
1113 static void
1114 print_unrhdr_iter(struct unrhdr_iter *iter)
1115 {
1116 	db_printf("iter %p unrhdr %p ipos %d upos %p ufi %d\n",
1117 	    iter, iter->uh, iter->ipos, iter->upos, iter->upos_first_item);
1118 }
1119 
1120 DB_SHOW_COMMAND(unrhdr_iter, unrhdr_print_iter)
1121 {
1122 	if (!have_addr) {
1123 		db_printf("show unrhdr_iter addr\n");
1124 		return;
1125 	}
1126 
1127 	print_unrhdr_iter((struct unrhdr_iter *)addr);
1128 }
1129 #endif
1130 
1131 #ifndef _KERNEL	/* USERLAND test driver */
1132 
1133 /*
1134  * Simple stochastic test driver for the above functions.  The code resides
1135  * here so that it can access static functions and structures.
1136  */
1137 
1138 static bool verbose;
1139 #define VPRINTF(...)	{if (verbose) printf(__VA_ARGS__);}
1140 
1141 static void
1142 test_alloc_unr(struct unrhdr *uh, u_int i, char a[])
1143 {
1144 	int j;
1145 
1146 	if (a[i]) {
1147 		VPRINTF("F %u\n", i);
1148 		free_unr(uh, i);
1149 		a[i] = 0;
1150 	} else {
1151 		no_alloc = 1;
1152 		j = alloc_unr(uh);
1153 		if (j != -1) {
1154 			a[j] = 1;
1155 			VPRINTF("A %d\n", j);
1156 		}
1157 		no_alloc = 0;
1158 	}
1159 }
1160 
1161 static void
1162 test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[])
1163 {
1164 	int j;
1165 
1166 	j = alloc_unr_specific(uh, i);
1167 	if (j == -1) {
1168 		VPRINTF("F %u\n", i);
1169 		a[i] = 0;
1170 		free_unr(uh, i);
1171 	} else {
1172 		a[i] = 1;
1173 		VPRINTF("A %d\n", j);
1174 	}
1175 }
1176 
1177 #define	TBASE	7
1178 #define	XSIZE	10
1179 #define	ISIZE	1000
1180 
1181 static int
1182 test_iter_compar(const void *a, const void *b)
1183 {
1184 	return (*(const int *)a - *(const int *)b);
1185 }
1186 
1187 static void
1188 test_iter_fill(int *vals, struct unrhdr *uh, int i, int v, int *res)
1189 {
1190 	int x;
1191 
1192 	vals[i] = v;
1193 	x = alloc_unr_specific(uh, v);
1194 	if (x != v) {
1195 		VPRINTF("alloc_unr_specific failed %d %d\n", x, v);
1196 		*res = 1;
1197 	}
1198 }
1199 
1200 static void
1201 test_iter(void)
1202 {
1203 	struct unrhdr *uh;
1204 	void *ihandle;
1205 	int vals[ISIZE];
1206 	int i, j, v, x, res;
1207 
1208 	res = 0;
1209 	uh = new_unrhdr(TBASE, INT_MAX, NULL);
1210 	for (i = 0; i < XSIZE; i++) {
1211 		vals[i] = i + TBASE;
1212 		x = alloc_unr_specific(uh, i + TBASE);
1213 		if (x != i + TBASE) {
1214 			VPRINTF("alloc_unr_specific failed %d %d\n", x,
1215 			    i + TBASE);
1216 			res = 1;
1217 		}
1218 	}
1219 	for (; i < ISIZE; i++) {
1220 		for (;;) {
1221 again:
1222 			v = arc4random_uniform(INT_MAX);
1223 			if (v < TBASE)
1224 				goto again;
1225 			for (j = 0; j < i; j++) {
1226 				if (v == vals[j] || v + 1 == vals[j])
1227 					goto again;
1228 			}
1229 			break;
1230 		}
1231 		test_iter_fill(vals, uh, i, v, &res);
1232 		i++, v++;
1233 		if (i < ISIZE)
1234 			test_iter_fill(vals, uh, i, v, &res);
1235 	}
1236 	qsort(vals, ISIZE, sizeof(vals[0]), test_iter_compar);
1237 
1238 	ihandle = create_iter_unr(uh);
1239 	i = 0;
1240 	while ((v = next_iter_unr(ihandle)) != -1) {
1241 		if (vals[i] != v) {
1242 			VPRINTF("iter %d: iter %d != val %d\n", i, v, vals[i]);
1243 			if (res == 0) {
1244 				if (verbose)
1245 					print_unrhdr(uh);
1246 				res = 1;
1247 			}
1248 		} else {
1249 			VPRINTF("iter %d: val %d\n", i, v);
1250 		}
1251 		i++;
1252 	}
1253 	free_iter_unr(ihandle);
1254 	clean_unrhdr(uh);
1255 	clear_unrhdr(uh);
1256 	delete_unrhdr(uh);
1257 	exit(res);
1258 }
1259 
1260 static void
1261 usage(char **argv)
1262 {
1263 	printf("%s [-h] [-i] [-r REPETITIONS] [-v]\n", argv[0]);
1264 }
1265 
1266 int
1267 main(int argc, char **argv)
1268 {
1269 	struct unrhdr *uh;
1270 	char *a;
1271 	long count = 10000;	/* Number of unrs to test */
1272 	long reps = 1, m;
1273 	int ch;
1274 	u_int i;
1275 	bool testing_iter;
1276 
1277 	verbose = false;
1278 	testing_iter = false;
1279 
1280 	while ((ch = getopt(argc, argv, "hir:v")) != -1) {
1281 		switch (ch) {
1282 		case 'i':
1283 			testing_iter = true;
1284 			break;
1285 		case 'r':
1286 			errno = 0;
1287 			reps = strtol(optarg, NULL, 0);
1288 			if (errno == ERANGE || errno == EINVAL) {
1289 				usage(argv);
1290 				exit(2);
1291 			}
1292 
1293 			break;
1294 		case 'v':
1295 			verbose = true;
1296 			break;
1297 		case 'h':
1298 		default:
1299 			usage(argv);
1300 			exit(2);
1301 		}
1302 	}
1303 
1304 	setbuf(stdout, NULL);
1305 
1306 	if (testing_iter)
1307 		test_iter();
1308 
1309 	uh = new_unrhdr(0, count - 1, NULL);
1310 	print_unrhdr(uh);
1311 
1312 	a = calloc(count, sizeof(char));
1313 	if (a == NULL)
1314 		err(1, "calloc failed");
1315 
1316 	printf("sizeof(struct unr) %zu\n", sizeof(struct unr));
1317 	printf("sizeof(struct unrb) %zu\n", sizeof(struct unrb));
1318 	printf("sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr));
1319 	printf("NBITS %lu\n", (unsigned long)NBITS);
1320 	for (m = 0; m < count * reps; m++) {
1321 		i = arc4random_uniform(count);
1322 #if 0
1323 		if (a[i] && (j & 1))
1324 			continue;
1325 #endif
1326 		if ((arc4random() & 1) != 0)
1327 			test_alloc_unr(uh, i, a);
1328 		else
1329 			test_alloc_unr_specific(uh, i, a);
1330 
1331 		if (verbose)
1332 			print_unrhdr(uh);
1333 		check_unrhdr(uh, __LINE__);
1334 	}
1335 	for (i = 0; i < (u_int)count; i++) {
1336 		if (a[i]) {
1337 			if (verbose) {
1338 				printf("C %u\n", i);
1339 				print_unrhdr(uh);
1340 			}
1341 			free_unr(uh, i);
1342 		}
1343 	}
1344 	print_unrhdr(uh);
1345 	delete_unrhdr(uh);
1346 	free(a);
1347 	return (0);
1348 }
1349 #endif
1350