xref: /freebsd/sys/kern/subr_blist.c (revision d4e236c70b0db52cd7232a11ad0a2ed895e65f70)
106b4bf3eSWarner Losh /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
406b4bf3eSWarner Losh  * Copyright (c) 1998 Matthew Dillon.  All Rights Reserved.
506b4bf3eSWarner Losh  * Redistribution and use in source and binary forms, with or without
606b4bf3eSWarner Losh  * modification, are permitted provided that the following conditions
706b4bf3eSWarner Losh  * are met:
806b4bf3eSWarner Losh  * 1. Redistributions of source code must retain the above copyright
906b4bf3eSWarner Losh  *    notice, this list of conditions and the following disclaimer.
1006b4bf3eSWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
1106b4bf3eSWarner Losh  *    notice, this list of conditions and the following disclaimer in the
1206b4bf3eSWarner Losh  *    documentation and/or other materials provided with the distribution.
1369a28758SEd Maste  * 3. Neither the name of the University nor the names of its contributors
1406b4bf3eSWarner Losh  *    may be used to endorse or promote products derived from this software
1506b4bf3eSWarner Losh  *    without specific prior written permission.
1606b4bf3eSWarner Losh  *
1706b4bf3eSWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1806b4bf3eSWarner Losh  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1906b4bf3eSWarner Losh  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2006b4bf3eSWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2106b4bf3eSWarner Losh  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2206b4bf3eSWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2306b4bf3eSWarner Losh  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2406b4bf3eSWarner Losh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2506b4bf3eSWarner Losh  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2606b4bf3eSWarner Losh  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2706b4bf3eSWarner Losh  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2806b4bf3eSWarner Losh  */
297090df5aSMatthew Dillon /*
307090df5aSMatthew Dillon  * BLIST.C -	Bitmap allocator/deallocator, using a radix tree with hinting
317090df5aSMatthew Dillon  *
327090df5aSMatthew Dillon  *	This module implements a general bitmap allocator/deallocator.  The
337090df5aSMatthew Dillon  *	allocator eats around 2 bits per 'block'.  The module does not
34f565f395SEitan Adler  *	try to interpret the meaning of a 'block' other than to return
357090df5aSMatthew Dillon  *	SWAPBLK_NONE on an allocation failure.
367090df5aSMatthew Dillon  *
37ec371b57SAlan Cox  *	A radix tree controls access to pieces of the bitmap, and includes
38ec371b57SAlan Cox  *	auxiliary information at each interior node about the availabilty of
3900fd73d2SDoug Moore  *	contiguous free blocks in the subtree rooted at that node.  A radix
4000fd73d2SDoug Moore  *	constant defines the size of the bitmaps contained in a leaf node
4100fd73d2SDoug Moore  *	and the number of descendents of each of the meta (interior) nodes.
4200fd73d2SDoug Moore  *	Each subtree is associated with a range of blocks.  The root of any
4300fd73d2SDoug Moore  *	subtree stores a hint field that defines an upper bound on the size
4400fd73d2SDoug Moore  *	of the largest allocation that can begin in the associated block
4500fd73d2SDoug Moore  *	range.  A hint is an upper bound on a potential allocation, but not
4600fd73d2SDoug Moore  *	necessarily a tight upper bound.
477090df5aSMatthew Dillon  *
48bb4a27f9SMark Johnston  *	The bitmap field in each node directs the search for available blocks.
49bb4a27f9SMark Johnston  *	For a leaf node, a bit is set if the corresponding block is free.  For a
50bb4a27f9SMark Johnston  *	meta node, a bit is set if the corresponding subtree contains a free
51bb4a27f9SMark Johnston  *	block somewhere within it.  The search at a meta node considers only
52bb4a27f9SMark Johnston  *	children of that node that represent a range that includes a free block.
537090df5aSMatthew Dillon  *
547090df5aSMatthew Dillon  * 	The hinting greatly increases code efficiency for allocations while
557090df5aSMatthew Dillon  *	the general radix structure optimizes both allocations and frees.  The
567090df5aSMatthew Dillon  *	radix tree should be able to operate well no matter how much
577090df5aSMatthew Dillon  *	fragmentation there is and no matter how large a bitmap is used.
587090df5aSMatthew Dillon  *
5951dc4feaSSergey Kandaurov  *	The blist code wires all necessary memory at creation time.  Neither
6051dc4feaSSergey Kandaurov  *	allocations nor frees require interaction with the memory subsystem.
61bb4a27f9SMark Johnston  *	The non-blocking nature of allocations and frees is required by swap
62bb4a27f9SMark Johnston  *	code (vm/swap_pager.c).
637090df5aSMatthew Dillon  *
64bb4a27f9SMark Johnston  *	LAYOUT: The radix tree is laid out recursively using a linear array.
65bb4a27f9SMark Johnston  *	Each meta node is immediately followed (laid out sequentially in
6600fd73d2SDoug Moore  *	memory) by BLIST_RADIX lower-level nodes.  This is a recursive
67bb4a27f9SMark Johnston  *	structure but one that can be easily scanned through a very simple
68bb4a27f9SMark Johnston  *	'skip' calculation.  The memory allocation is only large enough to
69bb4a27f9SMark Johnston  *	cover the number of blocks requested at creation time.  Nodes that
70bb4a27f9SMark Johnston  *	represent blocks beyond that limit, nodes that would never be read
71bb4a27f9SMark Johnston  *	or written, are not allocated, so that the last of the
7200fd73d2SDoug Moore  *	BLIST_RADIX lower-level nodes of a some nodes may not be allocated.
737090df5aSMatthew Dillon  *
74f565f395SEitan Adler  *	NOTE: the allocator cannot currently allocate more than
7500fd73d2SDoug Moore  *	BLIST_RADIX blocks per call.  It will panic with 'allocation too
767090df5aSMatthew Dillon  *	large' if you try.  This is an area that could use improvement.  The
777090df5aSMatthew Dillon  *	radix is large enough that this restriction does not effect the swap
78b411efa4SAlan Cox  *	system, though.  Currently only the allocation code is affected by
797090df5aSMatthew Dillon  *	this algorithmic unfeature.  The freeing code can handle arbitrary
807090df5aSMatthew Dillon  *	ranges.
817090df5aSMatthew Dillon  *
827090df5aSMatthew Dillon  *	This code can be compiled stand-alone for debugging.
837090df5aSMatthew Dillon  */
847090df5aSMatthew Dillon 
85677b542eSDavid E. O'Brien #include <sys/cdefs.h>
86677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
87677b542eSDavid E. O'Brien 
88c4473420SPeter Wemm #ifdef _KERNEL
897090df5aSMatthew Dillon 
907090df5aSMatthew Dillon #include <sys/param.h>
917090df5aSMatthew Dillon #include <sys/systm.h>
927090df5aSMatthew Dillon #include <sys/lock.h>
937090df5aSMatthew Dillon #include <sys/kernel.h>
947090df5aSMatthew Dillon #include <sys/blist.h>
957090df5aSMatthew Dillon #include <sys/malloc.h>
96d027ed2eSAlan Cox #include <sys/sbuf.h>
970cddd8f0SMatthew Dillon #include <sys/proc.h>
9823955314SAlfred Perlstein #include <sys/mutex.h>
997090df5aSMatthew Dillon 
1007090df5aSMatthew Dillon #else
1017090df5aSMatthew Dillon 
1027090df5aSMatthew Dillon #ifndef BLIST_NO_DEBUG
1037090df5aSMatthew Dillon #define BLIST_DEBUG
1047090df5aSMatthew Dillon #endif
1057090df5aSMatthew Dillon 
106bb4a27f9SMark Johnston #include <sys/errno.h>
1077090df5aSMatthew Dillon #include <sys/types.h>
108d90bf7d8SAlan Cox #include <sys/malloc.h>
109d027ed2eSAlan Cox #include <sys/sbuf.h>
110b1f59c92SDoug Moore #include <assert.h>
1117090df5aSMatthew Dillon #include <stdio.h>
1127090df5aSMatthew Dillon #include <string.h>
1138eefcd40SAlan Cox #include <stddef.h>
1147090df5aSMatthew Dillon #include <stdlib.h>
1157090df5aSMatthew Dillon #include <stdarg.h>
116d3783724SAlan Cox #include <stdbool.h>
1177090df5aSMatthew Dillon 
1184be4fd5dSAlan Cox #define	bitcount64(x)	__bitcount64((uint64_t)(x))
11992da00bbSMatthew Dillon #define malloc(a,b,c)	calloc(a, 1)
1207090df5aSMatthew Dillon #define free(a,b)	free(a)
121bb4a27f9SMark Johnston #define ummin(a,b)	((a) < (b) ? (a) : (b))
12231c82722SDoug Moore #define imin(a,b)	((a) < (b) ? (a) : (b))
123b1f59c92SDoug Moore #define KASSERT(a,b)	assert(a)
1247090df5aSMatthew Dillon 
1257090df5aSMatthew Dillon #include <sys/blist.h>
1267090df5aSMatthew Dillon 
1277090df5aSMatthew Dillon #endif
1287090df5aSMatthew Dillon 
1297090df5aSMatthew Dillon /*
1307090df5aSMatthew Dillon  * static support functions
1317090df5aSMatthew Dillon  */
13287ae0686SDoug Moore static daddr_t	blst_leaf_alloc(blmeta_t *scan, daddr_t blk,
13387ae0686SDoug Moore     int *count, int maxcount);
13487ae0686SDoug Moore static daddr_t	blst_meta_alloc(blmeta_t *scan, daddr_t cursor, int *count,
13587ae0686SDoug Moore     int maxcount, u_daddr_t radix);
1367090df5aSMatthew Dillon static void blst_leaf_free(blmeta_t *scan, daddr_t relblk, int count);
1377090df5aSMatthew Dillon static void blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count,
138bee93d3cSAlan Cox 		    u_daddr_t radix);
1397090df5aSMatthew Dillon static void blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix,
1402ac0c7c3SAlan Cox 		    blist_t dest, daddr_t count);
141a7249a6cSAlan Cox static daddr_t blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count);
142a7249a6cSAlan Cox static daddr_t blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count,
143bee93d3cSAlan Cox 		    u_daddr_t radix);
144c4473420SPeter Wemm #ifndef _KERNEL
145d3783724SAlan Cox static void	blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix,
1462ac0c7c3SAlan Cox 		    int tab);
1477090df5aSMatthew Dillon #endif
1487090df5aSMatthew Dillon 
149c4473420SPeter Wemm #ifdef _KERNEL
1507090df5aSMatthew Dillon static MALLOC_DEFINE(M_SWAP, "SWAP", "Swap space");
1517090df5aSMatthew Dillon #endif
1527090df5aSMatthew Dillon 
15300fd73d2SDoug Moore #define	BLIST_MASK	(BLIST_RADIX - 1)
154ba98e6a2SAlan Cox 
1557090df5aSMatthew Dillon /*
1562ac0c7c3SAlan Cox  * For a subtree that can represent the state of up to 'radix' blocks, the
15700fd73d2SDoug Moore  * number of leaf nodes of the subtree is L=radix/BLIST_RADIX.  If 'm'
15800fd73d2SDoug Moore  * is short for BLIST_RADIX, then for a tree of height h with L=m**h
1592ac0c7c3SAlan Cox  * leaf nodes, the total number of tree nodes is 1 + m + m**2 + ... + m**h,
1602ac0c7c3SAlan Cox  * or, equivalently, (m**(h+1)-1)/(m-1).  This quantity is called 'skip'
1612ac0c7c3SAlan Cox  * in the 'meta' functions that process subtrees.  Since integer division
1622ac0c7c3SAlan Cox  * discards remainders, we can express this computation as
1632ac0c7c3SAlan Cox  * skip = (m * m**h) / (m - 1)
16400fd73d2SDoug Moore  * skip = (m * (radix / m)) / (m - 1)
16500fd73d2SDoug Moore  * skip = radix / (m - 1)
166ba98e6a2SAlan Cox  * so that simple integer division by a constant can safely be used for the
167ba98e6a2SAlan Cox  * calculation.
1682ac0c7c3SAlan Cox  */
1692ac0c7c3SAlan Cox static inline daddr_t
1702ac0c7c3SAlan Cox radix_to_skip(daddr_t radix)
1712ac0c7c3SAlan Cox {
1722ac0c7c3SAlan Cox 
17300fd73d2SDoug Moore 	return (radix / BLIST_MASK);
174d027ed2eSAlan Cox }
175d027ed2eSAlan Cox 
176d027ed2eSAlan Cox /*
177bb4a27f9SMark Johnston  * Provide a mask with count bits set, starting as position n.
178bb4a27f9SMark Johnston  */
179bb4a27f9SMark Johnston static inline u_daddr_t
180bb4a27f9SMark Johnston bitrange(int n, int count)
181bb4a27f9SMark Johnston {
182bb4a27f9SMark Johnston 
183bb4a27f9SMark Johnston 	return (((u_daddr_t)-1 << n) &
18400fd73d2SDoug Moore 	    ((u_daddr_t)-1 >> (BLIST_RADIX - (n + count))));
185bb4a27f9SMark Johnston }
186bb4a27f9SMark Johnston 
18753519253SDoug Moore static inline int
1884ab18ea2SDoug Moore bitpos(u_daddr_t mask)
1894ab18ea2SDoug Moore {
1904ab18ea2SDoug Moore 
191*d4e236c7SDoug Moore 	_Static_assert(sizeof(long long) >= sizeof(mask),
192*d4e236c7SDoug Moore 	    "mask too big for ffsll()");
19312cd7dedSDoug Moore 	return (ffsll(mask) - 1);
1942ac0c7c3SAlan Cox }
1952ac0c7c3SAlan Cox 
1962ac0c7c3SAlan Cox /*
1977090df5aSMatthew Dillon  * blist_create() - create a blist capable of handling up to the specified
1987090df5aSMatthew Dillon  *		    number of blocks
1997090df5aSMatthew Dillon  *
200f565f395SEitan Adler  *	blocks - must be greater than 0
201c8c7ad92SKip Macy  * 	flags  - malloc flags
2027090df5aSMatthew Dillon  *
2037090df5aSMatthew Dillon  *	The smallest blist consists of a single leaf node capable of
20400fd73d2SDoug Moore  *	managing BLIST_RADIX blocks.
2057090df5aSMatthew Dillon  */
2067090df5aSMatthew Dillon blist_t
207c8c7ad92SKip Macy blist_create(daddr_t blocks, int flags)
2087090df5aSMatthew Dillon {
2097090df5aSMatthew Dillon 	blist_t bl;
210bb4a27f9SMark Johnston 	u_daddr_t nodes, radix;
2117090df5aSMatthew Dillon 
212b1f59c92SDoug Moore 	KASSERT(blocks > 0, ("invalid block count"));
213ce9eea64SMark Johnston 
2147090df5aSMatthew Dillon 	/*
215ce9eea64SMark Johnston 	 * Calculate the radix and node count used for scanning.
2167090df5aSMatthew Dillon 	 */
217bb4a27f9SMark Johnston 	nodes = 1;
2182783335cSMark Johnston 	for (radix = 1; (blocks - 1) / BLIST_RADIX / radix > 0;
2192783335cSMark Johnston 	    radix *= BLIST_RADIX)
2202783335cSMark Johnston 		nodes += 1 + (blocks - 1) / BLIST_RADIX / radix;
2212783335cSMark Johnston 
2222783335cSMark Johnston 	/*
2232783335cSMark Johnston 	 * Include a sentinel node to ensure that cross-leaf scans stay within
2242783335cSMark Johnston 	 * the bounds of the allocation.
2252783335cSMark Johnston 	 */
2262783335cSMark Johnston 	if (blocks % BLIST_RADIX == 0)
2272783335cSMark Johnston 		nodes++;
2287090df5aSMatthew Dillon 
22903ca2137SAlan Cox 	bl = malloc(offsetof(struct blist, bl_root[nodes]), M_SWAP, flags |
23003ca2137SAlan Cox 	    M_ZERO);
231015d7db6SAlan Cox 	if (bl == NULL)
232015d7db6SAlan Cox 		return (NULL);
2337090df5aSMatthew Dillon 
2347090df5aSMatthew Dillon 	bl->bl_blocks = blocks;
2357090df5aSMatthew Dillon 	bl->bl_radix = radix;
2367090df5aSMatthew Dillon 
2377090df5aSMatthew Dillon #if defined(BLIST_DEBUG)
2387090df5aSMatthew Dillon 	printf(
23992da00bbSMatthew Dillon 		"BLIST representing %lld blocks (%lld MB of swap)"
24092da00bbSMatthew Dillon 		", requiring %lldK of ram\n",
24192da00bbSMatthew Dillon 		(long long)bl->bl_blocks,
24292da00bbSMatthew Dillon 		(long long)bl->bl_blocks * 4 / 1024,
243015d7db6SAlan Cox 		(long long)(nodes * sizeof(blmeta_t) + 1023) / 1024
2447090df5aSMatthew Dillon 	);
24592da00bbSMatthew Dillon 	printf("BLIST raw radix tree contains %lld records\n",
246015d7db6SAlan Cox 	    (long long)nodes);
2477090df5aSMatthew Dillon #endif
2487090df5aSMatthew Dillon 
2497090df5aSMatthew Dillon 	return (bl);
2507090df5aSMatthew Dillon }
2517090df5aSMatthew Dillon 
2527090df5aSMatthew Dillon void
2537090df5aSMatthew Dillon blist_destroy(blist_t bl)
2547090df5aSMatthew Dillon {
2558eefcd40SAlan Cox 
2567090df5aSMatthew Dillon 	free(bl, M_SWAP);
2577090df5aSMatthew Dillon }
2587090df5aSMatthew Dillon 
2597090df5aSMatthew Dillon /*
2607090df5aSMatthew Dillon  * blist_alloc() -   reserve space in the block bitmap.  Return the base
2617090df5aSMatthew Dillon  *		     of a contiguous region or SWAPBLK_NONE if space could
2627090df5aSMatthew Dillon  *		     not be allocated.
2637090df5aSMatthew Dillon  */
2647090df5aSMatthew Dillon daddr_t
26587ae0686SDoug Moore blist_alloc(blist_t bl, int *count, int maxcount)
2667090df5aSMatthew Dillon {
26727d172bbSDoug Moore 	daddr_t blk, cursor;
2687090df5aSMatthew Dillon 
26987ae0686SDoug Moore 	KASSERT(*count <= maxcount,
27087ae0686SDoug Moore 	    ("invalid parameters %d > %d", *count, maxcount));
27131c82722SDoug Moore 	KASSERT(*count <= BLIST_MAX_ALLOC,
27231c82722SDoug Moore 	    ("minimum allocation too large: %d", *count));
273bb4a27f9SMark Johnston 
274d4e3484bSAlan Cox 	/*
275d4e3484bSAlan Cox 	 * This loop iterates at most twice.  An allocation failure in the
276d4e3484bSAlan Cox 	 * first iteration leads to a second iteration only if the cursor was
277d4e3484bSAlan Cox 	 * non-zero.  When the cursor is zero, an allocation failure will
278749cdf6fSAlan Cox 	 * stop further iterations.
279d4e3484bSAlan Cox 	 */
28087ae0686SDoug Moore 	for (cursor = bl->bl_cursor;; cursor = 0) {
28187ae0686SDoug Moore 		blk = blst_meta_alloc(bl->bl_root, cursor, count, maxcount,
282bee93d3cSAlan Cox 		    bl->bl_radix);
283d4e3484bSAlan Cox 		if (blk != SWAPBLK_NONE) {
28487ae0686SDoug Moore 			bl->bl_avail -= *count;
28587ae0686SDoug Moore 			bl->bl_cursor = blk + *count;
286a0ae476bSAlan Cox 			if (bl->bl_cursor == bl->bl_blocks)
287a0ae476bSAlan Cox 				bl->bl_cursor = 0;
2887090df5aSMatthew Dillon 			return (blk);
28987ae0686SDoug Moore 		}
29087ae0686SDoug Moore 		if (cursor == 0)
291749cdf6fSAlan Cox 			return (SWAPBLK_NONE);
2927090df5aSMatthew Dillon 	}
2934be4fd5dSAlan Cox }
2944be4fd5dSAlan Cox 
2954be4fd5dSAlan Cox /*
2964be4fd5dSAlan Cox  * blist_avail() -	return the number of free blocks.
2974be4fd5dSAlan Cox  */
2984be4fd5dSAlan Cox daddr_t
2994be4fd5dSAlan Cox blist_avail(blist_t bl)
3004be4fd5dSAlan Cox {
3014be4fd5dSAlan Cox 
302bb4a27f9SMark Johnston 	return (bl->bl_avail);
3034be4fd5dSAlan Cox }
3047090df5aSMatthew Dillon 
3057090df5aSMatthew Dillon /*
3067090df5aSMatthew Dillon  * blist_free() -	free up space in the block bitmap.  Return the base
307b1f59c92SDoug Moore  *		     	of a contiguous region.
3087090df5aSMatthew Dillon  */
3097090df5aSMatthew Dillon void
3107090df5aSMatthew Dillon blist_free(blist_t bl, daddr_t blkno, daddr_t count)
3117090df5aSMatthew Dillon {
312a396c83aSAlan Cox 
313b1f59c92SDoug Moore 	KASSERT(blkno >= 0 && blkno + count <= bl->bl_blocks,
314b1f59c92SDoug Moore 	    ("freeing invalid range: blkno %jx, count %d, blocks %jd",
315b1f59c92SDoug Moore 	    (uintmax_t)blkno, (int)count, (uintmax_t)bl->bl_blocks));
316bee93d3cSAlan Cox 	blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix);
317bb4a27f9SMark Johnston 	bl->bl_avail += count;
3187090df5aSMatthew Dillon }
3197090df5aSMatthew Dillon 
3207090df5aSMatthew Dillon /*
32192da00bbSMatthew Dillon  * blist_fill() -	mark a region in the block bitmap as off-limits
32292da00bbSMatthew Dillon  *			to the allocator (i.e. allocate it), ignoring any
32392da00bbSMatthew Dillon  *			existing allocations.  Return the number of blocks
32492da00bbSMatthew Dillon  *			actually filled that were free before the call.
32592da00bbSMatthew Dillon  */
326a7249a6cSAlan Cox daddr_t
32792da00bbSMatthew Dillon blist_fill(blist_t bl, daddr_t blkno, daddr_t count)
32892da00bbSMatthew Dillon {
329bb4a27f9SMark Johnston 	daddr_t filled;
33092da00bbSMatthew Dillon 
331b1f59c92SDoug Moore 	KASSERT(blkno >= 0 && blkno + count <= bl->bl_blocks,
332b1f59c92SDoug Moore 	    ("filling invalid range: blkno %jx, count %d, blocks %jd",
333b1f59c92SDoug Moore 	    (uintmax_t)blkno, (int)count, (uintmax_t)bl->bl_blocks));
334bb4a27f9SMark Johnston 	filled = blst_meta_fill(bl->bl_root, blkno, count, bl->bl_radix);
335bb4a27f9SMark Johnston 	bl->bl_avail -= filled;
336bb4a27f9SMark Johnston 	return (filled);
33792da00bbSMatthew Dillon }
33892da00bbSMatthew Dillon 
33992da00bbSMatthew Dillon /*
3407090df5aSMatthew Dillon  * blist_resize() -	resize an existing radix tree to handle the
3417090df5aSMatthew Dillon  *			specified number of blocks.  This will reallocate
3427090df5aSMatthew Dillon  *			the tree and transfer the previous bitmap to the new
3437090df5aSMatthew Dillon  *			one.  When extending the tree you can specify whether
3447090df5aSMatthew Dillon  *			the new blocks are to left allocated or freed.
3457090df5aSMatthew Dillon  */
3467090df5aSMatthew Dillon void
347c8c7ad92SKip Macy blist_resize(blist_t *pbl, daddr_t count, int freenew, int flags)
3487090df5aSMatthew Dillon {
349c8c7ad92SKip Macy     blist_t newbl = blist_create(count, flags);
3507090df5aSMatthew Dillon     blist_t save = *pbl;
3517090df5aSMatthew Dillon 
3527090df5aSMatthew Dillon     *pbl = newbl;
3537090df5aSMatthew Dillon     if (count > save->bl_blocks)
3547090df5aSMatthew Dillon 	    count = save->bl_blocks;
3552ac0c7c3SAlan Cox     blst_copy(save->bl_root, 0, save->bl_radix, newbl, count);
3567090df5aSMatthew Dillon 
3577090df5aSMatthew Dillon     /*
3587090df5aSMatthew Dillon      * If resizing upwards, should we free the new space or not?
3597090df5aSMatthew Dillon      */
3607090df5aSMatthew Dillon     if (freenew && count < newbl->bl_blocks) {
3617090df5aSMatthew Dillon 	    blist_free(newbl, count, newbl->bl_blocks - count);
3627090df5aSMatthew Dillon     }
3637090df5aSMatthew Dillon     blist_destroy(save);
3647090df5aSMatthew Dillon }
3657090df5aSMatthew Dillon 
3667090df5aSMatthew Dillon #ifdef BLIST_DEBUG
3677090df5aSMatthew Dillon 
3687090df5aSMatthew Dillon /*
3697090df5aSMatthew Dillon  * blist_print()    - dump radix tree
3707090df5aSMatthew Dillon  */
3717090df5aSMatthew Dillon void
3727090df5aSMatthew Dillon blist_print(blist_t bl)
3737090df5aSMatthew Dillon {
374bb4a27f9SMark Johnston 	printf("BLIST avail = %jd, cursor = %08jx {\n",
375bb4a27f9SMark Johnston 	    (uintmax_t)bl->bl_avail, (uintmax_t)bl->bl_cursor);
376bb4a27f9SMark Johnston 
377bb4a27f9SMark Johnston 	if (bl->bl_root->bm_bitmap != 0)
3782ac0c7c3SAlan Cox 		blst_radix_print(bl->bl_root, 0, bl->bl_radix, 4);
3797090df5aSMatthew Dillon 	printf("}\n");
3807090df5aSMatthew Dillon }
3817090df5aSMatthew Dillon 
3827090df5aSMatthew Dillon #endif
3837090df5aSMatthew Dillon 
384d027ed2eSAlan Cox static const u_daddr_t fib[] = {
385d027ed2eSAlan Cox 	1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584,
386d027ed2eSAlan Cox 	4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811,
387d027ed2eSAlan Cox 	514229, 832040, 1346269, 2178309, 3524578,
388d027ed2eSAlan Cox };
389d027ed2eSAlan Cox 
390d027ed2eSAlan Cox /*
391d027ed2eSAlan Cox  * Use 'gap' to describe a maximal range of unallocated blocks/bits.
392d027ed2eSAlan Cox  */
393d027ed2eSAlan Cox struct gap_stats {
394d027ed2eSAlan Cox 	daddr_t	start;		/* current gap start, or SWAPBLK_NONE */
395d027ed2eSAlan Cox 	daddr_t	num;		/* number of gaps observed */
396d027ed2eSAlan Cox 	daddr_t	max;		/* largest gap size */
397d027ed2eSAlan Cox 	daddr_t	avg;		/* average gap size */
398d027ed2eSAlan Cox 	daddr_t	err;		/* sum - num * avg */
399d027ed2eSAlan Cox 	daddr_t	histo[nitems(fib)]; /* # gaps in each size range */
400d027ed2eSAlan Cox 	int	max_bucket;	/* last histo elt with nonzero val */
401d027ed2eSAlan Cox };
402d027ed2eSAlan Cox 
403d027ed2eSAlan Cox /*
404d027ed2eSAlan Cox  * gap_stats_counting()    - is the state 'counting 1 bits'?
405d027ed2eSAlan Cox  *                           or 'skipping 0 bits'?
406d027ed2eSAlan Cox  */
407d027ed2eSAlan Cox static inline bool
408d027ed2eSAlan Cox gap_stats_counting(const struct gap_stats *stats)
409d027ed2eSAlan Cox {
410d027ed2eSAlan Cox 
411d027ed2eSAlan Cox 	return (stats->start != SWAPBLK_NONE);
412d027ed2eSAlan Cox }
413d027ed2eSAlan Cox 
414d027ed2eSAlan Cox /*
415d027ed2eSAlan Cox  * init_gap_stats()    - initialize stats on gap sizes
416d027ed2eSAlan Cox  */
417d027ed2eSAlan Cox static inline void
418d027ed2eSAlan Cox init_gap_stats(struct gap_stats *stats)
419d027ed2eSAlan Cox {
420d027ed2eSAlan Cox 
421d027ed2eSAlan Cox 	bzero(stats, sizeof(*stats));
422d027ed2eSAlan Cox 	stats->start = SWAPBLK_NONE;
423d027ed2eSAlan Cox }
424d027ed2eSAlan Cox 
425d027ed2eSAlan Cox /*
426d027ed2eSAlan Cox  * update_gap_stats()    - update stats on gap sizes
427d027ed2eSAlan Cox  */
428d027ed2eSAlan Cox static void
429d027ed2eSAlan Cox update_gap_stats(struct gap_stats *stats, daddr_t posn)
430d027ed2eSAlan Cox {
431d027ed2eSAlan Cox 	daddr_t size;
432d027ed2eSAlan Cox 	int hi, lo, mid;
433d027ed2eSAlan Cox 
434d027ed2eSAlan Cox 	if (!gap_stats_counting(stats)) {
435d027ed2eSAlan Cox 		stats->start = posn;
436d027ed2eSAlan Cox 		return;
437d027ed2eSAlan Cox 	}
438d027ed2eSAlan Cox 	size = posn - stats->start;
439d027ed2eSAlan Cox 	stats->start = SWAPBLK_NONE;
440d027ed2eSAlan Cox 	if (size > stats->max)
441d027ed2eSAlan Cox 		stats->max = size;
442d027ed2eSAlan Cox 
443d027ed2eSAlan Cox 	/*
444d027ed2eSAlan Cox 	 * Find the fibonacci range that contains size,
445d027ed2eSAlan Cox 	 * expecting to find it in an early range.
446d027ed2eSAlan Cox 	 */
447d027ed2eSAlan Cox 	lo = 0;
448d027ed2eSAlan Cox 	hi = 1;
449d027ed2eSAlan Cox 	while (hi < nitems(fib) && fib[hi] <= size) {
450d027ed2eSAlan Cox 		lo = hi;
451d027ed2eSAlan Cox 		hi *= 2;
452d027ed2eSAlan Cox 	}
453d027ed2eSAlan Cox 	if (hi >= nitems(fib))
454d027ed2eSAlan Cox 		hi = nitems(fib);
455d027ed2eSAlan Cox 	while (lo + 1 != hi) {
456d027ed2eSAlan Cox 		mid = (lo + hi) >> 1;
457d027ed2eSAlan Cox 		if (fib[mid] <= size)
458d027ed2eSAlan Cox 			lo = mid;
459d027ed2eSAlan Cox 		else
460d027ed2eSAlan Cox 			hi = mid;
461d027ed2eSAlan Cox 	}
462d027ed2eSAlan Cox 	stats->histo[lo]++;
463d027ed2eSAlan Cox 	if (lo > stats->max_bucket)
464d027ed2eSAlan Cox 		stats->max_bucket = lo;
465d027ed2eSAlan Cox 	stats->err += size - stats->avg;
466d027ed2eSAlan Cox 	stats->num++;
467d027ed2eSAlan Cox 	stats->avg += stats->err / stats->num;
468d027ed2eSAlan Cox 	stats->err %= stats->num;
469d027ed2eSAlan Cox }
470d027ed2eSAlan Cox 
471d027ed2eSAlan Cox /*
472d027ed2eSAlan Cox  * dump_gap_stats()    - print stats on gap sizes
473d027ed2eSAlan Cox  */
474d027ed2eSAlan Cox static inline void
475d027ed2eSAlan Cox dump_gap_stats(const struct gap_stats *stats, struct sbuf *s)
476d027ed2eSAlan Cox {
477d027ed2eSAlan Cox 	int i;
478d027ed2eSAlan Cox 
479d027ed2eSAlan Cox 	sbuf_printf(s, "number of maximal free ranges: %jd\n",
480d027ed2eSAlan Cox 	    (intmax_t)stats->num);
481d027ed2eSAlan Cox 	sbuf_printf(s, "largest free range: %jd\n", (intmax_t)stats->max);
482d027ed2eSAlan Cox 	sbuf_printf(s, "average maximal free range size: %jd\n",
483d027ed2eSAlan Cox 	    (intmax_t)stats->avg);
484d027ed2eSAlan Cox 	sbuf_printf(s, "number of maximal free ranges of different sizes:\n");
485d027ed2eSAlan Cox 	sbuf_printf(s, "               count  |  size range\n");
486d027ed2eSAlan Cox 	sbuf_printf(s, "               -----  |  ----------\n");
487d027ed2eSAlan Cox 	for (i = 0; i < stats->max_bucket; i++) {
488d027ed2eSAlan Cox 		if (stats->histo[i] != 0) {
489d027ed2eSAlan Cox 			sbuf_printf(s, "%20jd  |  ",
490d027ed2eSAlan Cox 			    (intmax_t)stats->histo[i]);
491d027ed2eSAlan Cox 			if (fib[i] != fib[i + 1] - 1)
492d027ed2eSAlan Cox 				sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i],
493d027ed2eSAlan Cox 				    (intmax_t)fib[i + 1] - 1);
494d027ed2eSAlan Cox 			else
495d027ed2eSAlan Cox 				sbuf_printf(s, "%jd\n", (intmax_t)fib[i]);
496d027ed2eSAlan Cox 		}
497d027ed2eSAlan Cox 	}
498d027ed2eSAlan Cox 	sbuf_printf(s, "%20jd  |  ", (intmax_t)stats->histo[i]);
499d027ed2eSAlan Cox 	if (stats->histo[i] > 1)
500d027ed2eSAlan Cox 		sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i],
501d027ed2eSAlan Cox 		    (intmax_t)stats->max);
502d027ed2eSAlan Cox 	else
503d027ed2eSAlan Cox 		sbuf_printf(s, "%jd\n", (intmax_t)stats->max);
504d027ed2eSAlan Cox }
505d027ed2eSAlan Cox 
506d027ed2eSAlan Cox /*
507d027ed2eSAlan Cox  * blist_stats()    - dump radix tree stats
508d027ed2eSAlan Cox  */
509d027ed2eSAlan Cox void
510d027ed2eSAlan Cox blist_stats(blist_t bl, struct sbuf *s)
511d027ed2eSAlan Cox {
512d027ed2eSAlan Cox 	struct gap_stats gstats;
513d027ed2eSAlan Cox 	struct gap_stats *stats = &gstats;
514d027ed2eSAlan Cox 	daddr_t i, nodes, radix;
51553519253SDoug Moore 	u_daddr_t diff, mask;
51653519253SDoug Moore 	int digit;
517d027ed2eSAlan Cox 
518d027ed2eSAlan Cox 	init_gap_stats(stats);
519d027ed2eSAlan Cox 	nodes = 0;
52000fd73d2SDoug Moore 	radix = bl->bl_radix;
52100fd73d2SDoug Moore 	for (i = 0; i < bl->bl_blocks; ) {
522d027ed2eSAlan Cox 		/*
523d027ed2eSAlan Cox 		 * Check for skippable subtrees starting at i.
524d027ed2eSAlan Cox 		 */
52500fd73d2SDoug Moore 		while (radix != 1) {
526bb4a27f9SMark Johnston 			if (bl->bl_root[nodes].bm_bitmap == 0) {
527d027ed2eSAlan Cox 				if (gap_stats_counting(stats))
528d027ed2eSAlan Cox 					update_gap_stats(stats, i);
529d027ed2eSAlan Cox 				break;
530d027ed2eSAlan Cox 			}
531d027ed2eSAlan Cox 
532d027ed2eSAlan Cox 			/*
533d027ed2eSAlan Cox 			 * Skip subtree root.
534d027ed2eSAlan Cox 			 */
535d027ed2eSAlan Cox 			nodes++;
53600fd73d2SDoug Moore 			radix /= BLIST_RADIX;
537d027ed2eSAlan Cox 		}
53800fd73d2SDoug Moore 		if (radix == 1) {
539d027ed2eSAlan Cox 			/*
540d027ed2eSAlan Cox 			 * Scan leaf.
541d027ed2eSAlan Cox 			 */
542bb4a27f9SMark Johnston 			mask = bl->bl_root[nodes].bm_bitmap;
543d027ed2eSAlan Cox 			diff = mask ^ (mask << 1);
544d027ed2eSAlan Cox 			if (gap_stats_counting(stats))
545d027ed2eSAlan Cox 				diff ^= 1;
546d027ed2eSAlan Cox 			while (diff != 0) {
54753519253SDoug Moore 				digit = bitpos(diff);
54853519253SDoug Moore 				update_gap_stats(stats, i + digit);
54953519253SDoug Moore 				diff ^= bitrange(digit, 1);
550d027ed2eSAlan Cox 			}
551d027ed2eSAlan Cox 		}
55200fd73d2SDoug Moore 		nodes += radix_to_skip(radix * BLIST_RADIX);
55300fd73d2SDoug Moore 		i += radix * BLIST_RADIX;
55400fd73d2SDoug Moore 
55500fd73d2SDoug Moore 		/*
55600fd73d2SDoug Moore 		 * Find max size subtree starting at i.
55700fd73d2SDoug Moore 		 */
55800fd73d2SDoug Moore 		for (radix = 1;
55900fd73d2SDoug Moore 		    ((i / BLIST_RADIX / radix) & BLIST_MASK) == 0;
56000fd73d2SDoug Moore 		    radix *= BLIST_RADIX)
56100fd73d2SDoug Moore 			;
562d027ed2eSAlan Cox 	}
563d027ed2eSAlan Cox 	update_gap_stats(stats, i);
564d027ed2eSAlan Cox 	dump_gap_stats(stats, s);
565d027ed2eSAlan Cox }
566d027ed2eSAlan Cox 
5677090df5aSMatthew Dillon /************************************************************************
5687090df5aSMatthew Dillon  *			  ALLOCATION SUPPORT FUNCTIONS			*
5697090df5aSMatthew Dillon  ************************************************************************
5707090df5aSMatthew Dillon  *
5717090df5aSMatthew Dillon  *	These support functions do all the actual work.  They may seem
5727090df5aSMatthew Dillon  *	rather longish, but that's because I've commented them up.  The
5737090df5aSMatthew Dillon  *	actual code is straight forward.
5747090df5aSMatthew Dillon  *
5757090df5aSMatthew Dillon  */
5767090df5aSMatthew Dillon 
5777090df5aSMatthew Dillon /*
57831c82722SDoug Moore  * BLST_NEXT_LEAF_ALLOC() - allocate the blocks starting with the next leaf.
579bb4a27f9SMark Johnston  *
58031c82722SDoug Moore  *	'scan' is a leaf node, and its first block is at address 'start'.  The
58131c82722SDoug Moore  *	next leaf node could be adjacent, or several nodes away if the least
58231c82722SDoug Moore  *	common ancestor of 'scan' and its neighbor is several levels up.  Use
58331c82722SDoug Moore  *	addresses to determine how many meta-nodes lie between the leaves.  If
58431c82722SDoug Moore  *	sequence of leaves starting with the next one has enough initial bits
58531c82722SDoug Moore  *	set, clear them and clear the bits in the meta nodes on the path up to
58631c82722SDoug Moore  *	the least common ancestor to mark any subtrees made completely empty.
587bb4a27f9SMark Johnston  */
588bb4a27f9SMark Johnston static int
58931c82722SDoug Moore blst_next_leaf_alloc(blmeta_t *scan, daddr_t start, int count, int maxcount)
590bb4a27f9SMark Johnston {
591bb4a27f9SMark Johnston 	u_daddr_t radix;
59231c82722SDoug Moore 	daddr_t blk;
59387ae0686SDoug Moore 	int avail, digit;
594bb4a27f9SMark Johnston 
59500fd73d2SDoug Moore 	start += BLIST_RADIX;
59600fd73d2SDoug Moore 	for (blk = start; blk - start < maxcount; blk += BLIST_RADIX) {
59731c82722SDoug Moore 		/* Skip meta-nodes, as long as they promise more free blocks. */
59800fd73d2SDoug Moore 		radix = BLIST_RADIX;
59931c82722SDoug Moore 		while (((++scan)->bm_bitmap & 1) == 1 &&
60000fd73d2SDoug Moore 		    ((blk / radix) & BLIST_MASK) == 0)
60100fd73d2SDoug Moore 			radix *= BLIST_RADIX;
60231c82722SDoug Moore 		if (~scan->bm_bitmap != 0) {
60331c82722SDoug Moore 			/*
60431c82722SDoug Moore 			 * Either there is no next leaf with any free blocks,
60531c82722SDoug Moore 			 * or we've reached the next leaf and found that some
60631c82722SDoug Moore 			 * of its blocks are not free.  In the first case,
60731c82722SDoug Moore 			 * bitpos() returns zero here.
60831c82722SDoug Moore 			 */
60931c82722SDoug Moore 			avail = blk - start + bitpos(~scan->bm_bitmap);
6103f3f7c05SDoug Moore 			if (avail < count || avail == 0) {
611bb4a27f9SMark Johnston 				/*
61231c82722SDoug Moore 				 * There isn't a next leaf with enough free
6133f3f7c05SDoug Moore 				 * blocks at its beginning to bother
6143f3f7c05SDoug Moore 				 * allocating.
615bb4a27f9SMark Johnston 				 */
61631c82722SDoug Moore 				return (avail);
617bb4a27f9SMark Johnston 			}
61831c82722SDoug Moore 			maxcount = imin(avail, maxcount);
61900fd73d2SDoug Moore 			if (maxcount % BLIST_RADIX == 0) {
6203f3f7c05SDoug Moore 				/*
6213f3f7c05SDoug Moore 				 * There was no next leaf.  Back scan up to
6223f3f7c05SDoug Moore 				 * last leaf.
6233f3f7c05SDoug Moore 				 */
62400fd73d2SDoug Moore 				do {
62500fd73d2SDoug Moore 					radix /= BLIST_RADIX;
6263f3f7c05SDoug Moore 					--scan;
62700fd73d2SDoug Moore 				} while (radix != 1);
62800fd73d2SDoug Moore 				blk -= BLIST_RADIX;
6293f3f7c05SDoug Moore 			}
63031c82722SDoug Moore 		}
63131c82722SDoug Moore 	}
632bb4a27f9SMark Johnston 
633bb4a27f9SMark Johnston 	/*
63431c82722SDoug Moore 	 * 'scan' is the last leaf that provides blocks.  Clear from 1 to
63500fd73d2SDoug Moore 	 * BLIST_RADIX bits to represent the allocation of those last blocks.
636bb4a27f9SMark Johnston 	 */
63700fd73d2SDoug Moore 	if (maxcount % BLIST_RADIX != 0)
63800fd73d2SDoug Moore 		scan->bm_bitmap &= ~bitrange(0, maxcount % BLIST_RADIX);
63931c82722SDoug Moore 	else
64031c82722SDoug Moore 		scan->bm_bitmap = 0;
64131c82722SDoug Moore 
64231c82722SDoug Moore 	for (;;) {
64331c82722SDoug Moore 		/* Back up over meta-nodes, clearing bits if necessary. */
64400fd73d2SDoug Moore 		blk -= BLIST_RADIX;
64500fd73d2SDoug Moore 		for (radix = BLIST_RADIX;
64600fd73d2SDoug Moore 		    (digit = ((blk / radix) & BLIST_MASK)) == 0;
64700fd73d2SDoug Moore 		    radix *= BLIST_RADIX) {
64831c82722SDoug Moore 			if ((scan--)->bm_bitmap == 0)
64931c82722SDoug Moore 				scan->bm_bitmap ^= 1;
65031c82722SDoug Moore 		}
65131c82722SDoug Moore 		if ((scan--)->bm_bitmap == 0)
652d1c34a6bSDoug Moore 			scan[-digit * radix_to_skip(radix)].bm_bitmap ^=
653d1c34a6bSDoug Moore 			    (u_daddr_t)1 << digit;
65431c82722SDoug Moore 
65531c82722SDoug Moore 		if (blk == start)
656d1c34a6bSDoug Moore 			break;
65731c82722SDoug Moore 		/* Clear all the bits of this leaf. */
65831c82722SDoug Moore 		scan->bm_bitmap = 0;
659bb4a27f9SMark Johnston 	}
66031c82722SDoug Moore 	return (maxcount);
661bb4a27f9SMark Johnston }
662bb4a27f9SMark Johnston 
663bb4a27f9SMark Johnston /*
664bb4a27f9SMark Johnston  * BLST_LEAF_ALLOC() -	allocate at a leaf in the radix tree (a bitmap).
6657090df5aSMatthew Dillon  *
6662905d1ceSAlan Cox  *	This function is the core of the allocator.  Its execution time is
6672905d1ceSAlan Cox  *	proportional to log(count), plus height of the tree if the allocation
6682905d1ceSAlan Cox  *	crosses a leaf boundary.
6697090df5aSMatthew Dillon  */
6707090df5aSMatthew Dillon static daddr_t
67187ae0686SDoug Moore blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int *count, int maxcount)
67254541421SAlan Cox {
6739f70442aSDoug Moore 	u_daddr_t mask;
6749f70442aSDoug Moore 	int bighint, count1, hi, lo, num_shifts;
6757090df5aSMatthew Dillon 
67687ae0686SDoug Moore 	count1 = *count - 1;
67754541421SAlan Cox 	num_shifts = fls(count1);
6789f70442aSDoug Moore 	mask = ~scan->bm_bitmap;
6799f70442aSDoug Moore 	while ((mask & (mask + 1)) != 0 && num_shifts > 0) {
68054541421SAlan Cox 		/*
6819f70442aSDoug Moore 		 * If bit i is 0 in mask, then bits in [i, i + (count1 >>
6829f70442aSDoug Moore 		 * num_shifts)] are 1 in scan->bm_bitmap.  Reduce num_shifts to
6839f70442aSDoug Moore 		 * 0, while preserving this invariant.  The updates to mask
6849f70442aSDoug Moore 		 * leave fewer bits 0, but each bit that remains 0 represents a
6859f70442aSDoug Moore 		 * longer string of consecutive 1-bits in scan->bm_bitmap.  If
6869f70442aSDoug Moore 		 * more updates to mask cannot set more bits, because mask is
6879f70442aSDoug Moore 		 * partitioned with all 1 bits following all 0 bits, the loop
6889f70442aSDoug Moore 		 * terminates immediately.
68954541421SAlan Cox 		 */
69054541421SAlan Cox 		num_shifts--;
6919f70442aSDoug Moore 		mask |= mask >> ((count1 >> num_shifts) + 1) / 2;
69254541421SAlan Cox 	}
6939f70442aSDoug Moore 	bighint = count1 >> num_shifts;
6949f70442aSDoug Moore 	if (~mask == 0) {
69554541421SAlan Cox 		/*
6969f70442aSDoug Moore 		 * Update bighint.  There is no allocation bigger than
6979f70442aSDoug Moore 		 * count1 >> num_shifts starting in this leaf.
69854541421SAlan Cox 		 */
6999f70442aSDoug Moore 		scan->bm_bighint = bighint;
7007090df5aSMatthew Dillon 		return (SWAPBLK_NONE);
7017090df5aSMatthew Dillon 	}
70254541421SAlan Cox 
703ec371b57SAlan Cox 	/* Discard any candidates that appear before blk. */
70400fd73d2SDoug Moore 	if ((blk & BLIST_MASK) != 0) {
70500fd73d2SDoug Moore 		if ((~mask & bitrange(0, blk & BLIST_MASK)) != 0) {
7069f70442aSDoug Moore 			/* Grow bighint in case all discarded bits are set. */
70700fd73d2SDoug Moore 			bighint += blk & BLIST_MASK;
70800fd73d2SDoug Moore 			mask |= bitrange(0, blk & BLIST_MASK);
7099f70442aSDoug Moore 			if (~mask == 0) {
7109f70442aSDoug Moore 				scan->bm_bighint = bighint;
71154541421SAlan Cox 				return (SWAPBLK_NONE);
7122905d1ceSAlan Cox 			}
7139f70442aSDoug Moore 		}
71400fd73d2SDoug Moore 		blk -= blk & BLIST_MASK;
7152905d1ceSAlan Cox 	}
7162905d1ceSAlan Cox 
7172905d1ceSAlan Cox 	/*
71854541421SAlan Cox 	 * The least significant set bit in mask marks the start of the first
71987ae0686SDoug Moore 	 * available range of sufficient size.  Find its position.
7207090df5aSMatthew Dillon 	 */
7219f70442aSDoug Moore 	lo = bitpos(~mask);
7227090df5aSMatthew Dillon 
72354541421SAlan Cox 	/*
72487ae0686SDoug Moore 	 * Find how much space is available starting at that position.
72554541421SAlan Cox 	 */
7269f70442aSDoug Moore 	if ((mask & (mask + 1)) != 0) {
72787ae0686SDoug Moore 		/* Count the 1 bits starting at position lo. */
7289f70442aSDoug Moore 		hi = bitpos(mask & (mask + 1)) + count1;
72987ae0686SDoug Moore 		if (maxcount < hi - lo)
73087ae0686SDoug Moore 			hi = lo + maxcount;
73187ae0686SDoug Moore 		*count = hi - lo;
7329f70442aSDoug Moore 		mask = ~bitrange(lo, *count);
73300fd73d2SDoug Moore 	} else if (maxcount <= BLIST_RADIX - lo) {
73487ae0686SDoug Moore 		/* All the blocks we can use are available here. */
73587ae0686SDoug Moore 		hi = lo + maxcount;
73687ae0686SDoug Moore 		*count = maxcount;
7379f70442aSDoug Moore 		mask = ~bitrange(lo, *count);
73800fd73d2SDoug Moore 		if (hi == BLIST_RADIX)
7399f70442aSDoug Moore 			scan->bm_bighint = bighint;
74087ae0686SDoug Moore 	} else {
74187ae0686SDoug Moore 		/* Check next leaf for some of the blocks we want or need. */
74200fd73d2SDoug Moore 		count1 = *count - (BLIST_RADIX - lo);
74300fd73d2SDoug Moore 		maxcount -= BLIST_RADIX - lo;
74487ae0686SDoug Moore 		hi = blst_next_leaf_alloc(scan, blk, count1, maxcount);
74587ae0686SDoug Moore 		if (hi < count1)
746ec371b57SAlan Cox 			/*
74787ae0686SDoug Moore 			 * The next leaf cannot supply enough blocks to reach
74887ae0686SDoug Moore 			 * the minimum required allocation.  The hint cannot be
74987ae0686SDoug Moore 			 * updated, because the same allocation request could
75087ae0686SDoug Moore 			 * be satisfied later, by this leaf, if the state of
75187ae0686SDoug Moore 			 * the next leaf changes, and without any changes to
75287ae0686SDoug Moore 			 * this leaf.
753ec371b57SAlan Cox 			 */
754ec371b57SAlan Cox 			return (SWAPBLK_NONE);
75500fd73d2SDoug Moore 		*count = BLIST_RADIX - lo + hi;
7569f70442aSDoug Moore 		scan->bm_bighint = bighint;
757ec371b57SAlan Cox 	}
758ec371b57SAlan Cox 
759ec371b57SAlan Cox 	/* Clear the allocated bits from this leaf. */
7609f70442aSDoug Moore 	scan->bm_bitmap &= mask;
7612905d1ceSAlan Cox 	return (blk + lo);
7627090df5aSMatthew Dillon }
7637090df5aSMatthew Dillon 
7647090df5aSMatthew Dillon /*
7657090df5aSMatthew Dillon  * blist_meta_alloc() -	allocate at a meta in the radix tree.
7667090df5aSMatthew Dillon  *
7677090df5aSMatthew Dillon  *	Attempt to allocate at a meta node.  If we can't, we update
7687090df5aSMatthew Dillon  *	bighint and return a failure.  Updating bighint optimize future
7697090df5aSMatthew Dillon  *	calls that hit this node.  We have to check for our collapse cases
7707090df5aSMatthew Dillon  *	and we have a few optimizations strewn in as well.
7717090df5aSMatthew Dillon  */
7727090df5aSMatthew Dillon static daddr_t
77387ae0686SDoug Moore blst_meta_alloc(blmeta_t *scan, daddr_t cursor, int *count,
77487ae0686SDoug Moore     int maxcount, u_daddr_t radix)
775d4e3484bSAlan Cox {
776bb4a27f9SMark Johnston 	daddr_t blk, i, r, skip;
77753519253SDoug Moore 	u_daddr_t mask;
778d4e3484bSAlan Cox 	bool scan_from_start;
779bb4a27f9SMark Johnston 	int digit;
7807090df5aSMatthew Dillon 
78100fd73d2SDoug Moore 	if (radix == 1)
78287ae0686SDoug Moore 		return (blst_leaf_alloc(scan, cursor, count, maxcount));
78300fd73d2SDoug Moore 	blk = cursor & -(radix * BLIST_RADIX);
784bb4a27f9SMark Johnston 	scan_from_start = (cursor == blk);
7852ac0c7c3SAlan Cox 	skip = radix_to_skip(radix);
786bb4a27f9SMark Johnston 	mask = scan->bm_bitmap;
787bb4a27f9SMark Johnston 
788bb4a27f9SMark Johnston 	/* Discard any candidates that appear before cursor. */
78900fd73d2SDoug Moore 	digit = (cursor / radix) & BLIST_MASK;
790bb4a27f9SMark Johnston 	mask &= (u_daddr_t)-1 << digit;
791ee73fef9SAlan Cox 	if (mask == 0)
792ee73fef9SAlan Cox 		return (SWAPBLK_NONE);
7937090df5aSMatthew Dillon 
7944be4fd5dSAlan Cox 	/*
795bb4a27f9SMark Johnston 	 * If the first try is for a block that includes the cursor, pre-undo
796bb4a27f9SMark Johnston 	 * the digit * radix offset in the first call; otherwise, ignore the
797bb4a27f9SMark Johnston 	 * cursor entirely.
7984be4fd5dSAlan Cox 	 */
799bb4a27f9SMark Johnston 	if (((mask >> digit) & 1) == 1)
800bb4a27f9SMark Johnston 		cursor -= digit * radix;
801d4e3484bSAlan Cox 	else
802bb4a27f9SMark Johnston 		cursor = blk;
8037090df5aSMatthew Dillon 
8044be4fd5dSAlan Cox 	/*
805bb4a27f9SMark Johnston 	 * Examine the nonempty subtree associated with each bit set in mask.
8064be4fd5dSAlan Cox 	 */
807bb4a27f9SMark Johnston 	do {
80853519253SDoug Moore 		digit = bitpos(mask);
809bb4a27f9SMark Johnston 		i = 1 + digit * skip;
81087ae0686SDoug Moore 		if (*count <= scan[i].bm_bighint) {
8117090df5aSMatthew Dillon 			/*
812ec371b57SAlan Cox 			 * The allocation might fit beginning in the i'th subtree.
8137090df5aSMatthew Dillon 			 */
814bb4a27f9SMark Johnston 			r = blst_meta_alloc(&scan[i], cursor + digit * radix,
81500fd73d2SDoug Moore 			    count, maxcount, radix / BLIST_RADIX);
8167090df5aSMatthew Dillon 			if (r != SWAPBLK_NONE) {
817bb4a27f9SMark Johnston 				if (scan[i].bm_bitmap == 0)
81853519253SDoug Moore 					scan->bm_bitmap ^= bitrange(digit, 1);
8197090df5aSMatthew Dillon 				return (r);
8207090df5aSMatthew Dillon 			}
8217090df5aSMatthew Dillon 		}
822bb4a27f9SMark Johnston 		cursor = blk;
82353519253SDoug Moore 	} while ((mask ^= bitrange(digit, 1)) != 0);
8247090df5aSMatthew Dillon 
8257090df5aSMatthew Dillon 	/*
826bb4a27f9SMark Johnston 	 * We couldn't allocate count in this subtree.  If the whole tree was
827bb4a27f9SMark Johnston 	 * scanned, and the last tree node is allocated, update bighint.
8287090df5aSMatthew Dillon 	 */
82900fd73d2SDoug Moore 	if (scan_from_start && !(digit == BLIST_RADIX - 1 &&
830bb4a27f9SMark Johnston 	    scan[i].bm_bighint == BLIST_MAX_ALLOC))
83187ae0686SDoug Moore 		scan->bm_bighint = *count - 1;
832d4e3484bSAlan Cox 
8337090df5aSMatthew Dillon 	return (SWAPBLK_NONE);
8347090df5aSMatthew Dillon }
8357090df5aSMatthew Dillon 
8367090df5aSMatthew Dillon /*
8377090df5aSMatthew Dillon  * BLST_LEAF_FREE() -	free allocated block from leaf bitmap
8387090df5aSMatthew Dillon  *
8397090df5aSMatthew Dillon  */
8407090df5aSMatthew Dillon static void
841b411efa4SAlan Cox blst_leaf_free(blmeta_t *scan, daddr_t blk, int count)
842b411efa4SAlan Cox {
843ec371b57SAlan Cox 	u_daddr_t mask;
844ec371b57SAlan Cox 
8457090df5aSMatthew Dillon 	/*
8467090df5aSMatthew Dillon 	 * free some data in this bitmap
847ec371b57SAlan Cox 	 * mask=0000111111111110000
8487090df5aSMatthew Dillon 	 *          \_________/\__/
849ec371b57SAlan Cox 	 *		count   n
8507090df5aSMatthew Dillon 	 */
85100fd73d2SDoug Moore 	mask = bitrange(blk & BLIST_MASK, count);
852b1f59c92SDoug Moore 	KASSERT((scan->bm_bitmap & mask) == 0,
853b1f59c92SDoug Moore 	    ("freeing free block: %jx, size %d, mask %jx",
854b1f59c92SDoug Moore 	    (uintmax_t)blk, count, (uintmax_t)scan->bm_bitmap & mask));
855bb4a27f9SMark Johnston 	scan->bm_bitmap |= mask;
8567090df5aSMatthew Dillon }
8577090df5aSMatthew Dillon 
8587090df5aSMatthew Dillon /*
8597090df5aSMatthew Dillon  * BLST_META_FREE() - free allocated blocks from radix tree meta info
8607090df5aSMatthew Dillon  *
8617090df5aSMatthew Dillon  *	This support routine frees a range of blocks from the bitmap.
8627090df5aSMatthew Dillon  *	The range must be entirely enclosed by this radix node.  If a
8637090df5aSMatthew Dillon  *	meta node, we break the range down recursively to free blocks
8647090df5aSMatthew Dillon  *	in subnodes (which means that this code can free an arbitrary
8657090df5aSMatthew Dillon  *	range whereas the allocation code cannot allocate an arbitrary
8667090df5aSMatthew Dillon  *	range).
8677090df5aSMatthew Dillon  */
8687090df5aSMatthew Dillon static void
869bee93d3cSAlan Cox blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, u_daddr_t radix)
870d3783724SAlan Cox {
871bb4a27f9SMark Johnston 	daddr_t blk, endBlk, i, skip;
872bb4a27f9SMark Johnston 	int digit, endDigit;
8737090df5aSMatthew Dillon 
874bb4a27f9SMark Johnston 	/*
875bb4a27f9SMark Johnston 	 * We could probably do a better job here.  We are required to make
876bb4a27f9SMark Johnston 	 * bighint at least as large as the biggest allocable block of data.
877bb4a27f9SMark Johnston 	 * If we just shoehorn it, a little extra overhead will be incurred
878bb4a27f9SMark Johnston 	 * on the next allocation (but only that one typically).
879bb4a27f9SMark Johnston 	 */
880bb4a27f9SMark Johnston 	scan->bm_bighint = BLIST_MAX_ALLOC;
881bb4a27f9SMark Johnston 
88200fd73d2SDoug Moore 	if (radix == 1)
883a396c83aSAlan Cox 		return (blst_leaf_free(scan, freeBlk, count));
8847090df5aSMatthew Dillon 
88500fd73d2SDoug Moore 	endBlk = freeBlk + count;
88600fd73d2SDoug Moore 	blk = (freeBlk + radix * BLIST_RADIX) & -(radix * BLIST_RADIX);
88700fd73d2SDoug Moore 	/*
88800fd73d2SDoug Moore 	 * blk is first block past the end of the range of this meta node,
88900fd73d2SDoug Moore 	 * or 0 in case of overflow.
89000fd73d2SDoug Moore 	 */
89100fd73d2SDoug Moore 	if (blk != 0)
89200fd73d2SDoug Moore 		endBlk = ummin(endBlk, blk);
893bb4a27f9SMark Johnston 	skip = radix_to_skip(radix);
894bb4a27f9SMark Johnston 	blk = freeBlk & -radix;
89500fd73d2SDoug Moore 	digit = (blk / radix) & BLIST_MASK;
89600fd73d2SDoug Moore 	endDigit = 1 + (((endBlk - 1) / radix) & BLIST_MASK);
897bb4a27f9SMark Johnston 	scan->bm_bitmap |= bitrange(digit, endDigit - digit);
898bb4a27f9SMark Johnston 	for (i = 1 + digit * skip; blk < endBlk; i += skip) {
8997090df5aSMatthew Dillon 		blk += radix;
900bb4a27f9SMark Johnston 		count = ummin(blk, endBlk) - freeBlk;
90100fd73d2SDoug Moore 		blst_meta_free(&scan[i], freeBlk, count, radix / BLIST_RADIX);
902bb4a27f9SMark Johnston 		freeBlk = blk;
9037090df5aSMatthew Dillon 	}
9047090df5aSMatthew Dillon }
9057090df5aSMatthew Dillon 
9067090df5aSMatthew Dillon /*
907bb4a27f9SMark Johnston  * BLST_COPY() - copy one radix tree to another
9087090df5aSMatthew Dillon  *
9097090df5aSMatthew Dillon  *	Locates free space in the source tree and frees it in the destination
9107090df5aSMatthew Dillon  *	tree.  The space may not already be free in the destination.
9117090df5aSMatthew Dillon  */
912b411efa4SAlan Cox static void
9132ac0c7c3SAlan Cox blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, blist_t dest,
9142ac0c7c3SAlan Cox     daddr_t count)
915b411efa4SAlan Cox {
916bb4a27f9SMark Johnston 	daddr_t endBlk, i, skip;
9177090df5aSMatthew Dillon 
9187090df5aSMatthew Dillon 	/*
9197090df5aSMatthew Dillon 	 * Leaf node
9207090df5aSMatthew Dillon 	 */
9217090df5aSMatthew Dillon 
92200fd73d2SDoug Moore 	if (radix == 1) {
923bb4a27f9SMark Johnston 		u_daddr_t v = scan->bm_bitmap;
9247090df5aSMatthew Dillon 
9257090df5aSMatthew Dillon 		if (v == (u_daddr_t)-1) {
9267090df5aSMatthew Dillon 			blist_free(dest, blk, count);
9277090df5aSMatthew Dillon 		} else if (v != 0) {
9287090df5aSMatthew Dillon 			int i;
9297090df5aSMatthew Dillon 
930bb4a27f9SMark Johnston 			for (i = 0; i < count; ++i) {
931064650c1SAlan Cox 				if (v & ((u_daddr_t)1 << i))
9327090df5aSMatthew Dillon 					blist_free(dest, blk + i, 1);
9337090df5aSMatthew Dillon 			}
9347090df5aSMatthew Dillon 		}
9357090df5aSMatthew Dillon 		return;
9367090df5aSMatthew Dillon 	}
9377090df5aSMatthew Dillon 
9387090df5aSMatthew Dillon 	/*
9397090df5aSMatthew Dillon 	 * Meta node
9407090df5aSMatthew Dillon 	 */
9417090df5aSMatthew Dillon 
942bb4a27f9SMark Johnston 	if (scan->bm_bitmap == 0) {
9437090df5aSMatthew Dillon 		/*
9447090df5aSMatthew Dillon 		 * Source all allocated, leave dest allocated
9457090df5aSMatthew Dillon 		 */
9467090df5aSMatthew Dillon 		return;
9477090df5aSMatthew Dillon 	}
9487090df5aSMatthew Dillon 
949bb4a27f9SMark Johnston 	endBlk = blk + count;
950bb4a27f9SMark Johnston 	skip = radix_to_skip(radix);
951bb4a27f9SMark Johnston 	for (i = 1; blk < endBlk; i += skip) {
9527090df5aSMatthew Dillon 		blk += radix;
953bb4a27f9SMark Johnston 		count = radix;
954bb4a27f9SMark Johnston 		if (blk >= endBlk)
955bb4a27f9SMark Johnston 			count -= blk - endBlk;
95600fd73d2SDoug Moore 		blst_copy(&scan[i], blk - radix,
95700fd73d2SDoug Moore 		    radix / BLIST_RADIX, dest, count);
9587090df5aSMatthew Dillon 	}
9597090df5aSMatthew Dillon }
9607090df5aSMatthew Dillon 
9617090df5aSMatthew Dillon /*
96292da00bbSMatthew Dillon  * BLST_LEAF_FILL() -	allocate specific blocks in leaf bitmap
96392da00bbSMatthew Dillon  *
96492da00bbSMatthew Dillon  *	This routine allocates all blocks in the specified range
96592da00bbSMatthew Dillon  *	regardless of any existing allocations in that range.  Returns
96692da00bbSMatthew Dillon  *	the number of blocks allocated by the call.
96792da00bbSMatthew Dillon  */
968a7249a6cSAlan Cox static daddr_t
96992da00bbSMatthew Dillon blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count)
97092da00bbSMatthew Dillon {
971a7249a6cSAlan Cox 	daddr_t nblks;
9724be4fd5dSAlan Cox 	u_daddr_t mask;
97392da00bbSMatthew Dillon 
97400fd73d2SDoug Moore 	mask = bitrange(blk & BLIST_MASK, count);
97592da00bbSMatthew Dillon 
9764be4fd5dSAlan Cox 	/* Count the number of blocks that we are allocating. */
977bb4a27f9SMark Johnston 	nblks = bitcount64(scan->bm_bitmap & mask);
97892da00bbSMatthew Dillon 
979bb4a27f9SMark Johnston 	scan->bm_bitmap &= ~mask;
9804be4fd5dSAlan Cox 	return (nblks);
98192da00bbSMatthew Dillon }
98292da00bbSMatthew Dillon 
98392da00bbSMatthew Dillon /*
98492da00bbSMatthew Dillon  * BLIST_META_FILL() -	allocate specific blocks at a meta node
98592da00bbSMatthew Dillon  *
98692da00bbSMatthew Dillon  *	This routine allocates the specified range of blocks,
98792da00bbSMatthew Dillon  *	regardless of any existing allocations in the range.  The
98892da00bbSMatthew Dillon  *	range must be within the extent of this node.  Returns the
98992da00bbSMatthew Dillon  *	number of blocks allocated by the call.
99092da00bbSMatthew Dillon  */
991a7249a6cSAlan Cox static daddr_t
992bee93d3cSAlan Cox blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, u_daddr_t radix)
993d3783724SAlan Cox {
994bb4a27f9SMark Johnston 	daddr_t blk, endBlk, i, nblks, skip;
995bb4a27f9SMark Johnston 	int digit;
99692da00bbSMatthew Dillon 
99700fd73d2SDoug Moore 	if (radix == 1)
998a396c83aSAlan Cox 		return (blst_leaf_fill(scan, allocBlk, count));
999bb4a27f9SMark Johnston 
100000fd73d2SDoug Moore 	endBlk = allocBlk + count;
100100fd73d2SDoug Moore 	blk = (allocBlk + radix * BLIST_RADIX) & -(radix * BLIST_RADIX);
100200fd73d2SDoug Moore 	/*
100300fd73d2SDoug Moore 	 * blk is first block past the end of the range of this meta node,
100400fd73d2SDoug Moore 	 * or 0 in case of overflow.
100500fd73d2SDoug Moore 	 */
100600fd73d2SDoug Moore 	if (blk != 0)
100700fd73d2SDoug Moore 		endBlk = ummin(endBlk, blk);
10082ac0c7c3SAlan Cox 	skip = radix_to_skip(radix);
1009bee93d3cSAlan Cox 	blk = allocBlk & -radix;
1010d3783724SAlan Cox 	nblks = 0;
1011bb4a27f9SMark Johnston 	while (blk < endBlk) {
101200fd73d2SDoug Moore 		digit = (blk / radix) & BLIST_MASK;
1013bb4a27f9SMark Johnston 		i = 1 + digit * skip;
101492da00bbSMatthew Dillon 		blk += radix;
1015bb4a27f9SMark Johnston 		count = ummin(blk, endBlk) - allocBlk;
101600fd73d2SDoug Moore 		nblks += blst_meta_fill(&scan[i], allocBlk, count,
101700fd73d2SDoug Moore 		    radix / BLIST_RADIX);
1018bb4a27f9SMark Johnston 		if (scan[i].bm_bitmap == 0)
1019bb4a27f9SMark Johnston 			scan->bm_bitmap &= ~((u_daddr_t)1 << digit);
1020bb4a27f9SMark Johnston 		allocBlk = blk;
102192da00bbSMatthew Dillon 	}
1022a396c83aSAlan Cox 	return (nblks);
102392da00bbSMatthew Dillon }
102492da00bbSMatthew Dillon 
10257090df5aSMatthew Dillon #ifdef BLIST_DEBUG
10267090df5aSMatthew Dillon 
10277090df5aSMatthew Dillon static void
10282ac0c7c3SAlan Cox blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab)
10297090df5aSMatthew Dillon {
1030bb4a27f9SMark Johnston 	daddr_t skip;
103153519253SDoug Moore 	u_daddr_t mask;
1032bb4a27f9SMark Johnston 	int digit;
10337090df5aSMatthew Dillon 
103400fd73d2SDoug Moore 	if (radix == 1) {
10357090df5aSMatthew Dillon 		printf(
1036bb4a27f9SMark Johnston 		    "%*.*s(%08llx,%lld): bitmap %0*llx big=%lld\n",
10377090df5aSMatthew Dillon 		    tab, tab, "",
103800fd73d2SDoug Moore 		    (long long)blk, (long long)BLIST_RADIX,
103900fd73d2SDoug Moore 		    (int)(1 + (BLIST_RADIX - 1) / 4),
1040bb4a27f9SMark Johnston 		    (long long)scan->bm_bitmap,
104192da00bbSMatthew Dillon 		    (long long)scan->bm_bighint
10427090df5aSMatthew Dillon 		);
10437090df5aSMatthew Dillon 		return;
10447090df5aSMatthew Dillon 	}
10457090df5aSMatthew Dillon 
10467090df5aSMatthew Dillon 	printf(
1047bb4a27f9SMark Johnston 	    "%*.*s(%08llx): subtree (%lld/%lld) bitmap %0*llx big=%lld {\n",
10487090df5aSMatthew Dillon 	    tab, tab, "",
104900fd73d2SDoug Moore 	    (long long)blk, (long long)radix * BLIST_RADIX,
105000fd73d2SDoug Moore 	    (long long)radix * BLIST_RADIX,
105100fd73d2SDoug Moore 	    (int)(1 + (BLIST_RADIX - 1) / 4),
1052bb4a27f9SMark Johnston 	    (long long)scan->bm_bitmap,
105392da00bbSMatthew Dillon 	    (long long)scan->bm_bighint
10547090df5aSMatthew Dillon 	);
10557090df5aSMatthew Dillon 
1056bb4a27f9SMark Johnston 	skip = radix_to_skip(radix);
10577090df5aSMatthew Dillon 	tab += 4;
10587090df5aSMatthew Dillon 
1059bb4a27f9SMark Johnston 	mask = scan->bm_bitmap;
1060bb4a27f9SMark Johnston 	/* Examine the nonempty subtree associated with each bit set in mask */
1061bb4a27f9SMark Johnston 	do {
106253519253SDoug Moore 		digit = bitpos(mask);
1063bb4a27f9SMark Johnston 		blst_radix_print(&scan[1 + digit * skip], blk + digit * radix,
106400fd73d2SDoug Moore 		    radix / BLIST_RADIX, tab);
106553519253SDoug Moore 	} while ((mask ^= bitrange(digit, 1)) != 0);
10667090df5aSMatthew Dillon 	tab -= 4;
10677090df5aSMatthew Dillon 
10687090df5aSMatthew Dillon 	printf(
10697090df5aSMatthew Dillon 	    "%*.*s}\n",
10707090df5aSMatthew Dillon 	    tab, tab, ""
10717090df5aSMatthew Dillon 	);
10727090df5aSMatthew Dillon }
10737090df5aSMatthew Dillon 
10747090df5aSMatthew Dillon #endif
10757090df5aSMatthew Dillon 
10767090df5aSMatthew Dillon #ifdef BLIST_DEBUG
10777090df5aSMatthew Dillon 
10787090df5aSMatthew Dillon int
10797090df5aSMatthew Dillon main(int ac, char **av)
10807090df5aSMatthew Dillon {
108100fd73d2SDoug Moore 	daddr_t size = BLIST_RADIX * BLIST_RADIX;
10827090df5aSMatthew Dillon 	int i;
10837090df5aSMatthew Dillon 	blist_t bl;
1084d027ed2eSAlan Cox 	struct sbuf *s;
10857090df5aSMatthew Dillon 
10867090df5aSMatthew Dillon 	for (i = 1; i < ac; ++i) {
10877090df5aSMatthew Dillon 		const char *ptr = av[i];
10887090df5aSMatthew Dillon 		if (*ptr != '-') {
108900fd73d2SDoug Moore 			size = strtoll(ptr, NULL, 0);
10907090df5aSMatthew Dillon 			continue;
10917090df5aSMatthew Dillon 		}
10927090df5aSMatthew Dillon 		ptr += 2;
10937090df5aSMatthew Dillon 		fprintf(stderr, "Bad option: %s\n", ptr - 2);
10947090df5aSMatthew Dillon 		exit(1);
10957090df5aSMatthew Dillon 	}
1096c8c7ad92SKip Macy 	bl = blist_create(size, M_WAITOK);
109700fd73d2SDoug Moore 	if (bl == NULL) {
109800fd73d2SDoug Moore 		fprintf(stderr, "blist_create failed\n");
109900fd73d2SDoug Moore 		exit(1);
110000fd73d2SDoug Moore 	}
11017090df5aSMatthew Dillon 	blist_free(bl, 0, size);
11027090df5aSMatthew Dillon 
11037090df5aSMatthew Dillon 	for (;;) {
11047090df5aSMatthew Dillon 		char buf[1024];
1105d90bf7d8SAlan Cox 		long long da = 0;
110687ae0686SDoug Moore 		int count = 0, maxcount = 0;
11077090df5aSMatthew Dillon 
11084be4fd5dSAlan Cox 		printf("%lld/%lld/%lld> ", (long long)blist_avail(bl),
110900fd73d2SDoug Moore 		    (long long)size, (long long)bl->bl_radix * BLIST_RADIX);
11107090df5aSMatthew Dillon 		fflush(stdout);
11117090df5aSMatthew Dillon 		if (fgets(buf, sizeof(buf), stdin) == NULL)
11127090df5aSMatthew Dillon 			break;
11137090df5aSMatthew Dillon 		switch(buf[0]) {
11147090df5aSMatthew Dillon 		case 'r':
111587ae0686SDoug Moore 			if (sscanf(buf + 1, "%d", &count) == 1) {
1116d90bf7d8SAlan Cox 				blist_resize(&bl, count, 1, M_WAITOK);
11177090df5aSMatthew Dillon 			} else {
11187090df5aSMatthew Dillon 				printf("?\n");
11197090df5aSMatthew Dillon 			}
11207090df5aSMatthew Dillon 		case 'p':
11217090df5aSMatthew Dillon 			blist_print(bl);
11227090df5aSMatthew Dillon 			break;
1123d027ed2eSAlan Cox 		case 's':
1124d027ed2eSAlan Cox 			s = sbuf_new_auto();
1125d027ed2eSAlan Cox 			blist_stats(bl, s);
1126d027ed2eSAlan Cox 			sbuf_finish(s);
1127d027ed2eSAlan Cox 			printf("%s", sbuf_data(s));
1128d027ed2eSAlan Cox 			sbuf_delete(s);
1129d027ed2eSAlan Cox 			break;
11307090df5aSMatthew Dillon 		case 'a':
113187ae0686SDoug Moore 			if (sscanf(buf + 1, "%d%d", &count, &maxcount) == 2) {
113287ae0686SDoug Moore 				daddr_t blk = blist_alloc(bl, &count, maxcount);
113387ae0686SDoug Moore 				printf("    R=%08llx, c=%08d\n",
113487ae0686SDoug Moore 				    (long long)blk, count);
11357090df5aSMatthew Dillon 			} else {
11367090df5aSMatthew Dillon 				printf("?\n");
11377090df5aSMatthew Dillon 			}
11387090df5aSMatthew Dillon 			break;
11397090df5aSMatthew Dillon 		case 'f':
114087ae0686SDoug Moore 			if (sscanf(buf + 1, "%llx %d", &da, &count) == 2) {
11417090df5aSMatthew Dillon 				blist_free(bl, da, count);
11427090df5aSMatthew Dillon 			} else {
11437090df5aSMatthew Dillon 				printf("?\n");
11447090df5aSMatthew Dillon 			}
11457090df5aSMatthew Dillon 			break;
114692da00bbSMatthew Dillon 		case 'l':
114787ae0686SDoug Moore 			if (sscanf(buf + 1, "%llx %d", &da, &count) == 2) {
1148a7249a6cSAlan Cox 				printf("    n=%jd\n",
1149a7249a6cSAlan Cox 				    (intmax_t)blist_fill(bl, da, count));
115092da00bbSMatthew Dillon 			} else {
115192da00bbSMatthew Dillon 				printf("?\n");
115292da00bbSMatthew Dillon 			}
115392da00bbSMatthew Dillon 			break;
11547090df5aSMatthew Dillon 		case '?':
11557090df5aSMatthew Dillon 		case 'h':
11567090df5aSMatthew Dillon 			puts(
11577090df5aSMatthew Dillon 			    "p          -print\n"
1158d027ed2eSAlan Cox 			    "s          -stats\n"
115987ae0686SDoug Moore 			    "a %d %d    -allocate\n"
11607090df5aSMatthew Dillon 			    "f %x %d    -free\n"
116192da00bbSMatthew Dillon 			    "l %x %d    -fill\n"
11627090df5aSMatthew Dillon 			    "r %d       -resize\n"
1163d4808c44SDoug Moore 			    "h/?        -help\n"
1164d4808c44SDoug Moore 			    "q          -quit"
11657090df5aSMatthew Dillon 			);
11667090df5aSMatthew Dillon 			break;
1167d4808c44SDoug Moore 		case 'q':
1168d4808c44SDoug Moore 			break;
11697090df5aSMatthew Dillon 		default:
11707090df5aSMatthew Dillon 			printf("?\n");
11717090df5aSMatthew Dillon 			break;
11727090df5aSMatthew Dillon 		}
1173d4808c44SDoug Moore 		if (buf[0] == 'q')
1174d4808c44SDoug Moore 			break;
11757090df5aSMatthew Dillon 	}
11767090df5aSMatthew Dillon 	return (0);
11777090df5aSMatthew Dillon }
11787090df5aSMatthew Dillon 
11797090df5aSMatthew Dillon #endif
1180