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)) 12431c82722SDoug Moore #define imin(a,b) ((a) < (b) ? (a) : (b)) 125b1f59c92SDoug Moore #define KASSERT(a,b) assert(a) 1267090df5aSMatthew Dillon 1277090df5aSMatthew Dillon #include <sys/blist.h> 1287090df5aSMatthew Dillon 1297090df5aSMatthew Dillon #endif 1307090df5aSMatthew Dillon 1317090df5aSMatthew Dillon /* 1327090df5aSMatthew Dillon * static support functions 1337090df5aSMatthew Dillon */ 13487ae0686SDoug Moore static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, 13587ae0686SDoug Moore int *count, int maxcount); 13687ae0686SDoug Moore static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t cursor, int *count, 13787ae0686SDoug Moore int maxcount, u_daddr_t radix); 1387090df5aSMatthew Dillon static void blst_leaf_free(blmeta_t *scan, daddr_t relblk, int count); 1397090df5aSMatthew Dillon static void blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, 140bee93d3cSAlan Cox u_daddr_t radix); 1417090df5aSMatthew Dillon static void blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, 1422ac0c7c3SAlan Cox blist_t dest, daddr_t count); 143a7249a6cSAlan Cox static daddr_t blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count); 144a7249a6cSAlan Cox static daddr_t blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, 145bee93d3cSAlan Cox u_daddr_t radix); 146c4473420SPeter Wemm #ifndef _KERNEL 147d3783724SAlan Cox static void blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, 1482ac0c7c3SAlan Cox int tab); 1497090df5aSMatthew Dillon #endif 1507090df5aSMatthew Dillon 151c4473420SPeter Wemm #ifdef _KERNEL 1527090df5aSMatthew Dillon static MALLOC_DEFINE(M_SWAP, "SWAP", "Swap space"); 1537090df5aSMatthew Dillon #endif 1547090df5aSMatthew Dillon 155ec371b57SAlan Cox _Static_assert(BLIST_BMAP_RADIX % BLIST_META_RADIX == 0, 156ec371b57SAlan Cox "radix divisibility error"); 157ec371b57SAlan Cox #define BLIST_BMAP_MASK (BLIST_BMAP_RADIX - 1) 158d027ed2eSAlan Cox #define BLIST_META_MASK (BLIST_META_RADIX - 1) 159ba98e6a2SAlan Cox 1607090df5aSMatthew Dillon /* 1612ac0c7c3SAlan Cox * For a subtree that can represent the state of up to 'radix' blocks, the 1622ac0c7c3SAlan Cox * number of leaf nodes of the subtree is L=radix/BLIST_BMAP_RADIX. If 'm' 1632ac0c7c3SAlan Cox * is short for BLIST_META_RADIX, then for a tree of height h with L=m**h 1642ac0c7c3SAlan Cox * leaf nodes, the total number of tree nodes is 1 + m + m**2 + ... + m**h, 1652ac0c7c3SAlan Cox * or, equivalently, (m**(h+1)-1)/(m-1). This quantity is called 'skip' 1662ac0c7c3SAlan Cox * in the 'meta' functions that process subtrees. Since integer division 1672ac0c7c3SAlan Cox * discards remainders, we can express this computation as 1682ac0c7c3SAlan Cox * skip = (m * m**h) / (m - 1) 169ba98e6a2SAlan Cox * skip = (m * (radix / BLIST_BMAP_RADIX)) / (m - 1) 170ba98e6a2SAlan Cox * and since m divides BLIST_BMAP_RADIX, we can simplify further to 171ba98e6a2SAlan Cox * skip = (radix / (BLIST_BMAP_RADIX / m)) / (m - 1) 172ba98e6a2SAlan Cox * skip = radix / ((BLIST_BMAP_RADIX / m) * (m - 1)) 173ba98e6a2SAlan Cox * so that simple integer division by a constant can safely be used for the 174ba98e6a2SAlan Cox * calculation. 1752ac0c7c3SAlan Cox */ 1762ac0c7c3SAlan Cox static inline daddr_t 1772ac0c7c3SAlan Cox radix_to_skip(daddr_t radix) 1782ac0c7c3SAlan Cox { 1792ac0c7c3SAlan Cox 1802ac0c7c3SAlan Cox return (radix / 181d027ed2eSAlan Cox ((BLIST_BMAP_RADIX / BLIST_META_RADIX) * BLIST_META_MASK)); 182d027ed2eSAlan Cox } 183d027ed2eSAlan Cox 184d027ed2eSAlan Cox /* 185bb4a27f9SMark Johnston * Provide a mask with count bits set, starting as position n. 186bb4a27f9SMark Johnston */ 187bb4a27f9SMark Johnston static inline u_daddr_t 188bb4a27f9SMark Johnston bitrange(int n, int count) 189bb4a27f9SMark Johnston { 190bb4a27f9SMark Johnston 191bb4a27f9SMark Johnston return (((u_daddr_t)-1 << n) & 192bb4a27f9SMark Johnston ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - (n + count)))); 193bb4a27f9SMark Johnston } 194bb4a27f9SMark Johnston 195bb4a27f9SMark Johnston 196bb4a27f9SMark Johnston /* 19753519253SDoug Moore * Find the first bit set in a u_daddr_t. 198d027ed2eSAlan Cox */ 199d027ed2eSAlan Cox static inline int 20053519253SDoug Moore generic_bitpos(u_daddr_t mask) 20153519253SDoug Moore { 20253519253SDoug Moore int hi, lo, mid; 20353519253SDoug Moore 20453519253SDoug Moore lo = 0; 20553519253SDoug Moore hi = BLIST_BMAP_RADIX; 20653519253SDoug Moore while (lo + 1 < hi) { 20753519253SDoug Moore mid = (lo + hi) >> 1; 20853519253SDoug Moore if (mask & bitrange(0, mid)) 20953519253SDoug Moore hi = mid; 21053519253SDoug Moore else 21153519253SDoug Moore lo = mid; 21253519253SDoug Moore } 21353519253SDoug Moore return (lo); 21453519253SDoug Moore } 21553519253SDoug Moore 21653519253SDoug Moore static inline int 2174ab18ea2SDoug Moore bitpos(u_daddr_t mask) 2184ab18ea2SDoug Moore { 2194ab18ea2SDoug Moore 22012cd7dedSDoug Moore switch (sizeof(mask)) { 2214ab18ea2SDoug Moore #ifdef HAVE_INLINE_FFSLL 22212cd7dedSDoug Moore case sizeof(long long): 22312cd7dedSDoug Moore return (ffsll(mask) - 1); 2244ab18ea2SDoug Moore #endif 22553519253SDoug Moore #ifdef HAVE_INLINE_FFS 22653519253SDoug Moore case sizeof(int): 22753519253SDoug Moore return (ffs(mask) - 1); 22853519253SDoug Moore #endif 22912cd7dedSDoug Moore default: 23053519253SDoug Moore return (generic_bitpos(mask)); 23112cd7dedSDoug Moore } 2322ac0c7c3SAlan Cox } 2332ac0c7c3SAlan Cox 2342ac0c7c3SAlan Cox /* 2357090df5aSMatthew Dillon * blist_create() - create a blist capable of handling up to the specified 2367090df5aSMatthew Dillon * number of blocks 2377090df5aSMatthew Dillon * 238f565f395SEitan Adler * blocks - must be greater than 0 239c8c7ad92SKip Macy * flags - malloc flags 2407090df5aSMatthew Dillon * 2417090df5aSMatthew Dillon * The smallest blist consists of a single leaf node capable of 2427090df5aSMatthew Dillon * managing BLIST_BMAP_RADIX blocks. 2437090df5aSMatthew Dillon */ 2447090df5aSMatthew Dillon blist_t 245c8c7ad92SKip Macy blist_create(daddr_t blocks, int flags) 2467090df5aSMatthew Dillon { 2477090df5aSMatthew Dillon blist_t bl; 248bb4a27f9SMark Johnston u_daddr_t nodes, radix; 2497090df5aSMatthew Dillon 250b1f59c92SDoug Moore KASSERT(blocks > 0, ("invalid block count")); 251ce9eea64SMark Johnston 2527090df5aSMatthew Dillon /* 253ce9eea64SMark Johnston * Calculate the radix and node count used for scanning. 2547090df5aSMatthew Dillon */ 255bb4a27f9SMark Johnston nodes = 1; 2567090df5aSMatthew Dillon radix = BLIST_BMAP_RADIX; 257bb4a27f9SMark Johnston while (radix <= blocks) { 258bb4a27f9SMark Johnston nodes += 1 + (blocks - 1) / radix; 25957e6d29bSMatthew Dillon radix *= BLIST_META_RADIX; 2607090df5aSMatthew Dillon } 2617090df5aSMatthew Dillon 26203ca2137SAlan Cox bl = malloc(offsetof(struct blist, bl_root[nodes]), M_SWAP, flags | 26303ca2137SAlan Cox M_ZERO); 264015d7db6SAlan Cox if (bl == NULL) 265015d7db6SAlan Cox return (NULL); 2667090df5aSMatthew Dillon 2677090df5aSMatthew Dillon bl->bl_blocks = blocks; 2687090df5aSMatthew Dillon bl->bl_radix = radix; 2697090df5aSMatthew Dillon 2707090df5aSMatthew Dillon #if defined(BLIST_DEBUG) 2717090df5aSMatthew Dillon printf( 27292da00bbSMatthew Dillon "BLIST representing %lld blocks (%lld MB of swap)" 27392da00bbSMatthew Dillon ", requiring %lldK of ram\n", 27492da00bbSMatthew Dillon (long long)bl->bl_blocks, 27592da00bbSMatthew Dillon (long long)bl->bl_blocks * 4 / 1024, 276015d7db6SAlan Cox (long long)(nodes * sizeof(blmeta_t) + 1023) / 1024 2777090df5aSMatthew Dillon ); 27892da00bbSMatthew Dillon printf("BLIST raw radix tree contains %lld records\n", 279015d7db6SAlan Cox (long long)nodes); 2807090df5aSMatthew Dillon #endif 2817090df5aSMatthew Dillon 2827090df5aSMatthew Dillon return (bl); 2837090df5aSMatthew Dillon } 2847090df5aSMatthew Dillon 2857090df5aSMatthew Dillon void 2867090df5aSMatthew Dillon blist_destroy(blist_t bl) 2877090df5aSMatthew Dillon { 2888eefcd40SAlan Cox 2897090df5aSMatthew Dillon free(bl, M_SWAP); 2907090df5aSMatthew Dillon } 2917090df5aSMatthew Dillon 2927090df5aSMatthew Dillon /* 2937090df5aSMatthew Dillon * blist_alloc() - reserve space in the block bitmap. Return the base 2947090df5aSMatthew Dillon * of a contiguous region or SWAPBLK_NONE if space could 2957090df5aSMatthew Dillon * not be allocated. 2967090df5aSMatthew Dillon */ 2977090df5aSMatthew Dillon daddr_t 29887ae0686SDoug Moore blist_alloc(blist_t bl, int *count, int maxcount) 2997090df5aSMatthew Dillon { 30027d172bbSDoug Moore daddr_t blk, cursor; 3017090df5aSMatthew Dillon 30287ae0686SDoug Moore KASSERT(*count <= maxcount, 30387ae0686SDoug Moore ("invalid parameters %d > %d", *count, maxcount)); 30431c82722SDoug Moore KASSERT(*count <= BLIST_MAX_ALLOC, 30531c82722SDoug Moore ("minimum allocation too large: %d", *count)); 306bb4a27f9SMark Johnston 307d4e3484bSAlan Cox /* 308d4e3484bSAlan Cox * This loop iterates at most twice. An allocation failure in the 309d4e3484bSAlan Cox * first iteration leads to a second iteration only if the cursor was 310d4e3484bSAlan Cox * non-zero. When the cursor is zero, an allocation failure will 311749cdf6fSAlan Cox * stop further iterations. 312d4e3484bSAlan Cox */ 31387ae0686SDoug Moore for (cursor = bl->bl_cursor;; cursor = 0) { 31487ae0686SDoug Moore blk = blst_meta_alloc(bl->bl_root, cursor, count, maxcount, 315bee93d3cSAlan Cox bl->bl_radix); 316d4e3484bSAlan Cox if (blk != SWAPBLK_NONE) { 31787ae0686SDoug Moore bl->bl_avail -= *count; 31887ae0686SDoug Moore bl->bl_cursor = blk + *count; 319a0ae476bSAlan Cox if (bl->bl_cursor == bl->bl_blocks) 320a0ae476bSAlan Cox bl->bl_cursor = 0; 3217090df5aSMatthew Dillon return (blk); 32287ae0686SDoug Moore } 32387ae0686SDoug Moore if (cursor == 0) 324749cdf6fSAlan Cox return (SWAPBLK_NONE); 3257090df5aSMatthew Dillon } 3264be4fd5dSAlan Cox } 3274be4fd5dSAlan Cox 3284be4fd5dSAlan Cox /* 3294be4fd5dSAlan Cox * blist_avail() - return the number of free blocks. 3304be4fd5dSAlan Cox */ 3314be4fd5dSAlan Cox daddr_t 3324be4fd5dSAlan Cox blist_avail(blist_t bl) 3334be4fd5dSAlan Cox { 3344be4fd5dSAlan Cox 335bb4a27f9SMark Johnston return (bl->bl_avail); 3364be4fd5dSAlan Cox } 3377090df5aSMatthew Dillon 3387090df5aSMatthew Dillon /* 3397090df5aSMatthew Dillon * blist_free() - free up space in the block bitmap. Return the base 340b1f59c92SDoug Moore * of a contiguous region. 3417090df5aSMatthew Dillon */ 3427090df5aSMatthew Dillon void 3437090df5aSMatthew Dillon blist_free(blist_t bl, daddr_t blkno, daddr_t count) 3447090df5aSMatthew Dillon { 345a396c83aSAlan Cox 346b1f59c92SDoug Moore KASSERT(blkno >= 0 && blkno + count <= bl->bl_blocks, 347b1f59c92SDoug Moore ("freeing invalid range: blkno %jx, count %d, blocks %jd", 348b1f59c92SDoug Moore (uintmax_t)blkno, (int)count, (uintmax_t)bl->bl_blocks)); 349bee93d3cSAlan Cox blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix); 350bb4a27f9SMark Johnston bl->bl_avail += count; 3517090df5aSMatthew Dillon } 3527090df5aSMatthew Dillon 3537090df5aSMatthew Dillon /* 35492da00bbSMatthew Dillon * blist_fill() - mark a region in the block bitmap as off-limits 35592da00bbSMatthew Dillon * to the allocator (i.e. allocate it), ignoring any 35692da00bbSMatthew Dillon * existing allocations. Return the number of blocks 35792da00bbSMatthew Dillon * actually filled that were free before the call. 35892da00bbSMatthew Dillon */ 359a7249a6cSAlan Cox daddr_t 36092da00bbSMatthew Dillon blist_fill(blist_t bl, daddr_t blkno, daddr_t count) 36192da00bbSMatthew Dillon { 362bb4a27f9SMark Johnston daddr_t filled; 36392da00bbSMatthew Dillon 364b1f59c92SDoug Moore KASSERT(blkno >= 0 && blkno + count <= bl->bl_blocks, 365b1f59c92SDoug Moore ("filling invalid range: blkno %jx, count %d, blocks %jd", 366b1f59c92SDoug Moore (uintmax_t)blkno, (int)count, (uintmax_t)bl->bl_blocks)); 367bb4a27f9SMark Johnston filled = blst_meta_fill(bl->bl_root, blkno, count, bl->bl_radix); 368bb4a27f9SMark Johnston bl->bl_avail -= filled; 369bb4a27f9SMark Johnston return (filled); 37092da00bbSMatthew Dillon } 37192da00bbSMatthew Dillon 37292da00bbSMatthew Dillon /* 3737090df5aSMatthew Dillon * blist_resize() - resize an existing radix tree to handle the 3747090df5aSMatthew Dillon * specified number of blocks. This will reallocate 3757090df5aSMatthew Dillon * the tree and transfer the previous bitmap to the new 3767090df5aSMatthew Dillon * one. When extending the tree you can specify whether 3777090df5aSMatthew Dillon * the new blocks are to left allocated or freed. 3787090df5aSMatthew Dillon */ 3797090df5aSMatthew Dillon void 380c8c7ad92SKip Macy blist_resize(blist_t *pbl, daddr_t count, int freenew, int flags) 3817090df5aSMatthew Dillon { 382c8c7ad92SKip Macy blist_t newbl = blist_create(count, flags); 3837090df5aSMatthew Dillon blist_t save = *pbl; 3847090df5aSMatthew Dillon 3857090df5aSMatthew Dillon *pbl = newbl; 3867090df5aSMatthew Dillon if (count > save->bl_blocks) 3877090df5aSMatthew Dillon count = save->bl_blocks; 3882ac0c7c3SAlan Cox blst_copy(save->bl_root, 0, save->bl_radix, newbl, count); 3897090df5aSMatthew Dillon 3907090df5aSMatthew Dillon /* 3917090df5aSMatthew Dillon * If resizing upwards, should we free the new space or not? 3927090df5aSMatthew Dillon */ 3937090df5aSMatthew Dillon if (freenew && count < newbl->bl_blocks) { 3947090df5aSMatthew Dillon blist_free(newbl, count, newbl->bl_blocks - count); 3957090df5aSMatthew Dillon } 3967090df5aSMatthew Dillon blist_destroy(save); 3977090df5aSMatthew Dillon } 3987090df5aSMatthew Dillon 3997090df5aSMatthew Dillon #ifdef BLIST_DEBUG 4007090df5aSMatthew Dillon 4017090df5aSMatthew Dillon /* 4027090df5aSMatthew Dillon * blist_print() - dump radix tree 4037090df5aSMatthew Dillon */ 4047090df5aSMatthew Dillon void 4057090df5aSMatthew Dillon blist_print(blist_t bl) 4067090df5aSMatthew Dillon { 407bb4a27f9SMark Johnston printf("BLIST avail = %jd, cursor = %08jx {\n", 408bb4a27f9SMark Johnston (uintmax_t)bl->bl_avail, (uintmax_t)bl->bl_cursor); 409bb4a27f9SMark Johnston 410bb4a27f9SMark Johnston if (bl->bl_root->bm_bitmap != 0) 4112ac0c7c3SAlan Cox blst_radix_print(bl->bl_root, 0, bl->bl_radix, 4); 4127090df5aSMatthew Dillon printf("}\n"); 4137090df5aSMatthew Dillon } 4147090df5aSMatthew Dillon 4157090df5aSMatthew Dillon #endif 4167090df5aSMatthew Dillon 417d027ed2eSAlan Cox static const u_daddr_t fib[] = { 418d027ed2eSAlan Cox 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 419d027ed2eSAlan Cox 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 420d027ed2eSAlan Cox 514229, 832040, 1346269, 2178309, 3524578, 421d027ed2eSAlan Cox }; 422d027ed2eSAlan Cox 423d027ed2eSAlan Cox /* 424d027ed2eSAlan Cox * Use 'gap' to describe a maximal range of unallocated blocks/bits. 425d027ed2eSAlan Cox */ 426d027ed2eSAlan Cox struct gap_stats { 427d027ed2eSAlan Cox daddr_t start; /* current gap start, or SWAPBLK_NONE */ 428d027ed2eSAlan Cox daddr_t num; /* number of gaps observed */ 429d027ed2eSAlan Cox daddr_t max; /* largest gap size */ 430d027ed2eSAlan Cox daddr_t avg; /* average gap size */ 431d027ed2eSAlan Cox daddr_t err; /* sum - num * avg */ 432d027ed2eSAlan Cox daddr_t histo[nitems(fib)]; /* # gaps in each size range */ 433d027ed2eSAlan Cox int max_bucket; /* last histo elt with nonzero val */ 434d027ed2eSAlan Cox }; 435d027ed2eSAlan Cox 436d027ed2eSAlan Cox /* 437d027ed2eSAlan Cox * gap_stats_counting() - is the state 'counting 1 bits'? 438d027ed2eSAlan Cox * or 'skipping 0 bits'? 439d027ed2eSAlan Cox */ 440d027ed2eSAlan Cox static inline bool 441d027ed2eSAlan Cox gap_stats_counting(const struct gap_stats *stats) 442d027ed2eSAlan Cox { 443d027ed2eSAlan Cox 444d027ed2eSAlan Cox return (stats->start != SWAPBLK_NONE); 445d027ed2eSAlan Cox } 446d027ed2eSAlan Cox 447d027ed2eSAlan Cox /* 448d027ed2eSAlan Cox * init_gap_stats() - initialize stats on gap sizes 449d027ed2eSAlan Cox */ 450d027ed2eSAlan Cox static inline void 451d027ed2eSAlan Cox init_gap_stats(struct gap_stats *stats) 452d027ed2eSAlan Cox { 453d027ed2eSAlan Cox 454d027ed2eSAlan Cox bzero(stats, sizeof(*stats)); 455d027ed2eSAlan Cox stats->start = SWAPBLK_NONE; 456d027ed2eSAlan Cox } 457d027ed2eSAlan Cox 458d027ed2eSAlan Cox /* 459d027ed2eSAlan Cox * update_gap_stats() - update stats on gap sizes 460d027ed2eSAlan Cox */ 461d027ed2eSAlan Cox static void 462d027ed2eSAlan Cox update_gap_stats(struct gap_stats *stats, daddr_t posn) 463d027ed2eSAlan Cox { 464d027ed2eSAlan Cox daddr_t size; 465d027ed2eSAlan Cox int hi, lo, mid; 466d027ed2eSAlan Cox 467d027ed2eSAlan Cox if (!gap_stats_counting(stats)) { 468d027ed2eSAlan Cox stats->start = posn; 469d027ed2eSAlan Cox return; 470d027ed2eSAlan Cox } 471d027ed2eSAlan Cox size = posn - stats->start; 472d027ed2eSAlan Cox stats->start = SWAPBLK_NONE; 473d027ed2eSAlan Cox if (size > stats->max) 474d027ed2eSAlan Cox stats->max = size; 475d027ed2eSAlan Cox 476d027ed2eSAlan Cox /* 477d027ed2eSAlan Cox * Find the fibonacci range that contains size, 478d027ed2eSAlan Cox * expecting to find it in an early range. 479d027ed2eSAlan Cox */ 480d027ed2eSAlan Cox lo = 0; 481d027ed2eSAlan Cox hi = 1; 482d027ed2eSAlan Cox while (hi < nitems(fib) && fib[hi] <= size) { 483d027ed2eSAlan Cox lo = hi; 484d027ed2eSAlan Cox hi *= 2; 485d027ed2eSAlan Cox } 486d027ed2eSAlan Cox if (hi >= nitems(fib)) 487d027ed2eSAlan Cox hi = nitems(fib); 488d027ed2eSAlan Cox while (lo + 1 != hi) { 489d027ed2eSAlan Cox mid = (lo + hi) >> 1; 490d027ed2eSAlan Cox if (fib[mid] <= size) 491d027ed2eSAlan Cox lo = mid; 492d027ed2eSAlan Cox else 493d027ed2eSAlan Cox hi = mid; 494d027ed2eSAlan Cox } 495d027ed2eSAlan Cox stats->histo[lo]++; 496d027ed2eSAlan Cox if (lo > stats->max_bucket) 497d027ed2eSAlan Cox stats->max_bucket = lo; 498d027ed2eSAlan Cox stats->err += size - stats->avg; 499d027ed2eSAlan Cox stats->num++; 500d027ed2eSAlan Cox stats->avg += stats->err / stats->num; 501d027ed2eSAlan Cox stats->err %= stats->num; 502d027ed2eSAlan Cox } 503d027ed2eSAlan Cox 504d027ed2eSAlan Cox /* 505d027ed2eSAlan Cox * dump_gap_stats() - print stats on gap sizes 506d027ed2eSAlan Cox */ 507d027ed2eSAlan Cox static inline void 508d027ed2eSAlan Cox dump_gap_stats(const struct gap_stats *stats, struct sbuf *s) 509d027ed2eSAlan Cox { 510d027ed2eSAlan Cox int i; 511d027ed2eSAlan Cox 512d027ed2eSAlan Cox sbuf_printf(s, "number of maximal free ranges: %jd\n", 513d027ed2eSAlan Cox (intmax_t)stats->num); 514d027ed2eSAlan Cox sbuf_printf(s, "largest free range: %jd\n", (intmax_t)stats->max); 515d027ed2eSAlan Cox sbuf_printf(s, "average maximal free range size: %jd\n", 516d027ed2eSAlan Cox (intmax_t)stats->avg); 517d027ed2eSAlan Cox sbuf_printf(s, "number of maximal free ranges of different sizes:\n"); 518d027ed2eSAlan Cox sbuf_printf(s, " count | size range\n"); 519d027ed2eSAlan Cox sbuf_printf(s, " ----- | ----------\n"); 520d027ed2eSAlan Cox for (i = 0; i < stats->max_bucket; i++) { 521d027ed2eSAlan Cox if (stats->histo[i] != 0) { 522d027ed2eSAlan Cox sbuf_printf(s, "%20jd | ", 523d027ed2eSAlan Cox (intmax_t)stats->histo[i]); 524d027ed2eSAlan Cox if (fib[i] != fib[i + 1] - 1) 525d027ed2eSAlan Cox sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i], 526d027ed2eSAlan Cox (intmax_t)fib[i + 1] - 1); 527d027ed2eSAlan Cox else 528d027ed2eSAlan Cox sbuf_printf(s, "%jd\n", (intmax_t)fib[i]); 529d027ed2eSAlan Cox } 530d027ed2eSAlan Cox } 531d027ed2eSAlan Cox sbuf_printf(s, "%20jd | ", (intmax_t)stats->histo[i]); 532d027ed2eSAlan Cox if (stats->histo[i] > 1) 533d027ed2eSAlan Cox sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i], 534d027ed2eSAlan Cox (intmax_t)stats->max); 535d027ed2eSAlan Cox else 536d027ed2eSAlan Cox sbuf_printf(s, "%jd\n", (intmax_t)stats->max); 537d027ed2eSAlan Cox } 538d027ed2eSAlan Cox 539d027ed2eSAlan Cox /* 540d027ed2eSAlan Cox * blist_stats() - dump radix tree stats 541d027ed2eSAlan Cox */ 542d027ed2eSAlan Cox void 543d027ed2eSAlan Cox blist_stats(blist_t bl, struct sbuf *s) 544d027ed2eSAlan Cox { 545d027ed2eSAlan Cox struct gap_stats gstats; 546d027ed2eSAlan Cox struct gap_stats *stats = &gstats; 547d027ed2eSAlan Cox daddr_t i, nodes, radix; 54853519253SDoug Moore u_daddr_t diff, mask; 54953519253SDoug Moore int digit; 550d027ed2eSAlan Cox 551d027ed2eSAlan Cox init_gap_stats(stats); 552d027ed2eSAlan Cox nodes = 0; 553d027ed2eSAlan Cox i = bl->bl_radix; 554d027ed2eSAlan Cox while (i < bl->bl_radix + bl->bl_blocks) { 555d027ed2eSAlan Cox /* 556d027ed2eSAlan Cox * Find max size subtree starting at i. 557d027ed2eSAlan Cox */ 558d027ed2eSAlan Cox radix = BLIST_BMAP_RADIX; 559d027ed2eSAlan Cox while (((i / radix) & BLIST_META_MASK) == 0) 560d027ed2eSAlan Cox radix *= BLIST_META_RADIX; 561d027ed2eSAlan Cox 562d027ed2eSAlan Cox /* 563d027ed2eSAlan Cox * Check for skippable subtrees starting at i. 564d027ed2eSAlan Cox */ 565d027ed2eSAlan Cox while (radix > BLIST_BMAP_RADIX) { 566bb4a27f9SMark Johnston if (bl->bl_root[nodes].bm_bitmap == 0) { 567d027ed2eSAlan Cox if (gap_stats_counting(stats)) 568d027ed2eSAlan Cox update_gap_stats(stats, i); 569d027ed2eSAlan Cox break; 570d027ed2eSAlan Cox } 571d027ed2eSAlan Cox 572d027ed2eSAlan Cox /* 573d027ed2eSAlan Cox * Skip subtree root. 574d027ed2eSAlan Cox */ 575d027ed2eSAlan Cox nodes++; 576d027ed2eSAlan Cox radix /= BLIST_META_RADIX; 577d027ed2eSAlan Cox } 578d027ed2eSAlan Cox if (radix == BLIST_BMAP_RADIX) { 579d027ed2eSAlan Cox /* 580d027ed2eSAlan Cox * Scan leaf. 581d027ed2eSAlan Cox */ 582bb4a27f9SMark Johnston mask = bl->bl_root[nodes].bm_bitmap; 583d027ed2eSAlan Cox diff = mask ^ (mask << 1); 584d027ed2eSAlan Cox if (gap_stats_counting(stats)) 585d027ed2eSAlan Cox diff ^= 1; 586d027ed2eSAlan Cox while (diff != 0) { 58753519253SDoug Moore digit = bitpos(diff); 58853519253SDoug Moore update_gap_stats(stats, i + digit); 58953519253SDoug Moore diff ^= bitrange(digit, 1); 590d027ed2eSAlan Cox } 591d027ed2eSAlan Cox } 592d027ed2eSAlan Cox nodes += radix_to_skip(radix); 593d027ed2eSAlan Cox i += radix; 594d027ed2eSAlan Cox } 595d027ed2eSAlan Cox update_gap_stats(stats, i); 596d027ed2eSAlan Cox dump_gap_stats(stats, s); 597d027ed2eSAlan Cox } 598d027ed2eSAlan Cox 5997090df5aSMatthew Dillon /************************************************************************ 6007090df5aSMatthew Dillon * ALLOCATION SUPPORT FUNCTIONS * 6017090df5aSMatthew Dillon ************************************************************************ 6027090df5aSMatthew Dillon * 6037090df5aSMatthew Dillon * These support functions do all the actual work. They may seem 6047090df5aSMatthew Dillon * rather longish, but that's because I've commented them up. The 6057090df5aSMatthew Dillon * actual code is straight forward. 6067090df5aSMatthew Dillon * 6077090df5aSMatthew Dillon */ 6087090df5aSMatthew Dillon 6097090df5aSMatthew Dillon /* 61031c82722SDoug Moore * BLST_NEXT_LEAF_ALLOC() - allocate the blocks starting with the next leaf. 611bb4a27f9SMark Johnston * 61231c82722SDoug Moore * 'scan' is a leaf node, and its first block is at address 'start'. The 61331c82722SDoug Moore * next leaf node could be adjacent, or several nodes away if the least 61431c82722SDoug Moore * common ancestor of 'scan' and its neighbor is several levels up. Use 61531c82722SDoug Moore * addresses to determine how many meta-nodes lie between the leaves. If 61631c82722SDoug Moore * sequence of leaves starting with the next one has enough initial bits 61731c82722SDoug Moore * set, clear them and clear the bits in the meta nodes on the path up to 61831c82722SDoug Moore * the least common ancestor to mark any subtrees made completely empty. 619bb4a27f9SMark Johnston */ 620bb4a27f9SMark Johnston static int 62131c82722SDoug Moore blst_next_leaf_alloc(blmeta_t *scan, daddr_t start, int count, int maxcount) 622bb4a27f9SMark Johnston { 623bb4a27f9SMark Johnston u_daddr_t radix; 62431c82722SDoug Moore daddr_t blk; 62587ae0686SDoug Moore int avail, digit; 626bb4a27f9SMark Johnston 62731c82722SDoug Moore start += BLIST_BMAP_RADIX; 62831c82722SDoug Moore for (blk = start; blk - start < maxcount; blk += BLIST_BMAP_RADIX) { 62931c82722SDoug Moore /* Skip meta-nodes, as long as they promise more free blocks. */ 630bb4a27f9SMark Johnston radix = BLIST_BMAP_RADIX; 63131c82722SDoug Moore while (((++scan)->bm_bitmap & 1) == 1 && 63231c82722SDoug Moore ((blk / radix) & BLIST_META_MASK) == 0) 633bb4a27f9SMark Johnston radix *= BLIST_META_RADIX; 63431c82722SDoug Moore if (~scan->bm_bitmap != 0) { 63531c82722SDoug Moore /* 63631c82722SDoug Moore * Either there is no next leaf with any free blocks, 63731c82722SDoug Moore * or we've reached the next leaf and found that some 63831c82722SDoug Moore * of its blocks are not free. In the first case, 63931c82722SDoug Moore * bitpos() returns zero here. 64031c82722SDoug Moore */ 64131c82722SDoug Moore avail = blk - start + bitpos(~scan->bm_bitmap); 6423f3f7c05SDoug Moore if (avail < count || avail == 0) { 643bb4a27f9SMark Johnston /* 64431c82722SDoug Moore * There isn't a next leaf with enough free 6453f3f7c05SDoug Moore * blocks at its beginning to bother 6463f3f7c05SDoug Moore * allocating. 647bb4a27f9SMark Johnston */ 64831c82722SDoug Moore return (avail); 649bb4a27f9SMark Johnston } 65031c82722SDoug Moore maxcount = imin(avail, maxcount); 6513f3f7c05SDoug Moore if (maxcount % BLIST_BMAP_RADIX == 0) { 6523f3f7c05SDoug Moore /* 6533f3f7c05SDoug Moore * There was no next leaf. Back scan up to 6543f3f7c05SDoug Moore * last leaf. 6553f3f7c05SDoug Moore */ 6563f3f7c05SDoug Moore --scan; 6573f3f7c05SDoug Moore while (radix != BLIST_BMAP_RADIX) { 6583f3f7c05SDoug Moore radix /= BLIST_META_RADIX; 6593f3f7c05SDoug Moore --scan; 6603f3f7c05SDoug Moore } 6613f3f7c05SDoug Moore blk -= BLIST_BMAP_RADIX; 6623f3f7c05SDoug Moore } 66331c82722SDoug Moore } 66431c82722SDoug Moore } 665bb4a27f9SMark Johnston 666bb4a27f9SMark Johnston /* 66731c82722SDoug Moore * 'scan' is the last leaf that provides blocks. Clear from 1 to 66831c82722SDoug Moore * BLIST_BMAP_RADIX bits to represent the allocation of those last 66931c82722SDoug Moore * blocks. 670bb4a27f9SMark Johnston */ 67131c82722SDoug Moore if (maxcount % BLIST_BMAP_RADIX != 0) 67231c82722SDoug Moore scan->bm_bitmap &= ~bitrange(0, maxcount % BLIST_BMAP_RADIX); 67331c82722SDoug Moore else 67431c82722SDoug Moore scan->bm_bitmap = 0; 67531c82722SDoug Moore 67631c82722SDoug Moore for (;;) { 67731c82722SDoug Moore /* Back up over meta-nodes, clearing bits if necessary. */ 67831c82722SDoug Moore blk -= BLIST_BMAP_RADIX; 67931c82722SDoug Moore radix = BLIST_BMAP_RADIX; 68031c82722SDoug Moore while ((digit = ((blk / radix) & BLIST_META_MASK)) == 0) { 68131c82722SDoug Moore if ((scan--)->bm_bitmap == 0) 68231c82722SDoug Moore scan->bm_bitmap ^= 1; 68331c82722SDoug Moore radix *= BLIST_META_RADIX; 68431c82722SDoug Moore } 68531c82722SDoug Moore if ((scan--)->bm_bitmap == 0) 686d1c34a6bSDoug Moore scan[-digit * radix_to_skip(radix)].bm_bitmap ^= 687d1c34a6bSDoug Moore (u_daddr_t)1 << digit; 68831c82722SDoug Moore 68931c82722SDoug Moore if (blk == start) 690d1c34a6bSDoug Moore break; 69131c82722SDoug Moore /* Clear all the bits of this leaf. */ 69231c82722SDoug Moore scan->bm_bitmap = 0; 693bb4a27f9SMark Johnston } 69431c82722SDoug Moore return (maxcount); 695bb4a27f9SMark Johnston } 696bb4a27f9SMark Johnston 697bb4a27f9SMark Johnston /* 698bb4a27f9SMark Johnston * BLST_LEAF_ALLOC() - allocate at a leaf in the radix tree (a bitmap). 6997090df5aSMatthew Dillon * 7002905d1ceSAlan Cox * This function is the core of the allocator. Its execution time is 7012905d1ceSAlan Cox * proportional to log(count), plus height of the tree if the allocation 7022905d1ceSAlan Cox * crosses a leaf boundary. 7037090df5aSMatthew Dillon */ 7047090df5aSMatthew Dillon static daddr_t 70587ae0686SDoug Moore blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int *count, int maxcount) 70654541421SAlan Cox { 707*9f70442aSDoug Moore u_daddr_t mask; 708*9f70442aSDoug Moore int bighint, count1, hi, lo, num_shifts; 7097090df5aSMatthew Dillon 71087ae0686SDoug Moore count1 = *count - 1; 71154541421SAlan Cox num_shifts = fls(count1); 712*9f70442aSDoug Moore mask = ~scan->bm_bitmap; 713*9f70442aSDoug Moore while ((mask & (mask + 1)) != 0 && num_shifts > 0) { 71454541421SAlan Cox /* 715*9f70442aSDoug Moore * If bit i is 0 in mask, then bits in [i, i + (count1 >> 716*9f70442aSDoug Moore * num_shifts)] are 1 in scan->bm_bitmap. Reduce num_shifts to 717*9f70442aSDoug Moore * 0, while preserving this invariant. The updates to mask 718*9f70442aSDoug Moore * leave fewer bits 0, but each bit that remains 0 represents a 719*9f70442aSDoug Moore * longer string of consecutive 1-bits in scan->bm_bitmap. If 720*9f70442aSDoug Moore * more updates to mask cannot set more bits, because mask is 721*9f70442aSDoug Moore * partitioned with all 1 bits following all 0 bits, the loop 722*9f70442aSDoug Moore * terminates immediately. 72354541421SAlan Cox */ 72454541421SAlan Cox num_shifts--; 725*9f70442aSDoug Moore mask |= mask >> ((count1 >> num_shifts) + 1) / 2; 72654541421SAlan Cox } 727*9f70442aSDoug Moore bighint = count1 >> num_shifts; 728*9f70442aSDoug Moore if (~mask == 0) { 72954541421SAlan Cox /* 730*9f70442aSDoug Moore * Update bighint. There is no allocation bigger than 731*9f70442aSDoug Moore * count1 >> num_shifts starting in this leaf. 73254541421SAlan Cox */ 733*9f70442aSDoug Moore scan->bm_bighint = bighint; 7347090df5aSMatthew Dillon return (SWAPBLK_NONE); 7357090df5aSMatthew Dillon } 73654541421SAlan Cox 737ec371b57SAlan Cox /* Discard any candidates that appear before blk. */ 7382905d1ceSAlan Cox if ((blk & BLIST_BMAP_MASK) != 0) { 739*9f70442aSDoug Moore if ((~mask & bitrange(0, blk & BLIST_BMAP_MASK)) != 0) { 740*9f70442aSDoug Moore /* Grow bighint in case all discarded bits are set. */ 741*9f70442aSDoug Moore bighint += blk & BLIST_BMAP_MASK; 742*9f70442aSDoug Moore mask |= bitrange(0, blk & BLIST_BMAP_MASK); 743*9f70442aSDoug Moore if (~mask == 0) { 744*9f70442aSDoug Moore scan->bm_bighint = bighint; 74554541421SAlan Cox return (SWAPBLK_NONE); 7462905d1ceSAlan Cox } 747*9f70442aSDoug Moore } 748*9f70442aSDoug Moore blk -= blk & BLIST_BMAP_MASK; 7492905d1ceSAlan Cox } 7502905d1ceSAlan Cox 7512905d1ceSAlan Cox /* 75254541421SAlan Cox * The least significant set bit in mask marks the start of the first 75387ae0686SDoug Moore * available range of sufficient size. Find its position. 7547090df5aSMatthew Dillon */ 755*9f70442aSDoug Moore lo = bitpos(~mask); 7567090df5aSMatthew Dillon 75754541421SAlan Cox /* 75887ae0686SDoug Moore * Find how much space is available starting at that position. 75954541421SAlan Cox */ 760*9f70442aSDoug Moore if ((mask & (mask + 1)) != 0) { 76187ae0686SDoug Moore /* Count the 1 bits starting at position lo. */ 762*9f70442aSDoug Moore hi = bitpos(mask & (mask + 1)) + count1; 76387ae0686SDoug Moore if (maxcount < hi - lo) 76487ae0686SDoug Moore hi = lo + maxcount; 76587ae0686SDoug Moore *count = hi - lo; 766*9f70442aSDoug Moore mask = ~bitrange(lo, *count); 76787ae0686SDoug Moore } else if (maxcount <= BLIST_BMAP_RADIX - lo) { 76887ae0686SDoug Moore /* All the blocks we can use are available here. */ 76987ae0686SDoug Moore hi = lo + maxcount; 77087ae0686SDoug Moore *count = maxcount; 771*9f70442aSDoug Moore mask = ~bitrange(lo, *count); 772*9f70442aSDoug Moore if (hi == BLIST_BMAP_RADIX) 773*9f70442aSDoug Moore scan->bm_bighint = bighint; 77487ae0686SDoug Moore } else { 77587ae0686SDoug Moore /* Check next leaf for some of the blocks we want or need. */ 77687ae0686SDoug Moore count1 = *count - (BLIST_BMAP_RADIX - lo); 77787ae0686SDoug Moore maxcount -= BLIST_BMAP_RADIX - lo; 77887ae0686SDoug Moore hi = blst_next_leaf_alloc(scan, blk, count1, maxcount); 77987ae0686SDoug Moore if (hi < count1) 780ec371b57SAlan Cox /* 78187ae0686SDoug Moore * The next leaf cannot supply enough blocks to reach 78287ae0686SDoug Moore * the minimum required allocation. The hint cannot be 78387ae0686SDoug Moore * updated, because the same allocation request could 78487ae0686SDoug Moore * be satisfied later, by this leaf, if the state of 78587ae0686SDoug Moore * the next leaf changes, and without any changes to 78687ae0686SDoug Moore * this leaf. 787ec371b57SAlan Cox */ 788ec371b57SAlan Cox return (SWAPBLK_NONE); 78987ae0686SDoug Moore *count = BLIST_BMAP_RADIX - lo + hi; 790*9f70442aSDoug Moore scan->bm_bighint = bighint; 791ec371b57SAlan Cox } 792ec371b57SAlan Cox 793ec371b57SAlan Cox /* Clear the allocated bits from this leaf. */ 794*9f70442aSDoug Moore scan->bm_bitmap &= mask; 7952905d1ceSAlan Cox return (blk + lo); 7967090df5aSMatthew Dillon } 7977090df5aSMatthew Dillon 7987090df5aSMatthew Dillon /* 7997090df5aSMatthew Dillon * blist_meta_alloc() - allocate at a meta in the radix tree. 8007090df5aSMatthew Dillon * 8017090df5aSMatthew Dillon * Attempt to allocate at a meta node. If we can't, we update 8027090df5aSMatthew Dillon * bighint and return a failure. Updating bighint optimize future 8037090df5aSMatthew Dillon * calls that hit this node. We have to check for our collapse cases 8047090df5aSMatthew Dillon * and we have a few optimizations strewn in as well. 8057090df5aSMatthew Dillon */ 8067090df5aSMatthew Dillon static daddr_t 80787ae0686SDoug Moore blst_meta_alloc(blmeta_t *scan, daddr_t cursor, int *count, 80887ae0686SDoug Moore int maxcount, u_daddr_t radix) 809d4e3484bSAlan Cox { 810bb4a27f9SMark Johnston daddr_t blk, i, r, skip; 81153519253SDoug Moore u_daddr_t mask; 812d4e3484bSAlan Cox bool scan_from_start; 813bb4a27f9SMark Johnston int digit; 8147090df5aSMatthew Dillon 815a396c83aSAlan Cox if (radix == BLIST_BMAP_RADIX) 81687ae0686SDoug Moore return (blst_leaf_alloc(scan, cursor, count, maxcount)); 817ec371b57SAlan Cox blk = cursor & -radix; 818bb4a27f9SMark Johnston scan_from_start = (cursor == blk); 819bb4a27f9SMark Johnston radix /= BLIST_META_RADIX; 8202ac0c7c3SAlan Cox skip = radix_to_skip(radix); 821bb4a27f9SMark Johnston mask = scan->bm_bitmap; 822bb4a27f9SMark Johnston 823bb4a27f9SMark Johnston /* Discard any candidates that appear before cursor. */ 824bb4a27f9SMark Johnston digit = (cursor / radix) & BLIST_META_MASK; 825bb4a27f9SMark Johnston mask &= (u_daddr_t)-1 << digit; 826ee73fef9SAlan Cox if (mask == 0) 827ee73fef9SAlan Cox return (SWAPBLK_NONE); 8287090df5aSMatthew Dillon 8294be4fd5dSAlan Cox /* 830bb4a27f9SMark Johnston * If the first try is for a block that includes the cursor, pre-undo 831bb4a27f9SMark Johnston * the digit * radix offset in the first call; otherwise, ignore the 832bb4a27f9SMark Johnston * cursor entirely. 8334be4fd5dSAlan Cox */ 834bb4a27f9SMark Johnston if (((mask >> digit) & 1) == 1) 835bb4a27f9SMark Johnston cursor -= digit * radix; 836d4e3484bSAlan Cox else 837bb4a27f9SMark Johnston cursor = blk; 8387090df5aSMatthew Dillon 8394be4fd5dSAlan Cox /* 840bb4a27f9SMark Johnston * Examine the nonempty subtree associated with each bit set in mask. 8414be4fd5dSAlan Cox */ 842bb4a27f9SMark Johnston do { 84353519253SDoug Moore digit = bitpos(mask); 844bb4a27f9SMark Johnston i = 1 + digit * skip; 84587ae0686SDoug Moore if (*count <= scan[i].bm_bighint) { 8467090df5aSMatthew Dillon /* 847ec371b57SAlan Cox * The allocation might fit beginning in the i'th subtree. 8487090df5aSMatthew Dillon */ 849bb4a27f9SMark Johnston r = blst_meta_alloc(&scan[i], cursor + digit * radix, 85087ae0686SDoug Moore count, maxcount, radix); 8517090df5aSMatthew Dillon if (r != SWAPBLK_NONE) { 852bb4a27f9SMark Johnston if (scan[i].bm_bitmap == 0) 85353519253SDoug Moore scan->bm_bitmap ^= bitrange(digit, 1); 8547090df5aSMatthew Dillon return (r); 8557090df5aSMatthew Dillon } 8567090df5aSMatthew Dillon } 857bb4a27f9SMark Johnston cursor = blk; 85853519253SDoug Moore } while ((mask ^= bitrange(digit, 1)) != 0); 8597090df5aSMatthew Dillon 8607090df5aSMatthew Dillon /* 861bb4a27f9SMark Johnston * We couldn't allocate count in this subtree. If the whole tree was 862bb4a27f9SMark Johnston * scanned, and the last tree node is allocated, update bighint. 8637090df5aSMatthew Dillon */ 864bb4a27f9SMark Johnston if (scan_from_start && !(digit == BLIST_META_RADIX - 1 && 865bb4a27f9SMark Johnston scan[i].bm_bighint == BLIST_MAX_ALLOC)) 86687ae0686SDoug Moore scan->bm_bighint = *count - 1; 867d4e3484bSAlan Cox 8687090df5aSMatthew Dillon return (SWAPBLK_NONE); 8697090df5aSMatthew Dillon } 8707090df5aSMatthew Dillon 8717090df5aSMatthew Dillon /* 8727090df5aSMatthew Dillon * BLST_LEAF_FREE() - free allocated block from leaf bitmap 8737090df5aSMatthew Dillon * 8747090df5aSMatthew Dillon */ 8757090df5aSMatthew Dillon static void 876b411efa4SAlan Cox blst_leaf_free(blmeta_t *scan, daddr_t blk, int count) 877b411efa4SAlan Cox { 878ec371b57SAlan Cox u_daddr_t mask; 879ec371b57SAlan Cox 8807090df5aSMatthew Dillon /* 8817090df5aSMatthew Dillon * free some data in this bitmap 882ec371b57SAlan Cox * mask=0000111111111110000 8837090df5aSMatthew Dillon * \_________/\__/ 884ec371b57SAlan Cox * count n 8857090df5aSMatthew Dillon */ 886bb4a27f9SMark Johnston mask = bitrange(blk & BLIST_BMAP_MASK, count); 887b1f59c92SDoug Moore KASSERT((scan->bm_bitmap & mask) == 0, 888b1f59c92SDoug Moore ("freeing free block: %jx, size %d, mask %jx", 889b1f59c92SDoug Moore (uintmax_t)blk, count, (uintmax_t)scan->bm_bitmap & mask)); 890bb4a27f9SMark Johnston scan->bm_bitmap |= mask; 8917090df5aSMatthew Dillon } 8927090df5aSMatthew Dillon 8937090df5aSMatthew Dillon /* 8947090df5aSMatthew Dillon * BLST_META_FREE() - free allocated blocks from radix tree meta info 8957090df5aSMatthew Dillon * 8967090df5aSMatthew Dillon * This support routine frees a range of blocks from the bitmap. 8977090df5aSMatthew Dillon * The range must be entirely enclosed by this radix node. If a 8987090df5aSMatthew Dillon * meta node, we break the range down recursively to free blocks 8997090df5aSMatthew Dillon * in subnodes (which means that this code can free an arbitrary 9007090df5aSMatthew Dillon * range whereas the allocation code cannot allocate an arbitrary 9017090df5aSMatthew Dillon * range). 9027090df5aSMatthew Dillon */ 9037090df5aSMatthew Dillon static void 904bee93d3cSAlan Cox blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, u_daddr_t radix) 905d3783724SAlan Cox { 906bb4a27f9SMark Johnston daddr_t blk, endBlk, i, skip; 907bb4a27f9SMark Johnston int digit, endDigit; 9087090df5aSMatthew Dillon 909bb4a27f9SMark Johnston /* 910bb4a27f9SMark Johnston * We could probably do a better job here. We are required to make 911bb4a27f9SMark Johnston * bighint at least as large as the biggest allocable block of data. 912bb4a27f9SMark Johnston * If we just shoehorn it, a little extra overhead will be incurred 913bb4a27f9SMark Johnston * on the next allocation (but only that one typically). 914bb4a27f9SMark Johnston */ 915bb4a27f9SMark Johnston scan->bm_bighint = BLIST_MAX_ALLOC; 916bb4a27f9SMark Johnston 917a396c83aSAlan Cox if (radix == BLIST_BMAP_RADIX) 918a396c83aSAlan Cox return (blst_leaf_free(scan, freeBlk, count)); 9197090df5aSMatthew Dillon 920bb4a27f9SMark Johnston endBlk = ummin(freeBlk + count, (freeBlk + radix) & -radix); 92157e6d29bSMatthew Dillon radix /= BLIST_META_RADIX; 922bb4a27f9SMark Johnston skip = radix_to_skip(radix); 923bb4a27f9SMark Johnston blk = freeBlk & -radix; 924bb4a27f9SMark Johnston digit = (blk / radix) & BLIST_META_MASK; 925bb4a27f9SMark Johnston endDigit = 1 + (((endBlk - 1) / radix) & BLIST_META_MASK); 926bb4a27f9SMark Johnston scan->bm_bitmap |= bitrange(digit, endDigit - digit); 927bb4a27f9SMark Johnston for (i = 1 + digit * skip; blk < endBlk; i += skip) { 9287090df5aSMatthew Dillon blk += radix; 929bb4a27f9SMark Johnston count = ummin(blk, endBlk) - freeBlk; 930bb4a27f9SMark Johnston blst_meta_free(&scan[i], freeBlk, count, radix); 931bb4a27f9SMark Johnston freeBlk = blk; 9327090df5aSMatthew Dillon } 9337090df5aSMatthew Dillon } 9347090df5aSMatthew Dillon 9357090df5aSMatthew Dillon /* 936bb4a27f9SMark Johnston * BLST_COPY() - copy one radix tree to another 9377090df5aSMatthew Dillon * 9387090df5aSMatthew Dillon * Locates free space in the source tree and frees it in the destination 9397090df5aSMatthew Dillon * tree. The space may not already be free in the destination. 9407090df5aSMatthew Dillon */ 941b411efa4SAlan Cox static void 9422ac0c7c3SAlan Cox blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, blist_t dest, 9432ac0c7c3SAlan Cox daddr_t count) 944b411efa4SAlan Cox { 945bb4a27f9SMark Johnston daddr_t endBlk, i, skip; 9467090df5aSMatthew Dillon 9477090df5aSMatthew Dillon /* 9487090df5aSMatthew Dillon * Leaf node 9497090df5aSMatthew Dillon */ 9507090df5aSMatthew Dillon 9517090df5aSMatthew Dillon if (radix == BLIST_BMAP_RADIX) { 952bb4a27f9SMark Johnston u_daddr_t v = scan->bm_bitmap; 9537090df5aSMatthew Dillon 9547090df5aSMatthew Dillon if (v == (u_daddr_t)-1) { 9557090df5aSMatthew Dillon blist_free(dest, blk, count); 9567090df5aSMatthew Dillon } else if (v != 0) { 9577090df5aSMatthew Dillon int i; 9587090df5aSMatthew Dillon 959bb4a27f9SMark Johnston for (i = 0; i < count; ++i) { 960064650c1SAlan Cox if (v & ((u_daddr_t)1 << i)) 9617090df5aSMatthew Dillon blist_free(dest, blk + i, 1); 9627090df5aSMatthew Dillon } 9637090df5aSMatthew Dillon } 9647090df5aSMatthew Dillon return; 9657090df5aSMatthew Dillon } 9667090df5aSMatthew Dillon 9677090df5aSMatthew Dillon /* 9687090df5aSMatthew Dillon * Meta node 9697090df5aSMatthew Dillon */ 9707090df5aSMatthew Dillon 971bb4a27f9SMark Johnston if (scan->bm_bitmap == 0) { 9727090df5aSMatthew Dillon /* 9737090df5aSMatthew Dillon * Source all allocated, leave dest allocated 9747090df5aSMatthew Dillon */ 9757090df5aSMatthew Dillon return; 9767090df5aSMatthew Dillon } 9777090df5aSMatthew Dillon 978bb4a27f9SMark Johnston endBlk = blk + count; 9792ac0c7c3SAlan Cox radix /= BLIST_META_RADIX; 980bb4a27f9SMark Johnston skip = radix_to_skip(radix); 981bb4a27f9SMark Johnston for (i = 1; blk < endBlk; i += skip) { 9827090df5aSMatthew Dillon blk += radix; 983bb4a27f9SMark Johnston count = radix; 984bb4a27f9SMark Johnston if (blk >= endBlk) 985bb4a27f9SMark Johnston count -= blk - endBlk; 986bb4a27f9SMark Johnston blst_copy(&scan[i], blk - radix, radix, dest, count); 9877090df5aSMatthew Dillon } 9887090df5aSMatthew Dillon } 9897090df5aSMatthew Dillon 9907090df5aSMatthew Dillon /* 99192da00bbSMatthew Dillon * BLST_LEAF_FILL() - allocate specific blocks in leaf bitmap 99292da00bbSMatthew Dillon * 99392da00bbSMatthew Dillon * This routine allocates all blocks in the specified range 99492da00bbSMatthew Dillon * regardless of any existing allocations in that range. Returns 99592da00bbSMatthew Dillon * the number of blocks allocated by the call. 99692da00bbSMatthew Dillon */ 997a7249a6cSAlan Cox static daddr_t 99892da00bbSMatthew Dillon blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count) 99992da00bbSMatthew Dillon { 1000a7249a6cSAlan Cox daddr_t nblks; 10014be4fd5dSAlan Cox u_daddr_t mask; 100292da00bbSMatthew Dillon 1003bb4a27f9SMark Johnston mask = bitrange(blk & BLIST_BMAP_MASK, count); 100492da00bbSMatthew Dillon 10054be4fd5dSAlan Cox /* Count the number of blocks that we are allocating. */ 1006bb4a27f9SMark Johnston nblks = bitcount64(scan->bm_bitmap & mask); 100792da00bbSMatthew Dillon 1008bb4a27f9SMark Johnston scan->bm_bitmap &= ~mask; 10094be4fd5dSAlan Cox return (nblks); 101092da00bbSMatthew Dillon } 101192da00bbSMatthew Dillon 101292da00bbSMatthew Dillon /* 101392da00bbSMatthew Dillon * BLIST_META_FILL() - allocate specific blocks at a meta node 101492da00bbSMatthew Dillon * 101592da00bbSMatthew Dillon * This routine allocates the specified range of blocks, 101692da00bbSMatthew Dillon * regardless of any existing allocations in the range. The 101792da00bbSMatthew Dillon * range must be within the extent of this node. Returns the 101892da00bbSMatthew Dillon * number of blocks allocated by the call. 101992da00bbSMatthew Dillon */ 1020a7249a6cSAlan Cox static daddr_t 1021bee93d3cSAlan Cox blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, u_daddr_t radix) 1022d3783724SAlan Cox { 1023bb4a27f9SMark Johnston daddr_t blk, endBlk, i, nblks, skip; 1024bb4a27f9SMark Johnston int digit; 102592da00bbSMatthew Dillon 1026a396c83aSAlan Cox if (radix == BLIST_BMAP_RADIX) 1027a396c83aSAlan Cox return (blst_leaf_fill(scan, allocBlk, count)); 1028bb4a27f9SMark Johnston 1029bb4a27f9SMark Johnston endBlk = ummin(allocBlk + count, (allocBlk + radix) & -radix); 1030bb4a27f9SMark Johnston radix /= BLIST_META_RADIX; 10312ac0c7c3SAlan Cox skip = radix_to_skip(radix); 1032bee93d3cSAlan Cox blk = allocBlk & -radix; 1033d3783724SAlan Cox nblks = 0; 1034bb4a27f9SMark Johnston while (blk < endBlk) { 1035bb4a27f9SMark Johnston digit = (blk / radix) & BLIST_META_MASK; 1036bb4a27f9SMark Johnston i = 1 + digit * skip; 103792da00bbSMatthew Dillon blk += radix; 1038bb4a27f9SMark Johnston count = ummin(blk, endBlk) - allocBlk; 1039bb4a27f9SMark Johnston nblks += blst_meta_fill(&scan[i], allocBlk, count, radix); 1040bb4a27f9SMark Johnston if (scan[i].bm_bitmap == 0) 1041bb4a27f9SMark Johnston scan->bm_bitmap &= ~((u_daddr_t)1 << digit); 1042bb4a27f9SMark Johnston allocBlk = blk; 104392da00bbSMatthew Dillon } 1044a396c83aSAlan Cox return (nblks); 104592da00bbSMatthew Dillon } 104692da00bbSMatthew Dillon 10477090df5aSMatthew Dillon #ifdef BLIST_DEBUG 10487090df5aSMatthew Dillon 10497090df5aSMatthew Dillon static void 10502ac0c7c3SAlan Cox blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab) 10517090df5aSMatthew Dillon { 1052bb4a27f9SMark Johnston daddr_t skip; 105353519253SDoug Moore u_daddr_t mask; 1054bb4a27f9SMark Johnston int digit; 10557090df5aSMatthew Dillon 10567090df5aSMatthew Dillon if (radix == BLIST_BMAP_RADIX) { 10577090df5aSMatthew Dillon printf( 1058bb4a27f9SMark Johnston "%*.*s(%08llx,%lld): bitmap %0*llx big=%lld\n", 10597090df5aSMatthew Dillon tab, tab, "", 106092da00bbSMatthew Dillon (long long)blk, (long long)radix, 1061bb4a27f9SMark Johnston 1 + (BLIST_BMAP_RADIX - 1) / 4, 1062bb4a27f9SMark Johnston (long long)scan->bm_bitmap, 106392da00bbSMatthew Dillon (long long)scan->bm_bighint 10647090df5aSMatthew Dillon ); 10657090df5aSMatthew Dillon return; 10667090df5aSMatthew Dillon } 10677090df5aSMatthew Dillon 10687090df5aSMatthew Dillon printf( 1069bb4a27f9SMark Johnston "%*.*s(%08llx): subtree (%lld/%lld) bitmap %0*llx big=%lld {\n", 10707090df5aSMatthew Dillon tab, tab, "", 107192da00bbSMatthew Dillon (long long)blk, (long long)radix, 107292da00bbSMatthew Dillon (long long)radix, 1073bb4a27f9SMark Johnston 1 + (BLIST_META_RADIX - 1) / 4, 1074bb4a27f9SMark Johnston (long long)scan->bm_bitmap, 107592da00bbSMatthew Dillon (long long)scan->bm_bighint 10767090df5aSMatthew Dillon ); 10777090df5aSMatthew Dillon 10782ac0c7c3SAlan Cox radix /= BLIST_META_RADIX; 1079bb4a27f9SMark Johnston skip = radix_to_skip(radix); 10807090df5aSMatthew Dillon tab += 4; 10817090df5aSMatthew Dillon 1082bb4a27f9SMark Johnston mask = scan->bm_bitmap; 1083bb4a27f9SMark Johnston /* Examine the nonempty subtree associated with each bit set in mask */ 1084bb4a27f9SMark Johnston do { 108553519253SDoug Moore digit = bitpos(mask); 1086bb4a27f9SMark Johnston blst_radix_print(&scan[1 + digit * skip], blk + digit * radix, 1087bb4a27f9SMark Johnston radix, tab); 108853519253SDoug Moore } while ((mask ^= bitrange(digit, 1)) != 0); 10897090df5aSMatthew Dillon tab -= 4; 10907090df5aSMatthew Dillon 10917090df5aSMatthew Dillon printf( 10927090df5aSMatthew Dillon "%*.*s}\n", 10937090df5aSMatthew Dillon tab, tab, "" 10947090df5aSMatthew Dillon ); 10957090df5aSMatthew Dillon } 10967090df5aSMatthew Dillon 10977090df5aSMatthew Dillon #endif 10987090df5aSMatthew Dillon 10997090df5aSMatthew Dillon #ifdef BLIST_DEBUG 11007090df5aSMatthew Dillon 11017090df5aSMatthew Dillon int 11027090df5aSMatthew Dillon main(int ac, char **av) 11037090df5aSMatthew Dillon { 1104bb4a27f9SMark Johnston int size = BLIST_META_RADIX * BLIST_BMAP_RADIX; 11057090df5aSMatthew Dillon int i; 11067090df5aSMatthew Dillon blist_t bl; 1107d027ed2eSAlan Cox struct sbuf *s; 11087090df5aSMatthew Dillon 11097090df5aSMatthew Dillon for (i = 1; i < ac; ++i) { 11107090df5aSMatthew Dillon const char *ptr = av[i]; 11117090df5aSMatthew Dillon if (*ptr != '-') { 11127090df5aSMatthew Dillon size = strtol(ptr, NULL, 0); 11137090df5aSMatthew Dillon continue; 11147090df5aSMatthew Dillon } 11157090df5aSMatthew Dillon ptr += 2; 11167090df5aSMatthew Dillon fprintf(stderr, "Bad option: %s\n", ptr - 2); 11177090df5aSMatthew Dillon exit(1); 11187090df5aSMatthew Dillon } 1119c8c7ad92SKip Macy bl = blist_create(size, M_WAITOK); 11207090df5aSMatthew Dillon blist_free(bl, 0, size); 11217090df5aSMatthew Dillon 11227090df5aSMatthew Dillon for (;;) { 11237090df5aSMatthew Dillon char buf[1024]; 1124d90bf7d8SAlan Cox long long da = 0; 112587ae0686SDoug Moore int count = 0, maxcount = 0; 11267090df5aSMatthew Dillon 11274be4fd5dSAlan Cox printf("%lld/%lld/%lld> ", (long long)blist_avail(bl), 112892da00bbSMatthew Dillon (long long)size, (long long)bl->bl_radix); 11297090df5aSMatthew Dillon fflush(stdout); 11307090df5aSMatthew Dillon if (fgets(buf, sizeof(buf), stdin) == NULL) 11317090df5aSMatthew Dillon break; 11327090df5aSMatthew Dillon switch(buf[0]) { 11337090df5aSMatthew Dillon case 'r': 113487ae0686SDoug Moore if (sscanf(buf + 1, "%d", &count) == 1) { 1135d90bf7d8SAlan Cox blist_resize(&bl, count, 1, M_WAITOK); 11367090df5aSMatthew Dillon } else { 11377090df5aSMatthew Dillon printf("?\n"); 11387090df5aSMatthew Dillon } 11397090df5aSMatthew Dillon case 'p': 11407090df5aSMatthew Dillon blist_print(bl); 11417090df5aSMatthew Dillon break; 1142d027ed2eSAlan Cox case 's': 1143d027ed2eSAlan Cox s = sbuf_new_auto(); 1144d027ed2eSAlan Cox blist_stats(bl, s); 1145d027ed2eSAlan Cox sbuf_finish(s); 1146d027ed2eSAlan Cox printf("%s", sbuf_data(s)); 1147d027ed2eSAlan Cox sbuf_delete(s); 1148d027ed2eSAlan Cox break; 11497090df5aSMatthew Dillon case 'a': 115087ae0686SDoug Moore if (sscanf(buf + 1, "%d%d", &count, &maxcount) == 2) { 115187ae0686SDoug Moore daddr_t blk = blist_alloc(bl, &count, maxcount); 115287ae0686SDoug Moore printf(" R=%08llx, c=%08d\n", 115387ae0686SDoug Moore (long long)blk, count); 11547090df5aSMatthew Dillon } else { 11557090df5aSMatthew Dillon printf("?\n"); 11567090df5aSMatthew Dillon } 11577090df5aSMatthew Dillon break; 11587090df5aSMatthew Dillon case 'f': 115987ae0686SDoug Moore if (sscanf(buf + 1, "%llx %d", &da, &count) == 2) { 11607090df5aSMatthew Dillon blist_free(bl, da, count); 11617090df5aSMatthew Dillon } else { 11627090df5aSMatthew Dillon printf("?\n"); 11637090df5aSMatthew Dillon } 11647090df5aSMatthew Dillon break; 116592da00bbSMatthew Dillon case 'l': 116687ae0686SDoug Moore if (sscanf(buf + 1, "%llx %d", &da, &count) == 2) { 1167a7249a6cSAlan Cox printf(" n=%jd\n", 1168a7249a6cSAlan Cox (intmax_t)blist_fill(bl, da, count)); 116992da00bbSMatthew Dillon } else { 117092da00bbSMatthew Dillon printf("?\n"); 117192da00bbSMatthew Dillon } 117292da00bbSMatthew Dillon break; 11737090df5aSMatthew Dillon case '?': 11747090df5aSMatthew Dillon case 'h': 11757090df5aSMatthew Dillon puts( 11767090df5aSMatthew Dillon "p -print\n" 1177d027ed2eSAlan Cox "s -stats\n" 117887ae0686SDoug Moore "a %d %d -allocate\n" 11797090df5aSMatthew Dillon "f %x %d -free\n" 118092da00bbSMatthew Dillon "l %x %d -fill\n" 11817090df5aSMatthew Dillon "r %d -resize\n" 1182d4808c44SDoug Moore "h/? -help\n" 1183d4808c44SDoug Moore "q -quit" 11847090df5aSMatthew Dillon ); 11857090df5aSMatthew Dillon break; 1186d4808c44SDoug Moore case 'q': 1187d4808c44SDoug Moore break; 11887090df5aSMatthew Dillon default: 11897090df5aSMatthew Dillon printf("?\n"); 11907090df5aSMatthew Dillon break; 11917090df5aSMatthew Dillon } 1192d4808c44SDoug Moore if (buf[0] == 'q') 1193d4808c44SDoug Moore break; 11947090df5aSMatthew Dillon } 11957090df5aSMatthew Dillon return (0); 11967090df5aSMatthew Dillon } 11977090df5aSMatthew Dillon 11987090df5aSMatthew Dillon #endif 1199