xref: /freebsd/sys/kern/subr_blist.c (revision 4ab18ea23a10d1fcb9aa70b5fe9f2580cb57daff)
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
39ec371b57SAlan Cox  *	contiguous free blocks in the subtree rooted at that node.  Two radix
40ec371b57SAlan Cox  *	constants are involved: one for the size of the bitmaps contained in the
41ec371b57SAlan Cox  *	leaf nodes (BLIST_BMAP_RADIX), and one for the number of descendents of
42ec371b57SAlan Cox  *	each of the meta (interior) nodes (BLIST_META_RADIX).  Each subtree is
43ec371b57SAlan Cox  *	associated with a range of blocks.  The root of any subtree stores a
44ec371b57SAlan Cox  *	hint field that defines an upper bound on the size of the largest
45ec371b57SAlan Cox  *	allocation that can begin in the associated block range.  A hint is an
46ec371b57SAlan Cox  *	upper bound on a potential allocation, but not necessarily a tight upper
47ec371b57SAlan Cox  *	bound.
487090df5aSMatthew Dillon  *
49bb4a27f9SMark Johnston  *	The bitmap field in each node directs the search for available blocks.
50bb4a27f9SMark Johnston  *	For a leaf node, a bit is set if the corresponding block is free.  For a
51bb4a27f9SMark Johnston  *	meta node, a bit is set if the corresponding subtree contains a free
52bb4a27f9SMark Johnston  *	block somewhere within it.  The search at a meta node considers only
53bb4a27f9SMark Johnston  *	children of that node that represent a range that includes a free block.
547090df5aSMatthew Dillon  *
557090df5aSMatthew Dillon  * 	The hinting greatly increases code efficiency for allocations while
567090df5aSMatthew Dillon  *	the general radix structure optimizes both allocations and frees.  The
577090df5aSMatthew Dillon  *	radix tree should be able to operate well no matter how much
587090df5aSMatthew Dillon  *	fragmentation there is and no matter how large a bitmap is used.
597090df5aSMatthew Dillon  *
6051dc4feaSSergey Kandaurov  *	The blist code wires all necessary memory at creation time.  Neither
6151dc4feaSSergey Kandaurov  *	allocations nor frees require interaction with the memory subsystem.
62bb4a27f9SMark Johnston  *	The non-blocking nature of allocations and frees is required by swap
63bb4a27f9SMark Johnston  *	code (vm/swap_pager.c).
647090df5aSMatthew Dillon  *
65bb4a27f9SMark Johnston  *	LAYOUT: The radix tree is laid out recursively using a linear array.
66bb4a27f9SMark Johnston  *	Each meta node is immediately followed (laid out sequentially in
67bb4a27f9SMark Johnston  *	memory) by BLIST_META_RADIX lower level nodes.  This is a recursive
68bb4a27f9SMark Johnston  *	structure but one that can be easily scanned through a very simple
69bb4a27f9SMark Johnston  *	'skip' calculation.  The memory allocation is only large enough to
70bb4a27f9SMark Johnston  *	cover the number of blocks requested at creation time.  Nodes that
71bb4a27f9SMark Johnston  *	represent blocks beyond that limit, nodes that would never be read
72bb4a27f9SMark Johnston  *	or written, are not allocated, so that the last of the
73bb4a27f9SMark Johnston  *	BLIST_META_RADIX lower level nodes of a some nodes may not be
74bb4a27f9SMark Johnston  *	allocated.
757090df5aSMatthew Dillon  *
76f565f395SEitan Adler  *	NOTE: the allocator cannot currently allocate more than
777090df5aSMatthew Dillon  *	BLIST_BMAP_RADIX blocks per call.  It will panic with 'allocation too
787090df5aSMatthew Dillon  *	large' if you try.  This is an area that could use improvement.  The
797090df5aSMatthew Dillon  *	radix is large enough that this restriction does not effect the swap
80b411efa4SAlan Cox  *	system, though.  Currently only the allocation code is affected by
817090df5aSMatthew Dillon  *	this algorithmic unfeature.  The freeing code can handle arbitrary
827090df5aSMatthew Dillon  *	ranges.
837090df5aSMatthew Dillon  *
847090df5aSMatthew Dillon  *	This code can be compiled stand-alone for debugging.
857090df5aSMatthew Dillon  */
867090df5aSMatthew Dillon 
87677b542eSDavid E. O'Brien #include <sys/cdefs.h>
88677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
89677b542eSDavid E. O'Brien 
90c4473420SPeter Wemm #ifdef _KERNEL
917090df5aSMatthew Dillon 
927090df5aSMatthew Dillon #include <sys/param.h>
937090df5aSMatthew Dillon #include <sys/systm.h>
947090df5aSMatthew Dillon #include <sys/lock.h>
957090df5aSMatthew Dillon #include <sys/kernel.h>
967090df5aSMatthew Dillon #include <sys/blist.h>
977090df5aSMatthew Dillon #include <sys/malloc.h>
98d027ed2eSAlan Cox #include <sys/sbuf.h>
990cddd8f0SMatthew Dillon #include <sys/proc.h>
10023955314SAlfred Perlstein #include <sys/mutex.h>
1017090df5aSMatthew Dillon 
1027090df5aSMatthew Dillon #else
1037090df5aSMatthew Dillon 
1047090df5aSMatthew Dillon #ifndef BLIST_NO_DEBUG
1057090df5aSMatthew Dillon #define BLIST_DEBUG
1067090df5aSMatthew Dillon #endif
1077090df5aSMatthew Dillon 
108bb4a27f9SMark Johnston #include <sys/errno.h>
1097090df5aSMatthew Dillon #include <sys/types.h>
110d90bf7d8SAlan Cox #include <sys/malloc.h>
111d027ed2eSAlan Cox #include <sys/sbuf.h>
112b1f59c92SDoug Moore #include <assert.h>
1137090df5aSMatthew Dillon #include <stdio.h>
1147090df5aSMatthew Dillon #include <string.h>
1158eefcd40SAlan Cox #include <stddef.h>
1167090df5aSMatthew Dillon #include <stdlib.h>
1177090df5aSMatthew Dillon #include <stdarg.h>
118d3783724SAlan Cox #include <stdbool.h>
1197090df5aSMatthew Dillon 
1204be4fd5dSAlan Cox #define	bitcount64(x)	__bitcount64((uint64_t)(x))
12192da00bbSMatthew Dillon #define malloc(a,b,c)	calloc(a, 1)
1227090df5aSMatthew Dillon #define free(a,b)	free(a)
123bb4a27f9SMark Johnston #define ummin(a,b)	((a) < (b) ? (a) : (b))
124b1f59c92SDoug Moore #define KASSERT(a,b)	assert(a)
1257090df5aSMatthew Dillon 
1267090df5aSMatthew Dillon #include <sys/blist.h>
1277090df5aSMatthew Dillon 
1287090df5aSMatthew Dillon #endif
1297090df5aSMatthew Dillon 
1307090df5aSMatthew Dillon /*
1317090df5aSMatthew Dillon  * static support functions
1327090df5aSMatthew Dillon  */
133ec371b57SAlan Cox static daddr_t	blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count);
134bee93d3cSAlan Cox static daddr_t	blst_meta_alloc(blmeta_t *scan, daddr_t cursor, daddr_t count,
135bee93d3cSAlan Cox 		    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 
153ec371b57SAlan Cox _Static_assert(BLIST_BMAP_RADIX % BLIST_META_RADIX == 0,
154ec371b57SAlan Cox     "radix divisibility error");
155ec371b57SAlan Cox #define	BLIST_BMAP_MASK	(BLIST_BMAP_RADIX - 1)
156d027ed2eSAlan Cox #define	BLIST_META_MASK	(BLIST_META_RADIX - 1)
157ba98e6a2SAlan Cox 
1587090df5aSMatthew Dillon /*
1592ac0c7c3SAlan Cox  * For a subtree that can represent the state of up to 'radix' blocks, the
1602ac0c7c3SAlan Cox  * number of leaf nodes of the subtree is L=radix/BLIST_BMAP_RADIX.  If 'm'
1612ac0c7c3SAlan Cox  * is short for BLIST_META_RADIX, then for a tree of height h with L=m**h
1622ac0c7c3SAlan Cox  * leaf nodes, the total number of tree nodes is 1 + m + m**2 + ... + m**h,
1632ac0c7c3SAlan Cox  * or, equivalently, (m**(h+1)-1)/(m-1).  This quantity is called 'skip'
1642ac0c7c3SAlan Cox  * in the 'meta' functions that process subtrees.  Since integer division
1652ac0c7c3SAlan Cox  * discards remainders, we can express this computation as
1662ac0c7c3SAlan Cox  * skip = (m * m**h) / (m - 1)
167ba98e6a2SAlan Cox  * skip = (m * (radix / BLIST_BMAP_RADIX)) / (m - 1)
168ba98e6a2SAlan Cox  * and since m divides BLIST_BMAP_RADIX, we can simplify further to
169ba98e6a2SAlan Cox  * skip = (radix / (BLIST_BMAP_RADIX / m)) / (m - 1)
170ba98e6a2SAlan Cox  * skip = radix / ((BLIST_BMAP_RADIX / m) * (m - 1))
171ba98e6a2SAlan Cox  * so that simple integer division by a constant can safely be used for the
172ba98e6a2SAlan Cox  * calculation.
1732ac0c7c3SAlan Cox  */
1742ac0c7c3SAlan Cox static inline daddr_t
1752ac0c7c3SAlan Cox radix_to_skip(daddr_t radix)
1762ac0c7c3SAlan Cox {
1772ac0c7c3SAlan Cox 
1782ac0c7c3SAlan Cox 	return (radix /
179d027ed2eSAlan Cox 	    ((BLIST_BMAP_RADIX / BLIST_META_RADIX) * BLIST_META_MASK));
180d027ed2eSAlan Cox }
181d027ed2eSAlan Cox 
182d027ed2eSAlan Cox /*
183bb4a27f9SMark Johnston  * Provide a mask with count bits set, starting as position n.
184bb4a27f9SMark Johnston  */
185bb4a27f9SMark Johnston static inline u_daddr_t
186bb4a27f9SMark Johnston bitrange(int n, int count)
187bb4a27f9SMark Johnston {
188bb4a27f9SMark Johnston 
189bb4a27f9SMark Johnston 	return (((u_daddr_t)-1 << n) &
190bb4a27f9SMark Johnston 	    ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - (n + count))));
191bb4a27f9SMark Johnston }
192bb4a27f9SMark Johnston 
193bb4a27f9SMark Johnston 
194bb4a27f9SMark Johnston /*
195*4ab18ea2SDoug Moore  * Find the first bit set in a u_daddr_t.
196d027ed2eSAlan Cox  */
197d027ed2eSAlan Cox static inline int
198*4ab18ea2SDoug Moore generic_bitpos(u_daddr_t mask)
199d027ed2eSAlan Cox {
200d027ed2eSAlan Cox 	int hi, lo, mid;
201d027ed2eSAlan Cox 
202d027ed2eSAlan Cox 	lo = 0;
203d027ed2eSAlan Cox 	hi = BLIST_BMAP_RADIX;
204d027ed2eSAlan Cox 	while (lo + 1 < hi) {
205d027ed2eSAlan Cox 		mid = (lo + hi) >> 1;
206*4ab18ea2SDoug Moore 		if (mask & bitrange(0, mid))
207d027ed2eSAlan Cox 			hi = mid;
208*4ab18ea2SDoug Moore 		else
209*4ab18ea2SDoug Moore 			lo = mid;
210d027ed2eSAlan Cox 	}
211d027ed2eSAlan Cox 	return (lo);
212d027ed2eSAlan Cox }
213*4ab18ea2SDoug Moore 
214*4ab18ea2SDoug Moore static inline int
215*4ab18ea2SDoug Moore bitpos(u_daddr_t mask)
216*4ab18ea2SDoug Moore {
217*4ab18ea2SDoug Moore 
218*4ab18ea2SDoug Moore 	return (_Generic(mask,
219*4ab18ea2SDoug Moore #ifdef HAVE_INLINE_FFSLL
220*4ab18ea2SDoug Moore 	    long long: ffsll(mask) - 1,
221*4ab18ea2SDoug Moore #endif
222*4ab18ea2SDoug Moore #ifdef HAVE_INLINE_FFSL
223*4ab18ea2SDoug Moore 	    long: ffsl(mask) - 1,
224*4ab18ea2SDoug Moore #endif
225*4ab18ea2SDoug Moore #ifdef HAVE_INLINE_FFS
226*4ab18ea2SDoug Moore 	    int: ffs(mask) - 1,
227*4ab18ea2SDoug Moore #endif
228*4ab18ea2SDoug Moore 	    default: generic_bitpos(mask)
229*4ab18ea2SDoug Moore 	));
2302ac0c7c3SAlan Cox }
2312ac0c7c3SAlan Cox 
2322ac0c7c3SAlan Cox /*
2337090df5aSMatthew Dillon  * blist_create() - create a blist capable of handling up to the specified
2347090df5aSMatthew Dillon  *		    number of blocks
2357090df5aSMatthew Dillon  *
236f565f395SEitan Adler  *	blocks - must be greater than 0
237c8c7ad92SKip Macy  * 	flags  - malloc flags
2387090df5aSMatthew Dillon  *
2397090df5aSMatthew Dillon  *	The smallest blist consists of a single leaf node capable of
2407090df5aSMatthew Dillon  *	managing BLIST_BMAP_RADIX blocks.
2417090df5aSMatthew Dillon  */
2427090df5aSMatthew Dillon blist_t
243c8c7ad92SKip Macy blist_create(daddr_t blocks, int flags)
2447090df5aSMatthew Dillon {
2457090df5aSMatthew Dillon 	blist_t bl;
246bb4a27f9SMark Johnston 	u_daddr_t nodes, radix;
2477090df5aSMatthew Dillon 
248b1f59c92SDoug Moore 	KASSERT(blocks > 0, ("invalid block count"));
249ce9eea64SMark Johnston 
2507090df5aSMatthew Dillon 	/*
251ce9eea64SMark Johnston 	 * Calculate the radix and node count used for scanning.
2527090df5aSMatthew Dillon 	 */
253bb4a27f9SMark Johnston 	nodes = 1;
2547090df5aSMatthew Dillon 	radix = BLIST_BMAP_RADIX;
255bb4a27f9SMark Johnston 	while (radix <= blocks) {
256bb4a27f9SMark Johnston 		nodes += 1 + (blocks - 1) / radix;
25757e6d29bSMatthew Dillon 		radix *= BLIST_META_RADIX;
2587090df5aSMatthew Dillon 	}
2597090df5aSMatthew Dillon 
26003ca2137SAlan Cox 	bl = malloc(offsetof(struct blist, bl_root[nodes]), M_SWAP, flags |
26103ca2137SAlan Cox 	    M_ZERO);
262015d7db6SAlan Cox 	if (bl == NULL)
263015d7db6SAlan Cox 		return (NULL);
2647090df5aSMatthew Dillon 
2657090df5aSMatthew Dillon 	bl->bl_blocks = blocks;
2667090df5aSMatthew Dillon 	bl->bl_radix = radix;
2677090df5aSMatthew Dillon 
2687090df5aSMatthew Dillon #if defined(BLIST_DEBUG)
2697090df5aSMatthew Dillon 	printf(
27092da00bbSMatthew Dillon 		"BLIST representing %lld blocks (%lld MB of swap)"
27192da00bbSMatthew Dillon 		", requiring %lldK of ram\n",
27292da00bbSMatthew Dillon 		(long long)bl->bl_blocks,
27392da00bbSMatthew Dillon 		(long long)bl->bl_blocks * 4 / 1024,
274015d7db6SAlan Cox 		(long long)(nodes * sizeof(blmeta_t) + 1023) / 1024
2757090df5aSMatthew Dillon 	);
27692da00bbSMatthew Dillon 	printf("BLIST raw radix tree contains %lld records\n",
277015d7db6SAlan Cox 	    (long long)nodes);
2787090df5aSMatthew Dillon #endif
2797090df5aSMatthew Dillon 
2807090df5aSMatthew Dillon 	return (bl);
2817090df5aSMatthew Dillon }
2827090df5aSMatthew Dillon 
2837090df5aSMatthew Dillon void
2847090df5aSMatthew Dillon blist_destroy(blist_t bl)
2857090df5aSMatthew Dillon {
2868eefcd40SAlan Cox 
2877090df5aSMatthew Dillon 	free(bl, M_SWAP);
2887090df5aSMatthew Dillon }
2897090df5aSMatthew Dillon 
2907090df5aSMatthew Dillon /*
2917090df5aSMatthew Dillon  * blist_alloc() -   reserve space in the block bitmap.  Return the base
2927090df5aSMatthew Dillon  *		     of a contiguous region or SWAPBLK_NONE if space could
2937090df5aSMatthew Dillon  *		     not be allocated.
2947090df5aSMatthew Dillon  */
2957090df5aSMatthew Dillon daddr_t
2967090df5aSMatthew Dillon blist_alloc(blist_t bl, daddr_t count)
2977090df5aSMatthew Dillon {
29827d172bbSDoug Moore 	daddr_t blk, cursor;
2997090df5aSMatthew Dillon 
300b1f59c92SDoug Moore 	KASSERT(count <= BLIST_MAX_ALLOC,
301b1f59c92SDoug Moore 	    ("allocation too large: %d", (int)count));
302bb4a27f9SMark Johnston 
303d4e3484bSAlan Cox 	/*
304d4e3484bSAlan Cox 	 * This loop iterates at most twice.  An allocation failure in the
305d4e3484bSAlan Cox 	 * first iteration leads to a second iteration only if the cursor was
306d4e3484bSAlan Cox 	 * non-zero.  When the cursor is zero, an allocation failure will
307749cdf6fSAlan Cox 	 * stop further iterations.
308d4e3484bSAlan Cox 	 */
30927d172bbSDoug Moore 	cursor = bl->bl_cursor;
310749cdf6fSAlan Cox 	for (;;) {
31127d172bbSDoug Moore 		blk = blst_meta_alloc(bl->bl_root, cursor, count,
312bee93d3cSAlan Cox 		    bl->bl_radix);
313d4e3484bSAlan Cox 		if (blk != SWAPBLK_NONE) {
314bb4a27f9SMark Johnston 			bl->bl_avail -= count;
315d4e3484bSAlan Cox 			bl->bl_cursor = blk + count;
316a0ae476bSAlan Cox 			if (bl->bl_cursor == bl->bl_blocks)
317a0ae476bSAlan Cox 				bl->bl_cursor = 0;
3187090df5aSMatthew Dillon 			return (blk);
31927d172bbSDoug Moore 		} else if (cursor == 0)
320749cdf6fSAlan Cox 			return (SWAPBLK_NONE);
32127d172bbSDoug Moore 		cursor = 0;
3227090df5aSMatthew Dillon 	}
3234be4fd5dSAlan Cox }
3244be4fd5dSAlan Cox 
3254be4fd5dSAlan Cox /*
3264be4fd5dSAlan Cox  * blist_avail() -	return the number of free blocks.
3274be4fd5dSAlan Cox  */
3284be4fd5dSAlan Cox daddr_t
3294be4fd5dSAlan Cox blist_avail(blist_t bl)
3304be4fd5dSAlan Cox {
3314be4fd5dSAlan Cox 
332bb4a27f9SMark Johnston 	return (bl->bl_avail);
3334be4fd5dSAlan Cox }
3347090df5aSMatthew Dillon 
3357090df5aSMatthew Dillon /*
3367090df5aSMatthew Dillon  * blist_free() -	free up space in the block bitmap.  Return the base
337b1f59c92SDoug Moore  *		     	of a contiguous region.
3387090df5aSMatthew Dillon  */
3397090df5aSMatthew Dillon void
3407090df5aSMatthew Dillon blist_free(blist_t bl, daddr_t blkno, daddr_t count)
3417090df5aSMatthew Dillon {
342a396c83aSAlan Cox 
343b1f59c92SDoug Moore 	KASSERT(blkno >= 0 && blkno + count <= bl->bl_blocks,
344b1f59c92SDoug Moore 	    ("freeing invalid range: blkno %jx, count %d, blocks %jd",
345b1f59c92SDoug Moore 	    (uintmax_t)blkno, (int)count, (uintmax_t)bl->bl_blocks));
346bee93d3cSAlan Cox 	blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix);
347bb4a27f9SMark Johnston 	bl->bl_avail += count;
3487090df5aSMatthew Dillon }
3497090df5aSMatthew Dillon 
3507090df5aSMatthew Dillon /*
35192da00bbSMatthew Dillon  * blist_fill() -	mark a region in the block bitmap as off-limits
35292da00bbSMatthew Dillon  *			to the allocator (i.e. allocate it), ignoring any
35392da00bbSMatthew Dillon  *			existing allocations.  Return the number of blocks
35492da00bbSMatthew Dillon  *			actually filled that were free before the call.
35592da00bbSMatthew Dillon  */
356a7249a6cSAlan Cox daddr_t
35792da00bbSMatthew Dillon blist_fill(blist_t bl, daddr_t blkno, daddr_t count)
35892da00bbSMatthew Dillon {
359bb4a27f9SMark Johnston 	daddr_t filled;
36092da00bbSMatthew Dillon 
361b1f59c92SDoug Moore 	KASSERT(blkno >= 0 && blkno + count <= bl->bl_blocks,
362b1f59c92SDoug Moore 	    ("filling invalid range: blkno %jx, count %d, blocks %jd",
363b1f59c92SDoug Moore 	    (uintmax_t)blkno, (int)count, (uintmax_t)bl->bl_blocks));
364bb4a27f9SMark Johnston 	filled = blst_meta_fill(bl->bl_root, blkno, count, bl->bl_radix);
365bb4a27f9SMark Johnston 	bl->bl_avail -= filled;
366bb4a27f9SMark Johnston 	return (filled);
36792da00bbSMatthew Dillon }
36892da00bbSMatthew Dillon 
36992da00bbSMatthew Dillon /*
3707090df5aSMatthew Dillon  * blist_resize() -	resize an existing radix tree to handle the
3717090df5aSMatthew Dillon  *			specified number of blocks.  This will reallocate
3727090df5aSMatthew Dillon  *			the tree and transfer the previous bitmap to the new
3737090df5aSMatthew Dillon  *			one.  When extending the tree you can specify whether
3747090df5aSMatthew Dillon  *			the new blocks are to left allocated or freed.
3757090df5aSMatthew Dillon  */
3767090df5aSMatthew Dillon void
377c8c7ad92SKip Macy blist_resize(blist_t *pbl, daddr_t count, int freenew, int flags)
3787090df5aSMatthew Dillon {
379c8c7ad92SKip Macy     blist_t newbl = blist_create(count, flags);
3807090df5aSMatthew Dillon     blist_t save = *pbl;
3817090df5aSMatthew Dillon 
3827090df5aSMatthew Dillon     *pbl = newbl;
3837090df5aSMatthew Dillon     if (count > save->bl_blocks)
3847090df5aSMatthew Dillon 	    count = save->bl_blocks;
3852ac0c7c3SAlan Cox     blst_copy(save->bl_root, 0, save->bl_radix, newbl, count);
3867090df5aSMatthew Dillon 
3877090df5aSMatthew Dillon     /*
3887090df5aSMatthew Dillon      * If resizing upwards, should we free the new space or not?
3897090df5aSMatthew Dillon      */
3907090df5aSMatthew Dillon     if (freenew && count < newbl->bl_blocks) {
3917090df5aSMatthew Dillon 	    blist_free(newbl, count, newbl->bl_blocks - count);
3927090df5aSMatthew Dillon     }
3937090df5aSMatthew Dillon     blist_destroy(save);
3947090df5aSMatthew Dillon }
3957090df5aSMatthew Dillon 
3967090df5aSMatthew Dillon #ifdef BLIST_DEBUG
3977090df5aSMatthew Dillon 
3987090df5aSMatthew Dillon /*
3997090df5aSMatthew Dillon  * blist_print()    - dump radix tree
4007090df5aSMatthew Dillon  */
4017090df5aSMatthew Dillon void
4027090df5aSMatthew Dillon blist_print(blist_t bl)
4037090df5aSMatthew Dillon {
404bb4a27f9SMark Johnston 	printf("BLIST avail = %jd, cursor = %08jx {\n",
405bb4a27f9SMark Johnston 	    (uintmax_t)bl->bl_avail, (uintmax_t)bl->bl_cursor);
406bb4a27f9SMark Johnston 
407bb4a27f9SMark Johnston 	if (bl->bl_root->bm_bitmap != 0)
4082ac0c7c3SAlan Cox 		blst_radix_print(bl->bl_root, 0, bl->bl_radix, 4);
4097090df5aSMatthew Dillon 	printf("}\n");
4107090df5aSMatthew Dillon }
4117090df5aSMatthew Dillon 
4127090df5aSMatthew Dillon #endif
4137090df5aSMatthew Dillon 
414d027ed2eSAlan Cox static const u_daddr_t fib[] = {
415d027ed2eSAlan Cox 	1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584,
416d027ed2eSAlan Cox 	4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811,
417d027ed2eSAlan Cox 	514229, 832040, 1346269, 2178309, 3524578,
418d027ed2eSAlan Cox };
419d027ed2eSAlan Cox 
420d027ed2eSAlan Cox /*
421d027ed2eSAlan Cox  * Use 'gap' to describe a maximal range of unallocated blocks/bits.
422d027ed2eSAlan Cox  */
423d027ed2eSAlan Cox struct gap_stats {
424d027ed2eSAlan Cox 	daddr_t	start;		/* current gap start, or SWAPBLK_NONE */
425d027ed2eSAlan Cox 	daddr_t	num;		/* number of gaps observed */
426d027ed2eSAlan Cox 	daddr_t	max;		/* largest gap size */
427d027ed2eSAlan Cox 	daddr_t	avg;		/* average gap size */
428d027ed2eSAlan Cox 	daddr_t	err;		/* sum - num * avg */
429d027ed2eSAlan Cox 	daddr_t	histo[nitems(fib)]; /* # gaps in each size range */
430d027ed2eSAlan Cox 	int	max_bucket;	/* last histo elt with nonzero val */
431d027ed2eSAlan Cox };
432d027ed2eSAlan Cox 
433d027ed2eSAlan Cox /*
434d027ed2eSAlan Cox  * gap_stats_counting()    - is the state 'counting 1 bits'?
435d027ed2eSAlan Cox  *                           or 'skipping 0 bits'?
436d027ed2eSAlan Cox  */
437d027ed2eSAlan Cox static inline bool
438d027ed2eSAlan Cox gap_stats_counting(const struct gap_stats *stats)
439d027ed2eSAlan Cox {
440d027ed2eSAlan Cox 
441d027ed2eSAlan Cox 	return (stats->start != SWAPBLK_NONE);
442d027ed2eSAlan Cox }
443d027ed2eSAlan Cox 
444d027ed2eSAlan Cox /*
445d027ed2eSAlan Cox  * init_gap_stats()    - initialize stats on gap sizes
446d027ed2eSAlan Cox  */
447d027ed2eSAlan Cox static inline void
448d027ed2eSAlan Cox init_gap_stats(struct gap_stats *stats)
449d027ed2eSAlan Cox {
450d027ed2eSAlan Cox 
451d027ed2eSAlan Cox 	bzero(stats, sizeof(*stats));
452d027ed2eSAlan Cox 	stats->start = SWAPBLK_NONE;
453d027ed2eSAlan Cox }
454d027ed2eSAlan Cox 
455d027ed2eSAlan Cox /*
456d027ed2eSAlan Cox  * update_gap_stats()    - update stats on gap sizes
457d027ed2eSAlan Cox  */
458d027ed2eSAlan Cox static void
459d027ed2eSAlan Cox update_gap_stats(struct gap_stats *stats, daddr_t posn)
460d027ed2eSAlan Cox {
461d027ed2eSAlan Cox 	daddr_t size;
462d027ed2eSAlan Cox 	int hi, lo, mid;
463d027ed2eSAlan Cox 
464d027ed2eSAlan Cox 	if (!gap_stats_counting(stats)) {
465d027ed2eSAlan Cox 		stats->start = posn;
466d027ed2eSAlan Cox 		return;
467d027ed2eSAlan Cox 	}
468d027ed2eSAlan Cox 	size = posn - stats->start;
469d027ed2eSAlan Cox 	stats->start = SWAPBLK_NONE;
470d027ed2eSAlan Cox 	if (size > stats->max)
471d027ed2eSAlan Cox 		stats->max = size;
472d027ed2eSAlan Cox 
473d027ed2eSAlan Cox 	/*
474d027ed2eSAlan Cox 	 * Find the fibonacci range that contains size,
475d027ed2eSAlan Cox 	 * expecting to find it in an early range.
476d027ed2eSAlan Cox 	 */
477d027ed2eSAlan Cox 	lo = 0;
478d027ed2eSAlan Cox 	hi = 1;
479d027ed2eSAlan Cox 	while (hi < nitems(fib) && fib[hi] <= size) {
480d027ed2eSAlan Cox 		lo = hi;
481d027ed2eSAlan Cox 		hi *= 2;
482d027ed2eSAlan Cox 	}
483d027ed2eSAlan Cox 	if (hi >= nitems(fib))
484d027ed2eSAlan Cox 		hi = nitems(fib);
485d027ed2eSAlan Cox 	while (lo + 1 != hi) {
486d027ed2eSAlan Cox 		mid = (lo + hi) >> 1;
487d027ed2eSAlan Cox 		if (fib[mid] <= size)
488d027ed2eSAlan Cox 			lo = mid;
489d027ed2eSAlan Cox 		else
490d027ed2eSAlan Cox 			hi = mid;
491d027ed2eSAlan Cox 	}
492d027ed2eSAlan Cox 	stats->histo[lo]++;
493d027ed2eSAlan Cox 	if (lo > stats->max_bucket)
494d027ed2eSAlan Cox 		stats->max_bucket = lo;
495d027ed2eSAlan Cox 	stats->err += size - stats->avg;
496d027ed2eSAlan Cox 	stats->num++;
497d027ed2eSAlan Cox 	stats->avg += stats->err / stats->num;
498d027ed2eSAlan Cox 	stats->err %= stats->num;
499d027ed2eSAlan Cox }
500d027ed2eSAlan Cox 
501d027ed2eSAlan Cox /*
502d027ed2eSAlan Cox  * dump_gap_stats()    - print stats on gap sizes
503d027ed2eSAlan Cox  */
504d027ed2eSAlan Cox static inline void
505d027ed2eSAlan Cox dump_gap_stats(const struct gap_stats *stats, struct sbuf *s)
506d027ed2eSAlan Cox {
507d027ed2eSAlan Cox 	int i;
508d027ed2eSAlan Cox 
509d027ed2eSAlan Cox 	sbuf_printf(s, "number of maximal free ranges: %jd\n",
510d027ed2eSAlan Cox 	    (intmax_t)stats->num);
511d027ed2eSAlan Cox 	sbuf_printf(s, "largest free range: %jd\n", (intmax_t)stats->max);
512d027ed2eSAlan Cox 	sbuf_printf(s, "average maximal free range size: %jd\n",
513d027ed2eSAlan Cox 	    (intmax_t)stats->avg);
514d027ed2eSAlan Cox 	sbuf_printf(s, "number of maximal free ranges of different sizes:\n");
515d027ed2eSAlan Cox 	sbuf_printf(s, "               count  |  size range\n");
516d027ed2eSAlan Cox 	sbuf_printf(s, "               -----  |  ----------\n");
517d027ed2eSAlan Cox 	for (i = 0; i < stats->max_bucket; i++) {
518d027ed2eSAlan Cox 		if (stats->histo[i] != 0) {
519d027ed2eSAlan Cox 			sbuf_printf(s, "%20jd  |  ",
520d027ed2eSAlan Cox 			    (intmax_t)stats->histo[i]);
521d027ed2eSAlan Cox 			if (fib[i] != fib[i + 1] - 1)
522d027ed2eSAlan Cox 				sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i],
523d027ed2eSAlan Cox 				    (intmax_t)fib[i + 1] - 1);
524d027ed2eSAlan Cox 			else
525d027ed2eSAlan Cox 				sbuf_printf(s, "%jd\n", (intmax_t)fib[i]);
526d027ed2eSAlan Cox 		}
527d027ed2eSAlan Cox 	}
528d027ed2eSAlan Cox 	sbuf_printf(s, "%20jd  |  ", (intmax_t)stats->histo[i]);
529d027ed2eSAlan Cox 	if (stats->histo[i] > 1)
530d027ed2eSAlan Cox 		sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i],
531d027ed2eSAlan Cox 		    (intmax_t)stats->max);
532d027ed2eSAlan Cox 	else
533d027ed2eSAlan Cox 		sbuf_printf(s, "%jd\n", (intmax_t)stats->max);
534d027ed2eSAlan Cox }
535d027ed2eSAlan Cox 
536d027ed2eSAlan Cox /*
537d027ed2eSAlan Cox  * blist_stats()    - dump radix tree stats
538d027ed2eSAlan Cox  */
539d027ed2eSAlan Cox void
540d027ed2eSAlan Cox blist_stats(blist_t bl, struct sbuf *s)
541d027ed2eSAlan Cox {
542d027ed2eSAlan Cox 	struct gap_stats gstats;
543d027ed2eSAlan Cox 	struct gap_stats *stats = &gstats;
544d027ed2eSAlan Cox 	daddr_t i, nodes, radix;
545*4ab18ea2SDoug Moore 	u_daddr_t diff, mask;
546*4ab18ea2SDoug Moore 	int digit;
547d027ed2eSAlan Cox 
548d027ed2eSAlan Cox 	init_gap_stats(stats);
549d027ed2eSAlan Cox 	nodes = 0;
550d027ed2eSAlan Cox 	i = bl->bl_radix;
551d027ed2eSAlan Cox 	while (i < bl->bl_radix + bl->bl_blocks) {
552d027ed2eSAlan Cox 		/*
553d027ed2eSAlan Cox 		 * Find max size subtree starting at i.
554d027ed2eSAlan Cox 		 */
555d027ed2eSAlan Cox 		radix = BLIST_BMAP_RADIX;
556d027ed2eSAlan Cox 		while (((i / radix) & BLIST_META_MASK) == 0)
557d027ed2eSAlan Cox 			radix *= BLIST_META_RADIX;
558d027ed2eSAlan Cox 
559d027ed2eSAlan Cox 		/*
560d027ed2eSAlan Cox 		 * Check for skippable subtrees starting at i.
561d027ed2eSAlan Cox 		 */
562d027ed2eSAlan Cox 		while (radix > BLIST_BMAP_RADIX) {
563bb4a27f9SMark Johnston 			if (bl->bl_root[nodes].bm_bitmap == 0) {
564d027ed2eSAlan Cox 				if (gap_stats_counting(stats))
565d027ed2eSAlan Cox 					update_gap_stats(stats, i);
566d027ed2eSAlan Cox 				break;
567d027ed2eSAlan Cox 			}
568d027ed2eSAlan Cox 
569d027ed2eSAlan Cox 			/*
570d027ed2eSAlan Cox 			 * Skip subtree root.
571d027ed2eSAlan Cox 			 */
572d027ed2eSAlan Cox 			nodes++;
573d027ed2eSAlan Cox 			radix /= BLIST_META_RADIX;
574d027ed2eSAlan Cox 		}
575d027ed2eSAlan Cox 		if (radix == BLIST_BMAP_RADIX) {
576d027ed2eSAlan Cox 			/*
577d027ed2eSAlan Cox 			 * Scan leaf.
578d027ed2eSAlan Cox 			 */
579bb4a27f9SMark Johnston 			mask = bl->bl_root[nodes].bm_bitmap;
580d027ed2eSAlan Cox 			diff = mask ^ (mask << 1);
581d027ed2eSAlan Cox 			if (gap_stats_counting(stats))
582d027ed2eSAlan Cox 				diff ^= 1;
583d027ed2eSAlan Cox 			while (diff != 0) {
584*4ab18ea2SDoug Moore 				digit = bitpos(diff);
585*4ab18ea2SDoug Moore 				update_gap_stats(stats, i + digit);
586*4ab18ea2SDoug Moore 				diff ^= bitrange(digit, 1);
587d027ed2eSAlan Cox 			}
588d027ed2eSAlan Cox 		}
589d027ed2eSAlan Cox 		nodes += radix_to_skip(radix);
590d027ed2eSAlan Cox 		i += radix;
591d027ed2eSAlan Cox 	}
592d027ed2eSAlan Cox 	update_gap_stats(stats, i);
593d027ed2eSAlan Cox 	dump_gap_stats(stats, s);
594d027ed2eSAlan Cox }
595d027ed2eSAlan Cox 
5967090df5aSMatthew Dillon /************************************************************************
5977090df5aSMatthew Dillon  *			  ALLOCATION SUPPORT FUNCTIONS			*
5987090df5aSMatthew Dillon  ************************************************************************
5997090df5aSMatthew Dillon  *
6007090df5aSMatthew Dillon  *	These support functions do all the actual work.  They may seem
6017090df5aSMatthew Dillon  *	rather longish, but that's because I've commented them up.  The
6027090df5aSMatthew Dillon  *	actual code is straight forward.
6037090df5aSMatthew Dillon  *
6047090df5aSMatthew Dillon  */
6057090df5aSMatthew Dillon 
6067090df5aSMatthew Dillon /*
607bb4a27f9SMark Johnston  * BLST_NEXT_LEAF_ALLOC() - allocate the first few blocks in the next leaf.
608bb4a27f9SMark Johnston  *
609bb4a27f9SMark Johnston  *	'scan' is a leaf node, associated with a block containing 'blk'.
610bb4a27f9SMark Johnston  *	The next leaf node could be adjacent, or several nodes away if the
611bb4a27f9SMark Johnston  *	least common ancestor of 'scan' and its neighbor is several levels
612bb4a27f9SMark Johnston  *	up.  Use 'blk' to determine how many meta-nodes lie between the
613bb4a27f9SMark Johnston  *	leaves.  If the next leaf has enough initial bits set, clear them
614bb4a27f9SMark Johnston  *	and clear the bits in the meta nodes on the path up to the least
615bb4a27f9SMark Johnston  *	common ancestor to mark any subtrees made completely empty.
616bb4a27f9SMark Johnston  */
617bb4a27f9SMark Johnston static int
618bb4a27f9SMark Johnston blst_next_leaf_alloc(blmeta_t *scan, daddr_t blk, int count)
619bb4a27f9SMark Johnston {
620bb4a27f9SMark Johnston 	blmeta_t *next;
621bb4a27f9SMark Johnston 	u_daddr_t radix;
622bb4a27f9SMark Johnston 	int digit;
623bb4a27f9SMark Johnston 
624bb4a27f9SMark Johnston 	next = scan + 1;
625bb4a27f9SMark Johnston 	blk += BLIST_BMAP_RADIX;
626bb4a27f9SMark Johnston 	radix = BLIST_BMAP_RADIX;
627bb4a27f9SMark Johnston 	while ((digit = ((blk / radix) & BLIST_META_MASK)) == 0 &&
628bb4a27f9SMark Johnston 	    (next->bm_bitmap & 1) == 1) {
629bb4a27f9SMark Johnston 		next++;
630bb4a27f9SMark Johnston 		radix *= BLIST_META_RADIX;
631bb4a27f9SMark Johnston 	}
632bb4a27f9SMark Johnston 	if (((next->bm_bitmap + 1) & ~((u_daddr_t)-1 << count)) != 0) {
633bb4a27f9SMark Johnston 		/*
634bb4a27f9SMark Johnston 		 * The next leaf doesn't have enough free blocks at the
635bb4a27f9SMark Johnston 		 * beginning to complete the spanning allocation.
636bb4a27f9SMark Johnston 		 */
637bb4a27f9SMark Johnston 		return (ENOMEM);
638bb4a27f9SMark Johnston 	}
639bb4a27f9SMark Johnston 	/* Clear the first 'count' bits in the next leaf to allocate. */
640bb4a27f9SMark Johnston 	next->bm_bitmap &= (u_daddr_t)-1 << count;
641bb4a27f9SMark Johnston 
642bb4a27f9SMark Johnston 	/*
643bb4a27f9SMark Johnston 	 * Update bitmaps of next-ancestors, up to least common ancestor.
644bb4a27f9SMark Johnston 	 */
645d1c34a6bSDoug Moore 	while (next->bm_bitmap == 0) {
646d1c34a6bSDoug Moore 		if (--next == scan) {
647d1c34a6bSDoug Moore 			scan[-digit * radix_to_skip(radix)].bm_bitmap ^=
648d1c34a6bSDoug Moore 			    (u_daddr_t)1 << digit;
649d1c34a6bSDoug Moore 			break;
650bb4a27f9SMark Johnston 		}
651d1c34a6bSDoug Moore 		next->bm_bitmap ^= 1;
652d1c34a6bSDoug Moore  	}
653bb4a27f9SMark Johnston 	return (0);
654bb4a27f9SMark Johnston }
655bb4a27f9SMark Johnston 
656bb4a27f9SMark Johnston /*
65709b380a1SDoug Moore  * Given a bitmask, flip all the bits from the least-significant 1-bit to the
65809b380a1SDoug Moore  * most significant bit.  If the result is non-zero, then the least-significant
65909b380a1SDoug Moore  * 1-bit of the result is in the same position as the least-signification 0-bit
66009b380a1SDoug Moore  * in mask that is followed by a 1-bit.
66109b380a1SDoug Moore  */
66209b380a1SDoug Moore static inline u_daddr_t
66309b380a1SDoug Moore flip_hibits(u_daddr_t mask)
66409b380a1SDoug Moore {
66509b380a1SDoug Moore 
66609b380a1SDoug Moore 	return (-mask & ~mask);
66709b380a1SDoug Moore }
66809b380a1SDoug Moore 
66909b380a1SDoug Moore /*
670bb4a27f9SMark Johnston  * BLST_LEAF_ALLOC() -	allocate at a leaf in the radix tree (a bitmap).
6717090df5aSMatthew Dillon  *
6722905d1ceSAlan Cox  *	This function is the core of the allocator.  Its execution time is
6732905d1ceSAlan Cox  *	proportional to log(count), plus height of the tree if the allocation
6742905d1ceSAlan Cox  *	crosses a leaf boundary.
6757090df5aSMatthew Dillon  */
6767090df5aSMatthew Dillon static daddr_t
677ec371b57SAlan Cox blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count)
67854541421SAlan Cox {
6792905d1ceSAlan Cox 	u_daddr_t cursor_mask, mask;
680ec371b57SAlan Cox 	int count1, hi, lo, num_shifts, range1, range_ext;
6817090df5aSMatthew Dillon 
68254541421SAlan Cox 	range1 = 0;
68354541421SAlan Cox 	count1 = count - 1;
68454541421SAlan Cox 	num_shifts = fls(count1);
685bb4a27f9SMark Johnston 	mask = scan->bm_bitmap;
68609b380a1SDoug Moore 	while (flip_hibits(mask) != 0 && num_shifts > 0) {
68754541421SAlan Cox 		/*
68854541421SAlan Cox 		 * If bit i is set in mask, then bits in [i, i+range1] are set
6892905d1ceSAlan Cox 		 * in scan->bm_bitmap.  The value of range1 is equal to count1
6902905d1ceSAlan Cox 		 * >> num_shifts.  Grow range1 and reduce num_shifts to 0,
6912905d1ceSAlan Cox 		 * while preserving these invariants.  The updates to mask
6922905d1ceSAlan Cox 		 * leave fewer bits set, but each bit that remains set
6932905d1ceSAlan Cox 		 * represents a longer string of consecutive bits set in
6942905d1ceSAlan Cox 		 * scan->bm_bitmap.  If more updates to mask cannot clear more
6952905d1ceSAlan Cox 		 * bits, because mask is partitioned with all 0 bits preceding
6962905d1ceSAlan Cox 		 * all 1 bits, the loop terminates immediately.
69754541421SAlan Cox 		 */
69854541421SAlan Cox 		num_shifts--;
69954541421SAlan Cox 		range_ext = range1 + ((count1 >> num_shifts) & 1);
700ec371b57SAlan Cox 		/*
701ec371b57SAlan Cox 		 * mask is a signed quantity for the shift because when it is
702ec371b57SAlan Cox 		 * shifted right, the sign bit should copied; when the last
703ec371b57SAlan Cox 		 * block of the leaf is free, pretend, for a while, that all the
704ec371b57SAlan Cox 		 * blocks that follow it are also free.
705ec371b57SAlan Cox 		 */
706ec371b57SAlan Cox 		mask &= (daddr_t)mask >> range_ext;
70754541421SAlan Cox 		range1 += range_ext;
70854541421SAlan Cox 	}
70954541421SAlan Cox 	if (mask == 0) {
71054541421SAlan Cox 		/*
71154541421SAlan Cox 		 * Update bighint.  There is no allocation bigger than range1
712ec371b57SAlan Cox 		 * starting in this leaf.
71354541421SAlan Cox 		 */
71454541421SAlan Cox 		scan->bm_bighint = range1;
7157090df5aSMatthew Dillon 		return (SWAPBLK_NONE);
7167090df5aSMatthew Dillon 	}
71754541421SAlan Cox 
718ec371b57SAlan Cox 	/* Discard any candidates that appear before blk. */
7192905d1ceSAlan Cox 	if ((blk & BLIST_BMAP_MASK) != 0) {
7202905d1ceSAlan Cox 		cursor_mask = mask & bitrange(0, blk & BLIST_BMAP_MASK);
7212905d1ceSAlan Cox 		if (cursor_mask != 0) {
7222905d1ceSAlan Cox 			mask ^= cursor_mask;
72354541421SAlan Cox 			if (mask == 0)
72454541421SAlan Cox 				return (SWAPBLK_NONE);
7257090df5aSMatthew Dillon 
7267090df5aSMatthew Dillon 			/*
7272905d1ceSAlan Cox 			 * Bighint change for last block allocation cannot
7282905d1ceSAlan Cox 			 * assume that any other blocks are allocated, so the
7292905d1ceSAlan Cox 			 * bighint cannot be reduced much.
7302905d1ceSAlan Cox 			 */
7312905d1ceSAlan Cox 			range1 = BLIST_MAX_ALLOC - 1;
7322905d1ceSAlan Cox 		}
7332905d1ceSAlan Cox 		blk &= ~BLIST_BMAP_MASK;
7342905d1ceSAlan Cox 	}
7352905d1ceSAlan Cox 
7362905d1ceSAlan Cox 	/*
73754541421SAlan Cox 	 * The least significant set bit in mask marks the start of the first
73854541421SAlan Cox 	 * available range of sufficient size.  Clear all the bits but that one,
739d027ed2eSAlan Cox 	 * and then find its position.
7407090df5aSMatthew Dillon 	 */
74154541421SAlan Cox 	mask &= -mask;
742d027ed2eSAlan Cox 	lo = bitpos(mask);
7437090df5aSMatthew Dillon 
744ec371b57SAlan Cox 	hi = lo + count;
745ec371b57SAlan Cox 	if (hi > BLIST_BMAP_RADIX) {
74654541421SAlan Cox 		/*
747ec371b57SAlan Cox 		 * An allocation within this leaf is impossible, so a successful
748ec371b57SAlan Cox 		 * allocation depends on the next leaf providing some of the blocks.
74954541421SAlan Cox 		 */
750bb4a27f9SMark Johnston 		if (blst_next_leaf_alloc(scan, blk, hi - BLIST_BMAP_RADIX) != 0)
751ec371b57SAlan Cox 			/*
752bb4a27f9SMark Johnston 			 * The hint cannot be updated, because the same
753bb4a27f9SMark Johnston 			 * allocation request could be satisfied later, by this
754bb4a27f9SMark Johnston 			 * leaf, if the state of the next leaf changes, and
755bb4a27f9SMark Johnston 			 * without any changes to this leaf.
756ec371b57SAlan Cox 			 */
757ec371b57SAlan Cox 			return (SWAPBLK_NONE);
758ec371b57SAlan Cox 		hi = BLIST_BMAP_RADIX;
759ec371b57SAlan Cox 	}
760ec371b57SAlan Cox 
761ec371b57SAlan Cox 	/* Set the bits of mask at position 'lo' and higher. */
762ec371b57SAlan Cox 	mask = -mask;
763ec371b57SAlan Cox 	if (hi == BLIST_BMAP_RADIX) {
764ec371b57SAlan Cox 		/*
765ec371b57SAlan Cox 		 * Update bighint.  There is no allocation bigger than range1
766ec371b57SAlan Cox 		 * available in this leaf after this allocation completes.
767ec371b57SAlan Cox 		 */
768ec371b57SAlan Cox 		scan->bm_bighint = range1;
769ec371b57SAlan Cox 	} else {
770ec371b57SAlan Cox 		/* Clear the bits of mask at position 'hi' and higher. */
771ec371b57SAlan Cox 		mask &= (u_daddr_t)-1 >> (BLIST_BMAP_RADIX - hi);
772ec371b57SAlan Cox 	}
773ec371b57SAlan Cox 	/* Clear the allocated bits from this leaf. */
774bb4a27f9SMark Johnston 	scan->bm_bitmap &= ~mask;
7752905d1ceSAlan Cox 	return (blk + lo);
7767090df5aSMatthew Dillon }
7777090df5aSMatthew Dillon 
7787090df5aSMatthew Dillon /*
7797090df5aSMatthew Dillon  * blist_meta_alloc() -	allocate at a meta in the radix tree.
7807090df5aSMatthew Dillon  *
7817090df5aSMatthew Dillon  *	Attempt to allocate at a meta node.  If we can't, we update
7827090df5aSMatthew Dillon  *	bighint and return a failure.  Updating bighint optimize future
7837090df5aSMatthew Dillon  *	calls that hit this node.  We have to check for our collapse cases
7847090df5aSMatthew Dillon  *	and we have a few optimizations strewn in as well.
7857090df5aSMatthew Dillon  */
7867090df5aSMatthew Dillon static daddr_t
787bee93d3cSAlan Cox blst_meta_alloc(blmeta_t *scan, daddr_t cursor, daddr_t count, u_daddr_t radix)
788d4e3484bSAlan Cox {
789bb4a27f9SMark Johnston 	daddr_t blk, i, r, skip;
790*4ab18ea2SDoug Moore 	u_daddr_t mask;
791d4e3484bSAlan Cox 	bool scan_from_start;
792bb4a27f9SMark Johnston 	int digit;
7937090df5aSMatthew Dillon 
794a396c83aSAlan Cox 	if (radix == BLIST_BMAP_RADIX)
795ec371b57SAlan Cox 		return (blst_leaf_alloc(scan, cursor, count));
796ec371b57SAlan Cox 	blk = cursor & -radix;
797bb4a27f9SMark Johnston 	scan_from_start = (cursor == blk);
798bb4a27f9SMark Johnston 	radix /= BLIST_META_RADIX;
7992ac0c7c3SAlan Cox 	skip = radix_to_skip(radix);
800bb4a27f9SMark Johnston 	mask = scan->bm_bitmap;
801bb4a27f9SMark Johnston 
802bb4a27f9SMark Johnston 	/* Discard any candidates that appear before cursor. */
803bb4a27f9SMark Johnston 	digit = (cursor / radix) & BLIST_META_MASK;
804bb4a27f9SMark Johnston 	mask &= (u_daddr_t)-1 << digit;
805ee73fef9SAlan Cox 	if (mask == 0)
806ee73fef9SAlan Cox 		return (SWAPBLK_NONE);
8077090df5aSMatthew Dillon 
8084be4fd5dSAlan Cox 	/*
809bb4a27f9SMark Johnston 	 * If the first try is for a block that includes the cursor, pre-undo
810bb4a27f9SMark Johnston 	 * the digit * radix offset in the first call; otherwise, ignore the
811bb4a27f9SMark Johnston 	 * cursor entirely.
8124be4fd5dSAlan Cox 	 */
813bb4a27f9SMark Johnston 	if (((mask >> digit) & 1) == 1)
814bb4a27f9SMark Johnston 		cursor -= digit * radix;
815d4e3484bSAlan Cox 	else
816bb4a27f9SMark Johnston 		cursor = blk;
8177090df5aSMatthew Dillon 
8184be4fd5dSAlan Cox 	/*
819bb4a27f9SMark Johnston 	 * Examine the nonempty subtree associated with each bit set in mask.
8204be4fd5dSAlan Cox 	 */
821bb4a27f9SMark Johnston 	do {
822*4ab18ea2SDoug Moore 		digit = bitpos(mask);
823bb4a27f9SMark Johnston 		i = 1 + digit * skip;
8247090df5aSMatthew Dillon 		if (count <= scan[i].bm_bighint) {
8257090df5aSMatthew Dillon 			/*
826ec371b57SAlan Cox 			 * The allocation might fit beginning in the i'th subtree.
8277090df5aSMatthew Dillon 			 */
828bb4a27f9SMark Johnston 			r = blst_meta_alloc(&scan[i], cursor + digit * radix,
829bb4a27f9SMark Johnston 			    count, radix);
8307090df5aSMatthew Dillon 			if (r != SWAPBLK_NONE) {
831bb4a27f9SMark Johnston 				if (scan[i].bm_bitmap == 0)
832*4ab18ea2SDoug Moore 					scan->bm_bitmap ^= bitrange(digit, 1);
8337090df5aSMatthew Dillon 				return (r);
8347090df5aSMatthew Dillon 			}
8357090df5aSMatthew Dillon 		}
836bb4a27f9SMark Johnston 		cursor = blk;
837*4ab18ea2SDoug Moore 	} while ((mask ^= bitrange(digit, 1)) != 0);
8387090df5aSMatthew Dillon 
8397090df5aSMatthew Dillon 	/*
840bb4a27f9SMark Johnston 	 * We couldn't allocate count in this subtree.  If the whole tree was
841bb4a27f9SMark Johnston 	 * scanned, and the last tree node is allocated, update bighint.
8427090df5aSMatthew Dillon 	 */
843bb4a27f9SMark Johnston 	if (scan_from_start && !(digit == BLIST_META_RADIX - 1 &&
844bb4a27f9SMark Johnston 	    scan[i].bm_bighint == BLIST_MAX_ALLOC))
8457090df5aSMatthew Dillon 		scan->bm_bighint = count - 1;
846d4e3484bSAlan Cox 
8477090df5aSMatthew Dillon 	return (SWAPBLK_NONE);
8487090df5aSMatthew Dillon }
8497090df5aSMatthew Dillon 
8507090df5aSMatthew Dillon /*
8517090df5aSMatthew Dillon  * BLST_LEAF_FREE() -	free allocated block from leaf bitmap
8527090df5aSMatthew Dillon  *
8537090df5aSMatthew Dillon  */
8547090df5aSMatthew Dillon static void
855b411efa4SAlan Cox blst_leaf_free(blmeta_t *scan, daddr_t blk, int count)
856b411efa4SAlan Cox {
857ec371b57SAlan Cox 	u_daddr_t mask;
858ec371b57SAlan Cox 
8597090df5aSMatthew Dillon 	/*
8607090df5aSMatthew Dillon 	 * free some data in this bitmap
861ec371b57SAlan Cox 	 * mask=0000111111111110000
8627090df5aSMatthew Dillon 	 *          \_________/\__/
863ec371b57SAlan Cox 	 *		count   n
8647090df5aSMatthew Dillon 	 */
865bb4a27f9SMark Johnston 	mask = bitrange(blk & BLIST_BMAP_MASK, count);
866b1f59c92SDoug Moore 	KASSERT((scan->bm_bitmap & mask) == 0,
867b1f59c92SDoug Moore 	    ("freeing free block: %jx, size %d, mask %jx",
868b1f59c92SDoug Moore 	    (uintmax_t)blk, count, (uintmax_t)scan->bm_bitmap & mask));
869bb4a27f9SMark Johnston 	scan->bm_bitmap |= mask;
8707090df5aSMatthew Dillon }
8717090df5aSMatthew Dillon 
8727090df5aSMatthew Dillon /*
8737090df5aSMatthew Dillon  * BLST_META_FREE() - free allocated blocks from radix tree meta info
8747090df5aSMatthew Dillon  *
8757090df5aSMatthew Dillon  *	This support routine frees a range of blocks from the bitmap.
8767090df5aSMatthew Dillon  *	The range must be entirely enclosed by this radix node.  If a
8777090df5aSMatthew Dillon  *	meta node, we break the range down recursively to free blocks
8787090df5aSMatthew Dillon  *	in subnodes (which means that this code can free an arbitrary
8797090df5aSMatthew Dillon  *	range whereas the allocation code cannot allocate an arbitrary
8807090df5aSMatthew Dillon  *	range).
8817090df5aSMatthew Dillon  */
8827090df5aSMatthew Dillon static void
883bee93d3cSAlan Cox blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, u_daddr_t radix)
884d3783724SAlan Cox {
885bb4a27f9SMark Johnston 	daddr_t blk, endBlk, i, skip;
886bb4a27f9SMark Johnston 	int digit, endDigit;
8877090df5aSMatthew Dillon 
888bb4a27f9SMark Johnston 	/*
889bb4a27f9SMark Johnston 	 * We could probably do a better job here.  We are required to make
890bb4a27f9SMark Johnston 	 * bighint at least as large as the biggest allocable block of data.
891bb4a27f9SMark Johnston 	 * If we just shoehorn it, a little extra overhead will be incurred
892bb4a27f9SMark Johnston 	 * on the next allocation (but only that one typically).
893bb4a27f9SMark Johnston 	 */
894bb4a27f9SMark Johnston 	scan->bm_bighint = BLIST_MAX_ALLOC;
895bb4a27f9SMark Johnston 
896a396c83aSAlan Cox 	if (radix == BLIST_BMAP_RADIX)
897a396c83aSAlan Cox 		return (blst_leaf_free(scan, freeBlk, count));
8987090df5aSMatthew Dillon 
899bb4a27f9SMark Johnston 	endBlk = ummin(freeBlk + count, (freeBlk + radix) & -radix);
90057e6d29bSMatthew Dillon 	radix /= BLIST_META_RADIX;
901bb4a27f9SMark Johnston 	skip = radix_to_skip(radix);
902bb4a27f9SMark Johnston 	blk = freeBlk & -radix;
903bb4a27f9SMark Johnston 	digit = (blk / radix) & BLIST_META_MASK;
904bb4a27f9SMark Johnston 	endDigit = 1 + (((endBlk - 1) / radix) & BLIST_META_MASK);
905bb4a27f9SMark Johnston 	scan->bm_bitmap |= bitrange(digit, endDigit - digit);
906bb4a27f9SMark Johnston 	for (i = 1 + digit * skip; blk < endBlk; i += skip) {
9077090df5aSMatthew Dillon 		blk += radix;
908bb4a27f9SMark Johnston 		count = ummin(blk, endBlk) - freeBlk;
909bb4a27f9SMark Johnston 		blst_meta_free(&scan[i], freeBlk, count, radix);
910bb4a27f9SMark Johnston 		freeBlk = blk;
9117090df5aSMatthew Dillon 	}
9127090df5aSMatthew Dillon }
9137090df5aSMatthew Dillon 
9147090df5aSMatthew Dillon /*
915bb4a27f9SMark Johnston  * BLST_COPY() - copy one radix tree to another
9167090df5aSMatthew Dillon  *
9177090df5aSMatthew Dillon  *	Locates free space in the source tree and frees it in the destination
9187090df5aSMatthew Dillon  *	tree.  The space may not already be free in the destination.
9197090df5aSMatthew Dillon  */
920b411efa4SAlan Cox static void
9212ac0c7c3SAlan Cox blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, blist_t dest,
9222ac0c7c3SAlan Cox     daddr_t count)
923b411efa4SAlan Cox {
924bb4a27f9SMark Johnston 	daddr_t endBlk, i, skip;
9257090df5aSMatthew Dillon 
9267090df5aSMatthew Dillon 	/*
9277090df5aSMatthew Dillon 	 * Leaf node
9287090df5aSMatthew Dillon 	 */
9297090df5aSMatthew Dillon 
9307090df5aSMatthew Dillon 	if (radix == BLIST_BMAP_RADIX) {
931bb4a27f9SMark Johnston 		u_daddr_t v = scan->bm_bitmap;
9327090df5aSMatthew Dillon 
9337090df5aSMatthew Dillon 		if (v == (u_daddr_t)-1) {
9347090df5aSMatthew Dillon 			blist_free(dest, blk, count);
9357090df5aSMatthew Dillon 		} else if (v != 0) {
9367090df5aSMatthew Dillon 			int i;
9377090df5aSMatthew Dillon 
938bb4a27f9SMark Johnston 			for (i = 0; i < count; ++i) {
939064650c1SAlan Cox 				if (v & ((u_daddr_t)1 << i))
9407090df5aSMatthew Dillon 					blist_free(dest, blk + i, 1);
9417090df5aSMatthew Dillon 			}
9427090df5aSMatthew Dillon 		}
9437090df5aSMatthew Dillon 		return;
9447090df5aSMatthew Dillon 	}
9457090df5aSMatthew Dillon 
9467090df5aSMatthew Dillon 	/*
9477090df5aSMatthew Dillon 	 * Meta node
9487090df5aSMatthew Dillon 	 */
9497090df5aSMatthew Dillon 
950bb4a27f9SMark Johnston 	if (scan->bm_bitmap == 0) {
9517090df5aSMatthew Dillon 		/*
9527090df5aSMatthew Dillon 		 * Source all allocated, leave dest allocated
9537090df5aSMatthew Dillon 		 */
9547090df5aSMatthew Dillon 		return;
9557090df5aSMatthew Dillon 	}
9567090df5aSMatthew Dillon 
957bb4a27f9SMark Johnston 	endBlk = blk + count;
9582ac0c7c3SAlan Cox 	radix /= BLIST_META_RADIX;
959bb4a27f9SMark Johnston 	skip = radix_to_skip(radix);
960bb4a27f9SMark Johnston 	for (i = 1; blk < endBlk; i += skip) {
9617090df5aSMatthew Dillon 		blk += radix;
962bb4a27f9SMark Johnston 		count = radix;
963bb4a27f9SMark Johnston 		if (blk >= endBlk)
964bb4a27f9SMark Johnston 			count -= blk - endBlk;
965bb4a27f9SMark Johnston 		blst_copy(&scan[i], blk - radix, radix, dest, count);
9667090df5aSMatthew Dillon 	}
9677090df5aSMatthew Dillon }
9687090df5aSMatthew Dillon 
9697090df5aSMatthew Dillon /*
97092da00bbSMatthew Dillon  * BLST_LEAF_FILL() -	allocate specific blocks in leaf bitmap
97192da00bbSMatthew Dillon  *
97292da00bbSMatthew Dillon  *	This routine allocates all blocks in the specified range
97392da00bbSMatthew Dillon  *	regardless of any existing allocations in that range.  Returns
97492da00bbSMatthew Dillon  *	the number of blocks allocated by the call.
97592da00bbSMatthew Dillon  */
976a7249a6cSAlan Cox static daddr_t
97792da00bbSMatthew Dillon blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count)
97892da00bbSMatthew Dillon {
979a7249a6cSAlan Cox 	daddr_t nblks;
9804be4fd5dSAlan Cox 	u_daddr_t mask;
98192da00bbSMatthew Dillon 
982bb4a27f9SMark Johnston 	mask = bitrange(blk & BLIST_BMAP_MASK, count);
98392da00bbSMatthew Dillon 
9844be4fd5dSAlan Cox 	/* Count the number of blocks that we are allocating. */
985bb4a27f9SMark Johnston 	nblks = bitcount64(scan->bm_bitmap & mask);
98692da00bbSMatthew Dillon 
987bb4a27f9SMark Johnston 	scan->bm_bitmap &= ~mask;
9884be4fd5dSAlan Cox 	return (nblks);
98992da00bbSMatthew Dillon }
99092da00bbSMatthew Dillon 
99192da00bbSMatthew Dillon /*
99292da00bbSMatthew Dillon  * BLIST_META_FILL() -	allocate specific blocks at a meta node
99392da00bbSMatthew Dillon  *
99492da00bbSMatthew Dillon  *	This routine allocates the specified range of blocks,
99592da00bbSMatthew Dillon  *	regardless of any existing allocations in the range.  The
99692da00bbSMatthew Dillon  *	range must be within the extent of this node.  Returns the
99792da00bbSMatthew Dillon  *	number of blocks allocated by the call.
99892da00bbSMatthew Dillon  */
999a7249a6cSAlan Cox static daddr_t
1000bee93d3cSAlan Cox blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, u_daddr_t radix)
1001d3783724SAlan Cox {
1002bb4a27f9SMark Johnston 	daddr_t blk, endBlk, i, nblks, skip;
1003bb4a27f9SMark Johnston 	int digit;
100492da00bbSMatthew Dillon 
1005a396c83aSAlan Cox 	if (radix == BLIST_BMAP_RADIX)
1006a396c83aSAlan Cox 		return (blst_leaf_fill(scan, allocBlk, count));
1007bb4a27f9SMark Johnston 
1008bb4a27f9SMark Johnston 	endBlk = ummin(allocBlk + count, (allocBlk + radix) & -radix);
1009bb4a27f9SMark Johnston 	radix /= BLIST_META_RADIX;
10102ac0c7c3SAlan Cox 	skip = radix_to_skip(radix);
1011bee93d3cSAlan Cox 	blk = allocBlk & -radix;
1012d3783724SAlan Cox 	nblks = 0;
1013bb4a27f9SMark Johnston 	while (blk < endBlk) {
1014bb4a27f9SMark Johnston 		digit = (blk / radix) & BLIST_META_MASK;
1015bb4a27f9SMark Johnston 		i = 1 + digit * skip;
101692da00bbSMatthew Dillon 		blk += radix;
1017bb4a27f9SMark Johnston 		count = ummin(blk, endBlk) - allocBlk;
1018bb4a27f9SMark Johnston 		nblks += blst_meta_fill(&scan[i], allocBlk, count, radix);
1019bb4a27f9SMark Johnston 		if (scan[i].bm_bitmap == 0)
1020bb4a27f9SMark Johnston 			scan->bm_bitmap &= ~((u_daddr_t)1 << digit);
1021bb4a27f9SMark Johnston 		allocBlk = blk;
102292da00bbSMatthew Dillon 	}
1023a396c83aSAlan Cox 	return (nblks);
102492da00bbSMatthew Dillon }
102592da00bbSMatthew Dillon 
10267090df5aSMatthew Dillon #ifdef BLIST_DEBUG
10277090df5aSMatthew Dillon 
10287090df5aSMatthew Dillon static void
10292ac0c7c3SAlan Cox blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab)
10307090df5aSMatthew Dillon {
1031bb4a27f9SMark Johnston 	daddr_t skip;
1032*4ab18ea2SDoug Moore 	u_daddr_t mask;
1033bb4a27f9SMark Johnston 	int digit;
10347090df5aSMatthew Dillon 
10357090df5aSMatthew Dillon 	if (radix == BLIST_BMAP_RADIX) {
10367090df5aSMatthew Dillon 		printf(
1037bb4a27f9SMark Johnston 		    "%*.*s(%08llx,%lld): bitmap %0*llx big=%lld\n",
10387090df5aSMatthew Dillon 		    tab, tab, "",
103992da00bbSMatthew Dillon 		    (long long)blk, (long long)radix,
1040bb4a27f9SMark Johnston 		    1 + (BLIST_BMAP_RADIX - 1) / 4,
1041bb4a27f9SMark Johnston 		    (long long)scan->bm_bitmap,
104292da00bbSMatthew Dillon 		    (long long)scan->bm_bighint
10437090df5aSMatthew Dillon 		);
10447090df5aSMatthew Dillon 		return;
10457090df5aSMatthew Dillon 	}
10467090df5aSMatthew Dillon 
10477090df5aSMatthew Dillon 	printf(
1048bb4a27f9SMark Johnston 	    "%*.*s(%08llx): subtree (%lld/%lld) bitmap %0*llx big=%lld {\n",
10497090df5aSMatthew Dillon 	    tab, tab, "",
105092da00bbSMatthew Dillon 	    (long long)blk, (long long)radix,
105192da00bbSMatthew Dillon 	    (long long)radix,
1052bb4a27f9SMark Johnston 	    1 + (BLIST_META_RADIX - 1) / 4,
1053bb4a27f9SMark Johnston 	    (long long)scan->bm_bitmap,
105492da00bbSMatthew Dillon 	    (long long)scan->bm_bighint
10557090df5aSMatthew Dillon 	);
10567090df5aSMatthew Dillon 
10572ac0c7c3SAlan Cox 	radix /= BLIST_META_RADIX;
1058bb4a27f9SMark Johnston 	skip = radix_to_skip(radix);
10597090df5aSMatthew Dillon 	tab += 4;
10607090df5aSMatthew Dillon 
1061bb4a27f9SMark Johnston 	mask = scan->bm_bitmap;
1062bb4a27f9SMark Johnston 	/* Examine the nonempty subtree associated with each bit set in mask */
1063bb4a27f9SMark Johnston 	do {
1064*4ab18ea2SDoug Moore 		digit = bitpos(mask);
1065bb4a27f9SMark Johnston 		blst_radix_print(&scan[1 + digit * skip], blk + digit * radix,
1066bb4a27f9SMark Johnston 		    radix, tab);
1067*4ab18ea2SDoug Moore 	} while ((mask ^= bitrange(digit, 1)) != 0);
10687090df5aSMatthew Dillon 	tab -= 4;
10697090df5aSMatthew Dillon 
10707090df5aSMatthew Dillon 	printf(
10717090df5aSMatthew Dillon 	    "%*.*s}\n",
10727090df5aSMatthew Dillon 	    tab, tab, ""
10737090df5aSMatthew Dillon 	);
10747090df5aSMatthew Dillon }
10757090df5aSMatthew Dillon 
10767090df5aSMatthew Dillon #endif
10777090df5aSMatthew Dillon 
10787090df5aSMatthew Dillon #ifdef BLIST_DEBUG
10797090df5aSMatthew Dillon 
10807090df5aSMatthew Dillon int
10817090df5aSMatthew Dillon main(int ac, char **av)
10827090df5aSMatthew Dillon {
1083bb4a27f9SMark Johnston 	int size = BLIST_META_RADIX * BLIST_BMAP_RADIX;
10847090df5aSMatthew Dillon 	int i;
10857090df5aSMatthew Dillon 	blist_t bl;
1086d027ed2eSAlan Cox 	struct sbuf *s;
10877090df5aSMatthew Dillon 
10887090df5aSMatthew Dillon 	for (i = 1; i < ac; ++i) {
10897090df5aSMatthew Dillon 		const char *ptr = av[i];
10907090df5aSMatthew Dillon 		if (*ptr != '-') {
10917090df5aSMatthew Dillon 			size = strtol(ptr, NULL, 0);
10927090df5aSMatthew Dillon 			continue;
10937090df5aSMatthew Dillon 		}
10947090df5aSMatthew Dillon 		ptr += 2;
10957090df5aSMatthew Dillon 		fprintf(stderr, "Bad option: %s\n", ptr - 2);
10967090df5aSMatthew Dillon 		exit(1);
10977090df5aSMatthew Dillon 	}
1098c8c7ad92SKip Macy 	bl = blist_create(size, M_WAITOK);
10997090df5aSMatthew Dillon 	blist_free(bl, 0, size);
11007090df5aSMatthew Dillon 
11017090df5aSMatthew Dillon 	for (;;) {
11027090df5aSMatthew Dillon 		char buf[1024];
1103d90bf7d8SAlan Cox 		long long da = 0;
1104d90bf7d8SAlan Cox 		long long count = 0;
11057090df5aSMatthew Dillon 
11064be4fd5dSAlan Cox 		printf("%lld/%lld/%lld> ", (long long)blist_avail(bl),
110792da00bbSMatthew Dillon 		    (long long)size, (long long)bl->bl_radix);
11087090df5aSMatthew Dillon 		fflush(stdout);
11097090df5aSMatthew Dillon 		if (fgets(buf, sizeof(buf), stdin) == NULL)
11107090df5aSMatthew Dillon 			break;
11117090df5aSMatthew Dillon 		switch(buf[0]) {
11127090df5aSMatthew Dillon 		case 'r':
111392da00bbSMatthew Dillon 			if (sscanf(buf + 1, "%lld", &count) == 1) {
1114d90bf7d8SAlan Cox 				blist_resize(&bl, count, 1, M_WAITOK);
11157090df5aSMatthew Dillon 			} else {
11167090df5aSMatthew Dillon 				printf("?\n");
11177090df5aSMatthew Dillon 			}
11187090df5aSMatthew Dillon 		case 'p':
11197090df5aSMatthew Dillon 			blist_print(bl);
11207090df5aSMatthew Dillon 			break;
1121d027ed2eSAlan Cox 		case 's':
1122d027ed2eSAlan Cox 			s = sbuf_new_auto();
1123d027ed2eSAlan Cox 			blist_stats(bl, s);
1124d027ed2eSAlan Cox 			sbuf_finish(s);
1125d027ed2eSAlan Cox 			printf("%s", sbuf_data(s));
1126d027ed2eSAlan Cox 			sbuf_delete(s);
1127d027ed2eSAlan Cox 			break;
11287090df5aSMatthew Dillon 		case 'a':
112992da00bbSMatthew Dillon 			if (sscanf(buf + 1, "%lld", &count) == 1) {
11307090df5aSMatthew Dillon 				daddr_t blk = blist_alloc(bl, count);
113192da00bbSMatthew Dillon 				printf("    R=%08llx\n", (long long)blk);
11327090df5aSMatthew Dillon 			} else {
11337090df5aSMatthew Dillon 				printf("?\n");
11347090df5aSMatthew Dillon 			}
11357090df5aSMatthew Dillon 			break;
11367090df5aSMatthew Dillon 		case 'f':
1137d90bf7d8SAlan Cox 			if (sscanf(buf + 1, "%llx %lld", &da, &count) == 2) {
11387090df5aSMatthew Dillon 				blist_free(bl, da, count);
11397090df5aSMatthew Dillon 			} else {
11407090df5aSMatthew Dillon 				printf("?\n");
11417090df5aSMatthew Dillon 			}
11427090df5aSMatthew Dillon 			break;
114392da00bbSMatthew Dillon 		case 'l':
1144d90bf7d8SAlan Cox 			if (sscanf(buf + 1, "%llx %lld", &da, &count) == 2) {
1145a7249a6cSAlan Cox 				printf("    n=%jd\n",
1146a7249a6cSAlan Cox 				    (intmax_t)blist_fill(bl, da, count));
114792da00bbSMatthew Dillon 			} else {
114892da00bbSMatthew Dillon 				printf("?\n");
114992da00bbSMatthew Dillon 			}
115092da00bbSMatthew Dillon 			break;
11517090df5aSMatthew Dillon 		case '?':
11527090df5aSMatthew Dillon 		case 'h':
11537090df5aSMatthew Dillon 			puts(
11547090df5aSMatthew Dillon 			    "p          -print\n"
1155d027ed2eSAlan Cox 			    "s          -stats\n"
11567090df5aSMatthew Dillon 			    "a %d       -allocate\n"
11577090df5aSMatthew Dillon 			    "f %x %d    -free\n"
115892da00bbSMatthew Dillon 			    "l %x %d    -fill\n"
11597090df5aSMatthew Dillon 			    "r %d       -resize\n"
1160d4808c44SDoug Moore 			    "h/?        -help\n"
1161d4808c44SDoug Moore 			    "q          -quit"
11627090df5aSMatthew Dillon 			);
11637090df5aSMatthew Dillon 			break;
1164d4808c44SDoug Moore 		case 'q':
1165d4808c44SDoug Moore 			break;
11667090df5aSMatthew Dillon 		default:
11677090df5aSMatthew Dillon 			printf("?\n");
11687090df5aSMatthew Dillon 			break;
11697090df5aSMatthew Dillon 		}
1170d4808c44SDoug Moore 		if (buf[0] == 'q')
1171d4808c44SDoug Moore 			break;
11727090df5aSMatthew Dillon 	}
11737090df5aSMatthew Dillon 	return (0);
11747090df5aSMatthew Dillon }
11757090df5aSMatthew Dillon 
11767090df5aSMatthew Dillon #endif
1177