17090df5aSMatthew Dillon 27090df5aSMatthew Dillon /* 37090df5aSMatthew Dillon * BLIST.C - Bitmap allocator/deallocator, using a radix tree with hinting 47090df5aSMatthew Dillon * 57090df5aSMatthew Dillon * (c)Copyright 1998, Matthew Dillon. Terms for use and redistribution 67090df5aSMatthew Dillon * are covered by the BSD Copyright as found in /usr/src/COPYRIGHT. 77090df5aSMatthew Dillon * 87090df5aSMatthew Dillon * This module implements a general bitmap allocator/deallocator. The 97090df5aSMatthew Dillon * allocator eats around 2 bits per 'block'. The module does not 107090df5aSMatthew Dillon * try to interpret the meaning of a 'block' other then to return 117090df5aSMatthew Dillon * SWAPBLK_NONE on an allocation failure. 127090df5aSMatthew Dillon * 137090df5aSMatthew Dillon * A radix tree is used to maintain the bitmap. Two radix constants are 147090df5aSMatthew Dillon * involved: One for the bitmaps contained in the leaf nodes (typically 157090df5aSMatthew Dillon * 32), and one for the meta nodes (typically 16). Both meta and leaf 167090df5aSMatthew Dillon * nodes have a hint field. This field gives us a hint as to the largest 177090df5aSMatthew Dillon * free contiguous range of blocks under the node. It may contain a 187090df5aSMatthew Dillon * value that is too high, but will never contain a value that is too 197090df5aSMatthew Dillon * low. When the radix tree is searched, allocation failures in subtrees 207090df5aSMatthew Dillon * update the hint. 217090df5aSMatthew Dillon * 227090df5aSMatthew Dillon * The radix tree also implements two collapsed states for meta nodes: 237090df5aSMatthew Dillon * the ALL-ALLOCATED state and the ALL-FREE state. If a meta node is 247090df5aSMatthew Dillon * in either of these two states, all information contained underneath 257090df5aSMatthew Dillon * the node is considered stale. These states are used to optimize 267090df5aSMatthew Dillon * allocation and freeing operations. 277090df5aSMatthew Dillon * 287090df5aSMatthew Dillon * The hinting greatly increases code efficiency for allocations while 297090df5aSMatthew Dillon * the general radix structure optimizes both allocations and frees. The 307090df5aSMatthew Dillon * radix tree should be able to operate well no matter how much 317090df5aSMatthew Dillon * fragmentation there is and no matter how large a bitmap is used. 327090df5aSMatthew Dillon * 337090df5aSMatthew Dillon * Unlike the rlist code, the blist code wires all necessary memory at 347090df5aSMatthew Dillon * creation time. Neither allocations nor frees require interaction with 357090df5aSMatthew Dillon * the memory subsystem. In contrast, the rlist code may allocate memory 367090df5aSMatthew Dillon * on an rlist_free() call. The non-blocking features of the blist code 377090df5aSMatthew Dillon * are used to great advantage in the swap code (vm/nswap_pager.c). The 387090df5aSMatthew Dillon * rlist code uses a little less overall memory then the blist code (but 397090df5aSMatthew Dillon * due to swap interleaving not all that much less), but the blist code 407090df5aSMatthew Dillon * scales much, much better. 417090df5aSMatthew Dillon * 427090df5aSMatthew Dillon * LAYOUT: The radix tree is layed out recursively using a 437090df5aSMatthew Dillon * linear array. Each meta node is immediately followed (layed out 447090df5aSMatthew Dillon * sequentially in memory) by BLIST_META_RADIX lower level nodes. This 457090df5aSMatthew Dillon * is a recursive structure but one that can be easily scanned through 467090df5aSMatthew Dillon * a very simple 'skip' calculation. In order to support large radixes, 477090df5aSMatthew Dillon * portions of the tree may reside outside our memory allocation. We 487090df5aSMatthew Dillon * handle this with an early-termination optimization (when bighint is 497090df5aSMatthew Dillon * set to -1) on the scan. The memory allocation is only large enough 507090df5aSMatthew Dillon * to cover the number of blocks requested at creation time even if it 517090df5aSMatthew Dillon * must be encompassed in larger root-node radix. 527090df5aSMatthew Dillon * 537090df5aSMatthew Dillon * NOTE: the allocator cannot currently allocate more then 547090df5aSMatthew Dillon * BLIST_BMAP_RADIX blocks per call. It will panic with 'allocation too 557090df5aSMatthew Dillon * large' if you try. This is an area that could use improvement. The 567090df5aSMatthew Dillon * radix is large enough that this restriction does not effect the swap 577090df5aSMatthew Dillon * system, though. Currently only the allocation code is effected by 587090df5aSMatthew Dillon * this algorithmic unfeature. The freeing code can handle arbitrary 597090df5aSMatthew Dillon * ranges. 607090df5aSMatthew Dillon * 617090df5aSMatthew Dillon * This code can be compiled stand-alone for debugging. 620625ba2fSGary Palmer * 63c3aac50fSPeter Wemm * $FreeBSD$ 647090df5aSMatthew Dillon */ 657090df5aSMatthew Dillon 66c4473420SPeter Wemm #ifdef _KERNEL 677090df5aSMatthew Dillon 687090df5aSMatthew Dillon #include <sys/param.h> 697090df5aSMatthew Dillon #include <sys/systm.h> 707090df5aSMatthew Dillon #include <sys/lock.h> 717090df5aSMatthew Dillon #include <sys/kernel.h> 727090df5aSMatthew Dillon #include <sys/blist.h> 737090df5aSMatthew Dillon #include <sys/malloc.h> 740cddd8f0SMatthew Dillon #include <sys/proc.h> 7523955314SAlfred Perlstein #include <sys/mutex.h> 767090df5aSMatthew Dillon #include <vm/vm.h> 777090df5aSMatthew Dillon #include <vm/vm_object.h> 787090df5aSMatthew Dillon #include <vm/vm_kern.h> 797090df5aSMatthew Dillon #include <vm/vm_extern.h> 807090df5aSMatthew Dillon #include <vm/vm_page.h> 817090df5aSMatthew Dillon 827090df5aSMatthew Dillon #else 837090df5aSMatthew Dillon 847090df5aSMatthew Dillon #ifndef BLIST_NO_DEBUG 857090df5aSMatthew Dillon #define BLIST_DEBUG 867090df5aSMatthew Dillon #endif 877090df5aSMatthew Dillon 887090df5aSMatthew Dillon #define SWAPBLK_NONE ((daddr_t)-1) 897090df5aSMatthew Dillon 907090df5aSMatthew Dillon #include <sys/types.h> 917090df5aSMatthew Dillon #include <stdio.h> 927090df5aSMatthew Dillon #include <string.h> 937090df5aSMatthew Dillon #include <stdlib.h> 947090df5aSMatthew Dillon #include <stdarg.h> 957090df5aSMatthew Dillon 967090df5aSMatthew Dillon #define malloc(a,b,c) malloc(a) 977090df5aSMatthew Dillon #define free(a,b) free(a) 987090df5aSMatthew Dillon 997090df5aSMatthew Dillon typedef unsigned int u_daddr_t; 1007090df5aSMatthew Dillon 1017090df5aSMatthew Dillon #include <sys/blist.h> 1027090df5aSMatthew Dillon 1037090df5aSMatthew Dillon void panic(const char *ctl, ...); 1047090df5aSMatthew Dillon 1057090df5aSMatthew Dillon #endif 1067090df5aSMatthew Dillon 1077090df5aSMatthew Dillon /* 1087090df5aSMatthew Dillon * static support functions 1097090df5aSMatthew Dillon */ 1107090df5aSMatthew Dillon 1117090df5aSMatthew Dillon static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count); 1127090df5aSMatthew Dillon static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t blk, 1137090df5aSMatthew Dillon daddr_t count, daddr_t radix, int skip); 1147090df5aSMatthew Dillon static void blst_leaf_free(blmeta_t *scan, daddr_t relblk, int count); 1157090df5aSMatthew Dillon static void blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, 1167090df5aSMatthew Dillon daddr_t radix, int skip, daddr_t blk); 1177090df5aSMatthew Dillon static void blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, 1187090df5aSMatthew Dillon daddr_t skip, blist_t dest, daddr_t count); 1197090df5aSMatthew Dillon static daddr_t blst_radix_init(blmeta_t *scan, daddr_t radix, 1207090df5aSMatthew Dillon int skip, daddr_t count); 121c4473420SPeter Wemm #ifndef _KERNEL 1227090df5aSMatthew Dillon static void blst_radix_print(blmeta_t *scan, daddr_t blk, 1237090df5aSMatthew Dillon daddr_t radix, int skip, int tab); 1247090df5aSMatthew Dillon #endif 1257090df5aSMatthew Dillon 126c4473420SPeter Wemm #ifdef _KERNEL 1277090df5aSMatthew Dillon static MALLOC_DEFINE(M_SWAP, "SWAP", "Swap space"); 1287090df5aSMatthew Dillon #endif 1297090df5aSMatthew Dillon 1307090df5aSMatthew Dillon /* 1317090df5aSMatthew Dillon * blist_create() - create a blist capable of handling up to the specified 1327090df5aSMatthew Dillon * number of blocks 1337090df5aSMatthew Dillon * 1347090df5aSMatthew Dillon * blocks must be greater then 0 1357090df5aSMatthew Dillon * 1367090df5aSMatthew Dillon * The smallest blist consists of a single leaf node capable of 1377090df5aSMatthew Dillon * managing BLIST_BMAP_RADIX blocks. 1387090df5aSMatthew Dillon */ 1397090df5aSMatthew Dillon 1407090df5aSMatthew Dillon blist_t 1417090df5aSMatthew Dillon blist_create(daddr_t blocks) 1427090df5aSMatthew Dillon { 1437090df5aSMatthew Dillon blist_t bl; 1447090df5aSMatthew Dillon int radix; 1457090df5aSMatthew Dillon int skip = 0; 1467090df5aSMatthew Dillon 1477090df5aSMatthew Dillon /* 1487090df5aSMatthew Dillon * Calculate radix and skip field used for scanning. 1497090df5aSMatthew Dillon */ 1507090df5aSMatthew Dillon radix = BLIST_BMAP_RADIX; 1517090df5aSMatthew Dillon 1527090df5aSMatthew Dillon while (radix < blocks) { 1537090df5aSMatthew Dillon radix <<= BLIST_META_RADIX_SHIFT; 1547090df5aSMatthew Dillon skip = (skip + 1) << BLIST_META_RADIX_SHIFT; 1557090df5aSMatthew Dillon } 1567090df5aSMatthew Dillon 1577cc0979fSDavid Malone bl = malloc(sizeof(struct blist), M_SWAP, M_WAITOK | M_ZERO); 1587090df5aSMatthew Dillon 1597090df5aSMatthew Dillon bl->bl_blocks = blocks; 1607090df5aSMatthew Dillon bl->bl_radix = radix; 1617090df5aSMatthew Dillon bl->bl_skip = skip; 1627090df5aSMatthew Dillon bl->bl_rootblks = 1 + 1637090df5aSMatthew Dillon blst_radix_init(NULL, bl->bl_radix, bl->bl_skip, blocks); 1647090df5aSMatthew Dillon bl->bl_root = malloc(sizeof(blmeta_t) * bl->bl_rootblks, M_SWAP, M_WAITOK); 1657090df5aSMatthew Dillon 1667090df5aSMatthew Dillon #if defined(BLIST_DEBUG) 1677090df5aSMatthew Dillon printf( 1687090df5aSMatthew Dillon "BLIST representing %d blocks (%d MB of swap)" 1697090df5aSMatthew Dillon ", requiring %dK of ram\n", 1707090df5aSMatthew Dillon bl->bl_blocks, 1717090df5aSMatthew Dillon bl->bl_blocks * 4 / 1024, 1727090df5aSMatthew Dillon (bl->bl_rootblks * sizeof(blmeta_t) + 1023) / 1024 1737090df5aSMatthew Dillon ); 1747090df5aSMatthew Dillon printf("BLIST raw radix tree contains %d records\n", bl->bl_rootblks); 1757090df5aSMatthew Dillon #endif 1767090df5aSMatthew Dillon blst_radix_init(bl->bl_root, bl->bl_radix, bl->bl_skip, blocks); 1777090df5aSMatthew Dillon 1787090df5aSMatthew Dillon return(bl); 1797090df5aSMatthew Dillon } 1807090df5aSMatthew Dillon 1817090df5aSMatthew Dillon void 1827090df5aSMatthew Dillon blist_destroy(blist_t bl) 1837090df5aSMatthew Dillon { 1847090df5aSMatthew Dillon free(bl->bl_root, M_SWAP); 1857090df5aSMatthew Dillon free(bl, M_SWAP); 1867090df5aSMatthew Dillon } 1877090df5aSMatthew Dillon 1887090df5aSMatthew Dillon /* 1897090df5aSMatthew Dillon * blist_alloc() - reserve space in the block bitmap. Return the base 1907090df5aSMatthew Dillon * of a contiguous region or SWAPBLK_NONE if space could 1917090df5aSMatthew Dillon * not be allocated. 1927090df5aSMatthew Dillon */ 1937090df5aSMatthew Dillon 1947090df5aSMatthew Dillon daddr_t 1957090df5aSMatthew Dillon blist_alloc(blist_t bl, daddr_t count) 1967090df5aSMatthew Dillon { 1977090df5aSMatthew Dillon daddr_t blk = SWAPBLK_NONE; 1987090df5aSMatthew Dillon 1997090df5aSMatthew Dillon if (bl) { 2007090df5aSMatthew Dillon if (bl->bl_radix == BLIST_BMAP_RADIX) 2017090df5aSMatthew Dillon blk = blst_leaf_alloc(bl->bl_root, 0, count); 2027090df5aSMatthew Dillon else 2037090df5aSMatthew Dillon blk = blst_meta_alloc(bl->bl_root, 0, count, bl->bl_radix, bl->bl_skip); 2047090df5aSMatthew Dillon if (blk != SWAPBLK_NONE) 2057090df5aSMatthew Dillon bl->bl_free -= count; 2067090df5aSMatthew Dillon } 2077090df5aSMatthew Dillon return(blk); 2087090df5aSMatthew Dillon } 2097090df5aSMatthew Dillon 2107090df5aSMatthew Dillon /* 2117090df5aSMatthew Dillon * blist_free() - free up space in the block bitmap. Return the base 2127090df5aSMatthew Dillon * of a contiguous region. Panic if an inconsistancy is 2137090df5aSMatthew Dillon * found. 2147090df5aSMatthew Dillon */ 2157090df5aSMatthew Dillon 2167090df5aSMatthew Dillon void 2177090df5aSMatthew Dillon blist_free(blist_t bl, daddr_t blkno, daddr_t count) 2187090df5aSMatthew Dillon { 2197090df5aSMatthew Dillon if (bl) { 2207090df5aSMatthew Dillon if (bl->bl_radix == BLIST_BMAP_RADIX) 2217090df5aSMatthew Dillon blst_leaf_free(bl->bl_root, blkno, count); 2227090df5aSMatthew Dillon else 2237090df5aSMatthew Dillon blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix, bl->bl_skip, 0); 2247090df5aSMatthew Dillon bl->bl_free += count; 2257090df5aSMatthew Dillon } 2267090df5aSMatthew Dillon } 2277090df5aSMatthew Dillon 2287090df5aSMatthew Dillon /* 2297090df5aSMatthew Dillon * blist_resize() - resize an existing radix tree to handle the 2307090df5aSMatthew Dillon * specified number of blocks. This will reallocate 2317090df5aSMatthew Dillon * the tree and transfer the previous bitmap to the new 2327090df5aSMatthew Dillon * one. When extending the tree you can specify whether 2337090df5aSMatthew Dillon * the new blocks are to left allocated or freed. 2347090df5aSMatthew Dillon */ 2357090df5aSMatthew Dillon 2367090df5aSMatthew Dillon void 2377090df5aSMatthew Dillon blist_resize(blist_t *pbl, daddr_t count, int freenew) 2387090df5aSMatthew Dillon { 2397090df5aSMatthew Dillon blist_t newbl = blist_create(count); 2407090df5aSMatthew Dillon blist_t save = *pbl; 2417090df5aSMatthew Dillon 2427090df5aSMatthew Dillon *pbl = newbl; 2437090df5aSMatthew Dillon if (count > save->bl_blocks) 2447090df5aSMatthew Dillon count = save->bl_blocks; 2457090df5aSMatthew Dillon blst_copy(save->bl_root, 0, save->bl_radix, save->bl_skip, newbl, count); 2467090df5aSMatthew Dillon 2477090df5aSMatthew Dillon /* 2487090df5aSMatthew Dillon * If resizing upwards, should we free the new space or not? 2497090df5aSMatthew Dillon */ 2507090df5aSMatthew Dillon if (freenew && count < newbl->bl_blocks) { 2517090df5aSMatthew Dillon blist_free(newbl, count, newbl->bl_blocks - count); 2527090df5aSMatthew Dillon } 2537090df5aSMatthew Dillon blist_destroy(save); 2547090df5aSMatthew Dillon } 2557090df5aSMatthew Dillon 2567090df5aSMatthew Dillon #ifdef BLIST_DEBUG 2577090df5aSMatthew Dillon 2587090df5aSMatthew Dillon /* 2597090df5aSMatthew Dillon * blist_print() - dump radix tree 2607090df5aSMatthew Dillon */ 2617090df5aSMatthew Dillon 2627090df5aSMatthew Dillon void 2637090df5aSMatthew Dillon blist_print(blist_t bl) 2647090df5aSMatthew Dillon { 2657090df5aSMatthew Dillon printf("BLIST {\n"); 2667090df5aSMatthew Dillon blst_radix_print(bl->bl_root, 0, bl->bl_radix, bl->bl_skip, 4); 2677090df5aSMatthew Dillon printf("}\n"); 2687090df5aSMatthew Dillon } 2697090df5aSMatthew Dillon 2707090df5aSMatthew Dillon #endif 2717090df5aSMatthew Dillon 2727090df5aSMatthew Dillon /************************************************************************ 2737090df5aSMatthew Dillon * ALLOCATION SUPPORT FUNCTIONS * 2747090df5aSMatthew Dillon ************************************************************************ 2757090df5aSMatthew Dillon * 2767090df5aSMatthew Dillon * These support functions do all the actual work. They may seem 2777090df5aSMatthew Dillon * rather longish, but that's because I've commented them up. The 2787090df5aSMatthew Dillon * actual code is straight forward. 2797090df5aSMatthew Dillon * 2807090df5aSMatthew Dillon */ 2817090df5aSMatthew Dillon 2827090df5aSMatthew Dillon /* 2837090df5aSMatthew Dillon * blist_leaf_alloc() - allocate at a leaf in the radix tree (a bitmap). 2847090df5aSMatthew Dillon * 2857090df5aSMatthew Dillon * This is the core of the allocator and is optimized for the 1 block 2867090df5aSMatthew Dillon * and the BLIST_BMAP_RADIX block allocation cases. Other cases are 2877090df5aSMatthew Dillon * somewhat slower. The 1 block allocation case is log2 and extremely 2887090df5aSMatthew Dillon * quick. 2897090df5aSMatthew Dillon */ 2907090df5aSMatthew Dillon 2917090df5aSMatthew Dillon static daddr_t 2927090df5aSMatthew Dillon blst_leaf_alloc( 2937090df5aSMatthew Dillon blmeta_t *scan, 2947090df5aSMatthew Dillon daddr_t blk, 2957090df5aSMatthew Dillon int count 2967090df5aSMatthew Dillon ) { 2977090df5aSMatthew Dillon u_daddr_t orig = scan->u.bmu_bitmap; 2987090df5aSMatthew Dillon 2997090df5aSMatthew Dillon if (orig == 0) { 3007090df5aSMatthew Dillon /* 3017090df5aSMatthew Dillon * Optimize bitmap all-allocated case. Also, count = 1 3027090df5aSMatthew Dillon * case assumes at least 1 bit is free in the bitmap, so 3037090df5aSMatthew Dillon * we have to take care of this case here. 3047090df5aSMatthew Dillon */ 3057090df5aSMatthew Dillon scan->bm_bighint = 0; 3067090df5aSMatthew Dillon return(SWAPBLK_NONE); 3077090df5aSMatthew Dillon } 3087090df5aSMatthew Dillon if (count == 1) { 3097090df5aSMatthew Dillon /* 3107090df5aSMatthew Dillon * Optimized code to allocate one bit out of the bitmap 3117090df5aSMatthew Dillon */ 3127090df5aSMatthew Dillon u_daddr_t mask; 3137090df5aSMatthew Dillon int j = BLIST_BMAP_RADIX/2; 3147090df5aSMatthew Dillon int r = 0; 3157090df5aSMatthew Dillon 3167090df5aSMatthew Dillon mask = (u_daddr_t)-1 >> (BLIST_BMAP_RADIX/2); 3177090df5aSMatthew Dillon 3187090df5aSMatthew Dillon while (j) { 3197090df5aSMatthew Dillon if ((orig & mask) == 0) { 3207090df5aSMatthew Dillon r += j; 3217090df5aSMatthew Dillon orig >>= j; 3227090df5aSMatthew Dillon } 3237090df5aSMatthew Dillon j >>= 1; 3247090df5aSMatthew Dillon mask >>= j; 3257090df5aSMatthew Dillon } 3267090df5aSMatthew Dillon scan->u.bmu_bitmap &= ~(1 << r); 3277090df5aSMatthew Dillon return(blk + r); 3287090df5aSMatthew Dillon } 3297090df5aSMatthew Dillon if (count <= BLIST_BMAP_RADIX) { 3307090df5aSMatthew Dillon /* 3317090df5aSMatthew Dillon * non-optimized code to allocate N bits out of the bitmap. 3327090df5aSMatthew Dillon * The more bits, the faster the code runs. It will run 3337090df5aSMatthew Dillon * the slowest allocating 2 bits, but since there aren't any 3347090df5aSMatthew Dillon * memory ops in the core loop (or shouldn't be, anyway), 3357090df5aSMatthew Dillon * you probably won't notice the difference. 3367090df5aSMatthew Dillon */ 3377090df5aSMatthew Dillon int j; 3387090df5aSMatthew Dillon int n = BLIST_BMAP_RADIX - count; 3397090df5aSMatthew Dillon u_daddr_t mask; 3407090df5aSMatthew Dillon 3417090df5aSMatthew Dillon mask = (u_daddr_t)-1 >> n; 3427090df5aSMatthew Dillon 3437090df5aSMatthew Dillon for (j = 0; j <= n; ++j) { 3447090df5aSMatthew Dillon if ((orig & mask) == mask) { 3457090df5aSMatthew Dillon scan->u.bmu_bitmap &= ~mask; 3467090df5aSMatthew Dillon return(blk + j); 3477090df5aSMatthew Dillon } 3487090df5aSMatthew Dillon mask = (mask << 1); 3497090df5aSMatthew Dillon } 3507090df5aSMatthew Dillon } 3517090df5aSMatthew Dillon /* 3527090df5aSMatthew Dillon * We couldn't allocate count in this subtree, update bighint. 3537090df5aSMatthew Dillon */ 3547090df5aSMatthew Dillon scan->bm_bighint = count - 1; 3557090df5aSMatthew Dillon return(SWAPBLK_NONE); 3567090df5aSMatthew Dillon } 3577090df5aSMatthew Dillon 3587090df5aSMatthew Dillon /* 3597090df5aSMatthew Dillon * blist_meta_alloc() - allocate at a meta in the radix tree. 3607090df5aSMatthew Dillon * 3617090df5aSMatthew Dillon * Attempt to allocate at a meta node. If we can't, we update 3627090df5aSMatthew Dillon * bighint and return a failure. Updating bighint optimize future 3637090df5aSMatthew Dillon * calls that hit this node. We have to check for our collapse cases 3647090df5aSMatthew Dillon * and we have a few optimizations strewn in as well. 3657090df5aSMatthew Dillon */ 3667090df5aSMatthew Dillon 3677090df5aSMatthew Dillon static daddr_t 3687090df5aSMatthew Dillon blst_meta_alloc( 3697090df5aSMatthew Dillon blmeta_t *scan, 3707090df5aSMatthew Dillon daddr_t blk, 3717090df5aSMatthew Dillon daddr_t count, 3727090df5aSMatthew Dillon daddr_t radix, 3737090df5aSMatthew Dillon int skip 3747090df5aSMatthew Dillon ) { 3757090df5aSMatthew Dillon int i; 3767090df5aSMatthew Dillon int next_skip = (skip >> BLIST_META_RADIX_SHIFT); 3777090df5aSMatthew Dillon 3787090df5aSMatthew Dillon if (scan->u.bmu_avail == 0) { 3797090df5aSMatthew Dillon /* 3807090df5aSMatthew Dillon * ALL-ALLOCATED special case 3817090df5aSMatthew Dillon */ 3827090df5aSMatthew Dillon scan->bm_bighint = count; 3837090df5aSMatthew Dillon return(SWAPBLK_NONE); 3847090df5aSMatthew Dillon } 3857090df5aSMatthew Dillon 3867090df5aSMatthew Dillon if (scan->u.bmu_avail == radix) { 3877090df5aSMatthew Dillon radix >>= BLIST_META_RADIX_SHIFT; 3887090df5aSMatthew Dillon 3897090df5aSMatthew Dillon /* 3907090df5aSMatthew Dillon * ALL-FREE special case, initialize uninitialize 3917090df5aSMatthew Dillon * sublevel. 3927090df5aSMatthew Dillon */ 3937090df5aSMatthew Dillon for (i = 1; i <= skip; i += next_skip) { 3947090df5aSMatthew Dillon if (scan[i].bm_bighint == (daddr_t)-1) 3957090df5aSMatthew Dillon break; 3967090df5aSMatthew Dillon if (next_skip == 1) { 3977090df5aSMatthew Dillon scan[i].u.bmu_bitmap = (u_daddr_t)-1; 3987090df5aSMatthew Dillon scan[i].bm_bighint = BLIST_BMAP_RADIX; 3997090df5aSMatthew Dillon } else { 4007090df5aSMatthew Dillon scan[i].bm_bighint = radix; 4017090df5aSMatthew Dillon scan[i].u.bmu_avail = radix; 4027090df5aSMatthew Dillon } 4037090df5aSMatthew Dillon } 4047090df5aSMatthew Dillon } else { 4057090df5aSMatthew Dillon radix >>= BLIST_META_RADIX_SHIFT; 4067090df5aSMatthew Dillon } 4077090df5aSMatthew Dillon 4087090df5aSMatthew Dillon for (i = 1; i <= skip; i += next_skip) { 4097090df5aSMatthew Dillon if (count <= scan[i].bm_bighint) { 4107090df5aSMatthew Dillon /* 4117090df5aSMatthew Dillon * count fits in object 4127090df5aSMatthew Dillon */ 4137090df5aSMatthew Dillon daddr_t r; 4147090df5aSMatthew Dillon if (next_skip == 1) { 4157090df5aSMatthew Dillon r = blst_leaf_alloc(&scan[i], blk, count); 4167090df5aSMatthew Dillon } else { 4177090df5aSMatthew Dillon r = blst_meta_alloc(&scan[i], blk, count, radix, next_skip - 1); 4187090df5aSMatthew Dillon } 4197090df5aSMatthew Dillon if (r != SWAPBLK_NONE) { 4207090df5aSMatthew Dillon scan->u.bmu_avail -= count; 4217090df5aSMatthew Dillon if (scan->bm_bighint > scan->u.bmu_avail) 4227090df5aSMatthew Dillon scan->bm_bighint = scan->u.bmu_avail; 4237090df5aSMatthew Dillon return(r); 4247090df5aSMatthew Dillon } 4257090df5aSMatthew Dillon } else if (scan[i].bm_bighint == (daddr_t)-1) { 4267090df5aSMatthew Dillon /* 4277090df5aSMatthew Dillon * Terminator 4287090df5aSMatthew Dillon */ 4297090df5aSMatthew Dillon break; 4307090df5aSMatthew Dillon } else if (count > radix) { 4317090df5aSMatthew Dillon /* 4327090df5aSMatthew Dillon * count does not fit in object even if it were 4337090df5aSMatthew Dillon * complete free. 4347090df5aSMatthew Dillon */ 4357090df5aSMatthew Dillon panic("blist_meta_alloc: allocation too large"); 4367090df5aSMatthew Dillon } 4377090df5aSMatthew Dillon blk += radix; 4387090df5aSMatthew Dillon } 4397090df5aSMatthew Dillon 4407090df5aSMatthew Dillon /* 4417090df5aSMatthew Dillon * We couldn't allocate count in this subtree, update bighint. 4427090df5aSMatthew Dillon */ 4437090df5aSMatthew Dillon if (scan->bm_bighint >= count) 4447090df5aSMatthew Dillon scan->bm_bighint = count - 1; 4457090df5aSMatthew Dillon return(SWAPBLK_NONE); 4467090df5aSMatthew Dillon } 4477090df5aSMatthew Dillon 4487090df5aSMatthew Dillon /* 4497090df5aSMatthew Dillon * BLST_LEAF_FREE() - free allocated block from leaf bitmap 4507090df5aSMatthew Dillon * 4517090df5aSMatthew Dillon */ 4527090df5aSMatthew Dillon 4537090df5aSMatthew Dillon static void 4547090df5aSMatthew Dillon blst_leaf_free( 4557090df5aSMatthew Dillon blmeta_t *scan, 4567090df5aSMatthew Dillon daddr_t blk, 4577090df5aSMatthew Dillon int count 4587090df5aSMatthew Dillon ) { 4597090df5aSMatthew Dillon /* 4607090df5aSMatthew Dillon * free some data in this bitmap 4617090df5aSMatthew Dillon * 4627090df5aSMatthew Dillon * e.g. 4637090df5aSMatthew Dillon * 0000111111111110000 4647090df5aSMatthew Dillon * \_________/\__/ 4657090df5aSMatthew Dillon * v n 4667090df5aSMatthew Dillon */ 4677090df5aSMatthew Dillon int n = blk & (BLIST_BMAP_RADIX - 1); 4687090df5aSMatthew Dillon u_daddr_t mask; 4697090df5aSMatthew Dillon 4707090df5aSMatthew Dillon mask = ((u_daddr_t)-1 << n) & 4717090df5aSMatthew Dillon ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - count - n)); 4727090df5aSMatthew Dillon 4737090df5aSMatthew Dillon if (scan->u.bmu_bitmap & mask) 4747090df5aSMatthew Dillon panic("blst_radix_free: freeing free block"); 4757090df5aSMatthew Dillon scan->u.bmu_bitmap |= mask; 4767090df5aSMatthew Dillon 4777090df5aSMatthew Dillon /* 4787090df5aSMatthew Dillon * We could probably do a better job here. We are required to make 4797090df5aSMatthew Dillon * bighint at least as large as the biggest contiguous block of 4807090df5aSMatthew Dillon * data. If we just shoehorn it, a little extra overhead will 4817090df5aSMatthew Dillon * be incured on the next allocation (but only that one typically). 4827090df5aSMatthew Dillon */ 4837090df5aSMatthew Dillon scan->bm_bighint = BLIST_BMAP_RADIX; 4847090df5aSMatthew Dillon } 4857090df5aSMatthew Dillon 4867090df5aSMatthew Dillon /* 4877090df5aSMatthew Dillon * BLST_META_FREE() - free allocated blocks from radix tree meta info 4887090df5aSMatthew Dillon * 4897090df5aSMatthew Dillon * This support routine frees a range of blocks from the bitmap. 4907090df5aSMatthew Dillon * The range must be entirely enclosed by this radix node. If a 4917090df5aSMatthew Dillon * meta node, we break the range down recursively to free blocks 4927090df5aSMatthew Dillon * in subnodes (which means that this code can free an arbitrary 4937090df5aSMatthew Dillon * range whereas the allocation code cannot allocate an arbitrary 4947090df5aSMatthew Dillon * range). 4957090df5aSMatthew Dillon */ 4967090df5aSMatthew Dillon 4977090df5aSMatthew Dillon static void 4987090df5aSMatthew Dillon blst_meta_free( 4997090df5aSMatthew Dillon blmeta_t *scan, 5007090df5aSMatthew Dillon daddr_t freeBlk, 5017090df5aSMatthew Dillon daddr_t count, 5027090df5aSMatthew Dillon daddr_t radix, 5037090df5aSMatthew Dillon int skip, 5047090df5aSMatthew Dillon daddr_t blk 5057090df5aSMatthew Dillon ) { 5067090df5aSMatthew Dillon int i; 5077090df5aSMatthew Dillon int next_skip = (skip >> BLIST_META_RADIX_SHIFT); 5087090df5aSMatthew Dillon 5097090df5aSMatthew Dillon #if 0 5107090df5aSMatthew Dillon printf("FREE (%x,%d) FROM (%x,%d)\n", 5117090df5aSMatthew Dillon freeBlk, count, 5127090df5aSMatthew Dillon blk, radix 5137090df5aSMatthew Dillon ); 5147090df5aSMatthew Dillon #endif 5157090df5aSMatthew Dillon 5167090df5aSMatthew Dillon if (scan->u.bmu_avail == 0) { 5177090df5aSMatthew Dillon /* 5187090df5aSMatthew Dillon * ALL-ALLOCATED special case, with possible 5197090df5aSMatthew Dillon * shortcut to ALL-FREE special case. 5207090df5aSMatthew Dillon */ 5217090df5aSMatthew Dillon scan->u.bmu_avail = count; 5227090df5aSMatthew Dillon scan->bm_bighint = count; 5237090df5aSMatthew Dillon 5247090df5aSMatthew Dillon if (count != radix) { 5257090df5aSMatthew Dillon for (i = 1; i <= skip; i += next_skip) { 5267090df5aSMatthew Dillon if (scan[i].bm_bighint == (daddr_t)-1) 5277090df5aSMatthew Dillon break; 5287090df5aSMatthew Dillon scan[i].bm_bighint = 0; 5297090df5aSMatthew Dillon if (next_skip == 1) { 5307090df5aSMatthew Dillon scan[i].u.bmu_bitmap = 0; 5317090df5aSMatthew Dillon } else { 5327090df5aSMatthew Dillon scan[i].u.bmu_avail = 0; 5337090df5aSMatthew Dillon } 5347090df5aSMatthew Dillon } 5357090df5aSMatthew Dillon /* fall through */ 5367090df5aSMatthew Dillon } 5377090df5aSMatthew Dillon } else { 5387090df5aSMatthew Dillon scan->u.bmu_avail += count; 5397090df5aSMatthew Dillon /* scan->bm_bighint = radix; */ 5407090df5aSMatthew Dillon } 5417090df5aSMatthew Dillon 5427090df5aSMatthew Dillon /* 5437090df5aSMatthew Dillon * ALL-FREE special case. 5447090df5aSMatthew Dillon */ 5457090df5aSMatthew Dillon 5467090df5aSMatthew Dillon if (scan->u.bmu_avail == radix) 5477090df5aSMatthew Dillon return; 5487090df5aSMatthew Dillon if (scan->u.bmu_avail > radix) 5497090df5aSMatthew Dillon panic("blst_meta_free: freeing already free blocks (%d) %d/%d", count, scan->u.bmu_avail, radix); 5507090df5aSMatthew Dillon 5517090df5aSMatthew Dillon /* 5527090df5aSMatthew Dillon * Break the free down into its components 5537090df5aSMatthew Dillon */ 5547090df5aSMatthew Dillon 5557090df5aSMatthew Dillon radix >>= BLIST_META_RADIX_SHIFT; 5567090df5aSMatthew Dillon 5577090df5aSMatthew Dillon i = (freeBlk - blk) / radix; 5587090df5aSMatthew Dillon blk += i * radix; 5597090df5aSMatthew Dillon i = i * next_skip + 1; 5607090df5aSMatthew Dillon 5617090df5aSMatthew Dillon while (i <= skip && blk < freeBlk + count) { 5627090df5aSMatthew Dillon daddr_t v; 5637090df5aSMatthew Dillon 5647090df5aSMatthew Dillon v = blk + radix - freeBlk; 5657090df5aSMatthew Dillon if (v > count) 5667090df5aSMatthew Dillon v = count; 5677090df5aSMatthew Dillon 5687090df5aSMatthew Dillon if (scan->bm_bighint == (daddr_t)-1) 5697090df5aSMatthew Dillon panic("blst_meta_free: freeing unexpected range"); 5707090df5aSMatthew Dillon 5717090df5aSMatthew Dillon if (next_skip == 1) { 5727090df5aSMatthew Dillon blst_leaf_free(&scan[i], freeBlk, v); 5737090df5aSMatthew Dillon } else { 5747090df5aSMatthew Dillon blst_meta_free(&scan[i], freeBlk, v, radix, next_skip - 1, blk); 5757090df5aSMatthew Dillon } 5767090df5aSMatthew Dillon if (scan->bm_bighint < scan[i].bm_bighint) 5777090df5aSMatthew Dillon scan->bm_bighint = scan[i].bm_bighint; 5787090df5aSMatthew Dillon count -= v; 5797090df5aSMatthew Dillon freeBlk += v; 5807090df5aSMatthew Dillon blk += radix; 5817090df5aSMatthew Dillon i += next_skip; 5827090df5aSMatthew Dillon } 5837090df5aSMatthew Dillon } 5847090df5aSMatthew Dillon 5857090df5aSMatthew Dillon /* 5867090df5aSMatthew Dillon * BLIST_RADIX_COPY() - copy one radix tree to another 5877090df5aSMatthew Dillon * 5887090df5aSMatthew Dillon * Locates free space in the source tree and frees it in the destination 5897090df5aSMatthew Dillon * tree. The space may not already be free in the destination. 5907090df5aSMatthew Dillon */ 5917090df5aSMatthew Dillon 5927090df5aSMatthew Dillon static void blst_copy( 5937090df5aSMatthew Dillon blmeta_t *scan, 5947090df5aSMatthew Dillon daddr_t blk, 5957090df5aSMatthew Dillon daddr_t radix, 5967090df5aSMatthew Dillon daddr_t skip, 5977090df5aSMatthew Dillon blist_t dest, 5987090df5aSMatthew Dillon daddr_t count 5997090df5aSMatthew Dillon ) { 6007090df5aSMatthew Dillon int next_skip; 6017090df5aSMatthew Dillon int i; 6027090df5aSMatthew Dillon 6037090df5aSMatthew Dillon /* 6047090df5aSMatthew Dillon * Leaf node 6057090df5aSMatthew Dillon */ 6067090df5aSMatthew Dillon 6077090df5aSMatthew Dillon if (radix == BLIST_BMAP_RADIX) { 6087090df5aSMatthew Dillon u_daddr_t v = scan->u.bmu_bitmap; 6097090df5aSMatthew Dillon 6107090df5aSMatthew Dillon if (v == (u_daddr_t)-1) { 6117090df5aSMatthew Dillon blist_free(dest, blk, count); 6127090df5aSMatthew Dillon } else if (v != 0) { 6137090df5aSMatthew Dillon int i; 6147090df5aSMatthew Dillon 6157090df5aSMatthew Dillon for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) { 6167090df5aSMatthew Dillon if (v & (1 << i)) 6177090df5aSMatthew Dillon blist_free(dest, blk + i, 1); 6187090df5aSMatthew Dillon } 6197090df5aSMatthew Dillon } 6207090df5aSMatthew Dillon return; 6217090df5aSMatthew Dillon } 6227090df5aSMatthew Dillon 6237090df5aSMatthew Dillon /* 6247090df5aSMatthew Dillon * Meta node 6257090df5aSMatthew Dillon */ 6267090df5aSMatthew Dillon 6277090df5aSMatthew Dillon if (scan->u.bmu_avail == 0) { 6287090df5aSMatthew Dillon /* 6297090df5aSMatthew Dillon * Source all allocated, leave dest allocated 6307090df5aSMatthew Dillon */ 6317090df5aSMatthew Dillon return; 6327090df5aSMatthew Dillon } 6337090df5aSMatthew Dillon if (scan->u.bmu_avail == radix) { 6347090df5aSMatthew Dillon /* 6357090df5aSMatthew Dillon * Source all free, free entire dest 6367090df5aSMatthew Dillon */ 6377090df5aSMatthew Dillon if (count < radix) 6387090df5aSMatthew Dillon blist_free(dest, blk, count); 6397090df5aSMatthew Dillon else 6407090df5aSMatthew Dillon blist_free(dest, blk, radix); 6417090df5aSMatthew Dillon return; 6427090df5aSMatthew Dillon } 6437090df5aSMatthew Dillon 6447090df5aSMatthew Dillon 6457090df5aSMatthew Dillon radix >>= BLIST_META_RADIX_SHIFT; 6467090df5aSMatthew Dillon next_skip = (skip >> BLIST_META_RADIX_SHIFT); 6477090df5aSMatthew Dillon 6487090df5aSMatthew Dillon for (i = 1; count && i <= skip; i += next_skip) { 6497090df5aSMatthew Dillon if (scan[i].bm_bighint == (daddr_t)-1) 6507090df5aSMatthew Dillon break; 6517090df5aSMatthew Dillon 6527090df5aSMatthew Dillon if (count >= radix) { 6537090df5aSMatthew Dillon blst_copy( 6547090df5aSMatthew Dillon &scan[i], 6557090df5aSMatthew Dillon blk, 6567090df5aSMatthew Dillon radix, 6577090df5aSMatthew Dillon next_skip - 1, 6587090df5aSMatthew Dillon dest, 6597090df5aSMatthew Dillon radix 6607090df5aSMatthew Dillon ); 6617090df5aSMatthew Dillon count -= radix; 6627090df5aSMatthew Dillon } else { 6637090df5aSMatthew Dillon if (count) { 6647090df5aSMatthew Dillon blst_copy( 6657090df5aSMatthew Dillon &scan[i], 6667090df5aSMatthew Dillon blk, 6677090df5aSMatthew Dillon radix, 6687090df5aSMatthew Dillon next_skip - 1, 6697090df5aSMatthew Dillon dest, 6707090df5aSMatthew Dillon count 6717090df5aSMatthew Dillon ); 6727090df5aSMatthew Dillon } 6737090df5aSMatthew Dillon count = 0; 6747090df5aSMatthew Dillon } 6757090df5aSMatthew Dillon blk += radix; 6767090df5aSMatthew Dillon } 6777090df5aSMatthew Dillon } 6787090df5aSMatthew Dillon 6797090df5aSMatthew Dillon /* 6807090df5aSMatthew Dillon * BLST_RADIX_INIT() - initialize radix tree 6817090df5aSMatthew Dillon * 6827090df5aSMatthew Dillon * Initialize our meta structures and bitmaps and calculate the exact 6837090df5aSMatthew Dillon * amount of space required to manage 'count' blocks - this space may 6847090df5aSMatthew Dillon * be considerably less then the calculated radix due to the large 6857090df5aSMatthew Dillon * RADIX values we use. 6867090df5aSMatthew Dillon */ 6877090df5aSMatthew Dillon 6887090df5aSMatthew Dillon static daddr_t 6897090df5aSMatthew Dillon blst_radix_init(blmeta_t *scan, daddr_t radix, int skip, daddr_t count) 6907090df5aSMatthew Dillon { 6917090df5aSMatthew Dillon int i; 6927090df5aSMatthew Dillon int next_skip; 6937090df5aSMatthew Dillon daddr_t memindex = 0; 6947090df5aSMatthew Dillon 6957090df5aSMatthew Dillon /* 6967090df5aSMatthew Dillon * Leaf node 6977090df5aSMatthew Dillon */ 6987090df5aSMatthew Dillon 6997090df5aSMatthew Dillon if (radix == BLIST_BMAP_RADIX) { 7007090df5aSMatthew Dillon if (scan) { 7017090df5aSMatthew Dillon scan->bm_bighint = 0; 7027090df5aSMatthew Dillon scan->u.bmu_bitmap = 0; 7037090df5aSMatthew Dillon } 7047090df5aSMatthew Dillon return(memindex); 7057090df5aSMatthew Dillon } 7067090df5aSMatthew Dillon 7077090df5aSMatthew Dillon /* 7087090df5aSMatthew Dillon * Meta node. If allocating the entire object we can special 7097090df5aSMatthew Dillon * case it. However, we need to figure out how much memory 7107090df5aSMatthew Dillon * is required to manage 'count' blocks, so we continue on anyway. 7117090df5aSMatthew Dillon */ 7127090df5aSMatthew Dillon 7137090df5aSMatthew Dillon if (scan) { 7147090df5aSMatthew Dillon scan->bm_bighint = 0; 7157090df5aSMatthew Dillon scan->u.bmu_avail = 0; 7167090df5aSMatthew Dillon } 7177090df5aSMatthew Dillon 7187090df5aSMatthew Dillon radix >>= BLIST_META_RADIX_SHIFT; 7197090df5aSMatthew Dillon next_skip = (skip >> BLIST_META_RADIX_SHIFT); 7207090df5aSMatthew Dillon 7217090df5aSMatthew Dillon for (i = 1; i <= skip; i += next_skip) { 7227090df5aSMatthew Dillon if (count >= radix) { 7237090df5aSMatthew Dillon /* 7247090df5aSMatthew Dillon * Allocate the entire object 7257090df5aSMatthew Dillon */ 7267090df5aSMatthew Dillon memindex = i + blst_radix_init( 7277090df5aSMatthew Dillon ((scan) ? &scan[i] : NULL), 7287090df5aSMatthew Dillon radix, 7297090df5aSMatthew Dillon next_skip - 1, 7307090df5aSMatthew Dillon radix 7317090df5aSMatthew Dillon ); 7327090df5aSMatthew Dillon count -= radix; 7337090df5aSMatthew Dillon } else if (count > 0) { 7347090df5aSMatthew Dillon /* 7357090df5aSMatthew Dillon * Allocate a partial object 7367090df5aSMatthew Dillon */ 7377090df5aSMatthew Dillon memindex = i + blst_radix_init( 7387090df5aSMatthew Dillon ((scan) ? &scan[i] : NULL), 7397090df5aSMatthew Dillon radix, 7407090df5aSMatthew Dillon next_skip - 1, 7417090df5aSMatthew Dillon count 7427090df5aSMatthew Dillon ); 7437090df5aSMatthew Dillon count = 0; 7447090df5aSMatthew Dillon } else { 7457090df5aSMatthew Dillon /* 7467090df5aSMatthew Dillon * Add terminator and break out 7477090df5aSMatthew Dillon */ 7487090df5aSMatthew Dillon if (scan) 7497090df5aSMatthew Dillon scan[i].bm_bighint = (daddr_t)-1; 7507090df5aSMatthew Dillon break; 7517090df5aSMatthew Dillon } 7527090df5aSMatthew Dillon } 7537090df5aSMatthew Dillon if (memindex < i) 7547090df5aSMatthew Dillon memindex = i; 7557090df5aSMatthew Dillon return(memindex); 7567090df5aSMatthew Dillon } 7577090df5aSMatthew Dillon 7587090df5aSMatthew Dillon #ifdef BLIST_DEBUG 7597090df5aSMatthew Dillon 7607090df5aSMatthew Dillon static void 7617090df5aSMatthew Dillon blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int skip, int tab) 7627090df5aSMatthew Dillon { 7637090df5aSMatthew Dillon int i; 7647090df5aSMatthew Dillon int next_skip; 7657090df5aSMatthew Dillon int lastState = 0; 7667090df5aSMatthew Dillon 7677090df5aSMatthew Dillon if (radix == BLIST_BMAP_RADIX) { 7687090df5aSMatthew Dillon printf( 7697090df5aSMatthew Dillon "%*.*s(%04x,%d): bitmap %08x big=%d\n", 7707090df5aSMatthew Dillon tab, tab, "", 7717090df5aSMatthew Dillon blk, radix, 7727090df5aSMatthew Dillon scan->u.bmu_bitmap, 7737090df5aSMatthew Dillon scan->bm_bighint 7747090df5aSMatthew Dillon ); 7757090df5aSMatthew Dillon return; 7767090df5aSMatthew Dillon } 7777090df5aSMatthew Dillon 7787090df5aSMatthew Dillon if (scan->u.bmu_avail == 0) { 7797090df5aSMatthew Dillon printf( 7807090df5aSMatthew Dillon "%*.*s(%04x,%d) ALL ALLOCATED\n", 7817090df5aSMatthew Dillon tab, tab, "", 7827090df5aSMatthew Dillon blk, 7837090df5aSMatthew Dillon radix 7847090df5aSMatthew Dillon ); 7857090df5aSMatthew Dillon return; 7867090df5aSMatthew Dillon } 7877090df5aSMatthew Dillon if (scan->u.bmu_avail == radix) { 7887090df5aSMatthew Dillon printf( 7897090df5aSMatthew Dillon "%*.*s(%04x,%d) ALL FREE\n", 7907090df5aSMatthew Dillon tab, tab, "", 7917090df5aSMatthew Dillon blk, 7927090df5aSMatthew Dillon radix 7937090df5aSMatthew Dillon ); 7947090df5aSMatthew Dillon return; 7957090df5aSMatthew Dillon } 7967090df5aSMatthew Dillon 7977090df5aSMatthew Dillon printf( 7987090df5aSMatthew Dillon "%*.*s(%04x,%d): subtree (%d/%d) big=%d {\n", 7997090df5aSMatthew Dillon tab, tab, "", 8007090df5aSMatthew Dillon blk, radix, 8017090df5aSMatthew Dillon scan->u.bmu_avail, 8027090df5aSMatthew Dillon radix, 8037090df5aSMatthew Dillon scan->bm_bighint 8047090df5aSMatthew Dillon ); 8057090df5aSMatthew Dillon 8067090df5aSMatthew Dillon radix >>= BLIST_META_RADIX_SHIFT; 8077090df5aSMatthew Dillon next_skip = (skip >> BLIST_META_RADIX_SHIFT); 8087090df5aSMatthew Dillon tab += 4; 8097090df5aSMatthew Dillon 8107090df5aSMatthew Dillon for (i = 1; i <= skip; i += next_skip) { 8117090df5aSMatthew Dillon if (scan[i].bm_bighint == (daddr_t)-1) { 8127090df5aSMatthew Dillon printf( 8137090df5aSMatthew Dillon "%*.*s(%04x,%d): Terminator\n", 8147090df5aSMatthew Dillon tab, tab, "", 8157090df5aSMatthew Dillon blk, radix 8167090df5aSMatthew Dillon ); 8177090df5aSMatthew Dillon lastState = 0; 8187090df5aSMatthew Dillon break; 8197090df5aSMatthew Dillon } 8207090df5aSMatthew Dillon blst_radix_print( 8217090df5aSMatthew Dillon &scan[i], 8227090df5aSMatthew Dillon blk, 8237090df5aSMatthew Dillon radix, 8247090df5aSMatthew Dillon next_skip - 1, 8257090df5aSMatthew Dillon tab 8267090df5aSMatthew Dillon ); 8277090df5aSMatthew Dillon blk += radix; 8287090df5aSMatthew Dillon } 8297090df5aSMatthew Dillon tab -= 4; 8307090df5aSMatthew Dillon 8317090df5aSMatthew Dillon printf( 8327090df5aSMatthew Dillon "%*.*s}\n", 8337090df5aSMatthew Dillon tab, tab, "" 8347090df5aSMatthew Dillon ); 8357090df5aSMatthew Dillon } 8367090df5aSMatthew Dillon 8377090df5aSMatthew Dillon #endif 8387090df5aSMatthew Dillon 8397090df5aSMatthew Dillon #ifdef BLIST_DEBUG 8407090df5aSMatthew Dillon 8417090df5aSMatthew Dillon int 8427090df5aSMatthew Dillon main(int ac, char **av) 8437090df5aSMatthew Dillon { 8447090df5aSMatthew Dillon int size = 1024; 8457090df5aSMatthew Dillon int i; 8467090df5aSMatthew Dillon blist_t bl; 8477090df5aSMatthew Dillon 8487090df5aSMatthew Dillon for (i = 1; i < ac; ++i) { 8497090df5aSMatthew Dillon const char *ptr = av[i]; 8507090df5aSMatthew Dillon if (*ptr != '-') { 8517090df5aSMatthew Dillon size = strtol(ptr, NULL, 0); 8527090df5aSMatthew Dillon continue; 8537090df5aSMatthew Dillon } 8547090df5aSMatthew Dillon ptr += 2; 8557090df5aSMatthew Dillon fprintf(stderr, "Bad option: %s\n", ptr - 2); 8567090df5aSMatthew Dillon exit(1); 8577090df5aSMatthew Dillon } 8587090df5aSMatthew Dillon bl = blist_create(size); 8597090df5aSMatthew Dillon blist_free(bl, 0, size); 8607090df5aSMatthew Dillon 8617090df5aSMatthew Dillon for (;;) { 8627090df5aSMatthew Dillon char buf[1024]; 8637090df5aSMatthew Dillon daddr_t da = 0; 8647090df5aSMatthew Dillon daddr_t count = 0; 8657090df5aSMatthew Dillon 8667090df5aSMatthew Dillon 8677090df5aSMatthew Dillon printf("%d/%d/%d> ", bl->bl_free, size, bl->bl_radix); 8687090df5aSMatthew Dillon fflush(stdout); 8697090df5aSMatthew Dillon if (fgets(buf, sizeof(buf), stdin) == NULL) 8707090df5aSMatthew Dillon break; 8717090df5aSMatthew Dillon switch(buf[0]) { 8727090df5aSMatthew Dillon case 'r': 8737090df5aSMatthew Dillon if (sscanf(buf + 1, "%d", &count) == 1) { 8747090df5aSMatthew Dillon blist_resize(&bl, count, 1); 8757090df5aSMatthew Dillon } else { 8767090df5aSMatthew Dillon printf("?\n"); 8777090df5aSMatthew Dillon } 8787090df5aSMatthew Dillon case 'p': 8797090df5aSMatthew Dillon blist_print(bl); 8807090df5aSMatthew Dillon break; 8817090df5aSMatthew Dillon case 'a': 8827090df5aSMatthew Dillon if (sscanf(buf + 1, "%d", &count) == 1) { 8837090df5aSMatthew Dillon daddr_t blk = blist_alloc(bl, count); 8847090df5aSMatthew Dillon printf(" R=%04x\n", blk); 8857090df5aSMatthew Dillon } else { 8867090df5aSMatthew Dillon printf("?\n"); 8877090df5aSMatthew Dillon } 8887090df5aSMatthew Dillon break; 8897090df5aSMatthew Dillon case 'f': 8907090df5aSMatthew Dillon if (sscanf(buf + 1, "%x %d", &da, &count) == 2) { 8917090df5aSMatthew Dillon blist_free(bl, da, count); 8927090df5aSMatthew Dillon } else { 8937090df5aSMatthew Dillon printf("?\n"); 8947090df5aSMatthew Dillon } 8957090df5aSMatthew Dillon break; 8967090df5aSMatthew Dillon case '?': 8977090df5aSMatthew Dillon case 'h': 8987090df5aSMatthew Dillon puts( 8997090df5aSMatthew Dillon "p -print\n" 9007090df5aSMatthew Dillon "a %d -allocate\n" 9017090df5aSMatthew Dillon "f %x %d -free\n" 9027090df5aSMatthew Dillon "r %d -resize\n" 9037090df5aSMatthew Dillon "h/? -help" 9047090df5aSMatthew Dillon ); 9057090df5aSMatthew Dillon break; 9067090df5aSMatthew Dillon default: 9077090df5aSMatthew Dillon printf("?\n"); 9087090df5aSMatthew Dillon break; 9097090df5aSMatthew Dillon } 9107090df5aSMatthew Dillon } 9117090df5aSMatthew Dillon return(0); 9127090df5aSMatthew Dillon } 9137090df5aSMatthew Dillon 9147090df5aSMatthew Dillon void 9157090df5aSMatthew Dillon panic(const char *ctl, ...) 9167090df5aSMatthew Dillon { 9177090df5aSMatthew Dillon va_list va; 9187090df5aSMatthew Dillon 9197090df5aSMatthew Dillon va_start(va, ctl); 9207090df5aSMatthew Dillon vfprintf(stderr, ctl, va); 9217090df5aSMatthew Dillon fprintf(stderr, "\n"); 9227090df5aSMatthew Dillon va_end(va); 9237090df5aSMatthew Dillon exit(1); 9247090df5aSMatthew Dillon } 9257090df5aSMatthew Dillon 9267090df5aSMatthew Dillon #endif 9277090df5aSMatthew Dillon 928