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