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