4 * Bitmap allocator/deallocator, using a radix tree with hinting.
5 * Unlimited-size allocations, power-of-2 only, power-of-2 aligned results
6 * only. This module has been separated from the generic kernel module and
7 * written specifically for embedding in HAMMER storage structures.
9 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
11 * This code is derived from software contributed to The DragonFly Project
12 * by Matthew Dillon <dillon@backplane.com>
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in
22 * the documentation and/or other materials provided with the
24 * 3. Neither the name of The DragonFly Project nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific, prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
34 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
36 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * $DragonFly: src/sys/vfs/hammer/Attic/hammer_alist.c,v 1.2 2007/10/12 18:57:45 dillon Exp $
44 * This module implements a generic allocator through the use of a hinted
45 * radix tree. All allocations must be in powers of 2 and will return
46 * similarly aligned results. The radix tree typically recurses within
47 * a memory buffer and then continues its recursion by chaining to other
48 * memory buffers, creating a seemless whole capable of managing any amount
51 * The radix tree is layed out recursively using a linear array. Each meta
52 * node is immediately followed (layed out sequentially in memory) by
53 * HAMMER_ALIST_META_RADIX lower level nodes. This is a recursive structure
54 * but one that can be easily scanned through a very simple 'skip'
57 * The radix tree supports an early-termination optimization which
58 * effectively allows us to efficiently mix large and small allocations
59 * with a single abstraction. The address space can be partitioned
60 * arbitrarily without adding much in the way of additional meta-storage
63 * The radix tree supports allocator layering. By supplying a base_radix > 1
64 * the allocator will issue callbacks to recurse into lower layers once
65 * higher layers have been exhausted. Allocations in multiples of base_radix
66 * will be entirely retained in the higher level allocator and never recurse.
68 * This code can be compiled stand-alone for debugging.
73 #include <sys/param.h>
74 #include <sys/systm.h>
76 #include <sys/kernel.h>
77 #include <sys/malloc.h>
79 #include <vm/vm_object.h>
80 #include <vm/vm_kern.h>
81 #include <vm/vm_extern.h>
82 #include <vm/vm_page.h>
84 #include "hammer_disk.h"
88 #ifndef ALIST_NO_DEBUG
92 #include <sys/types.h>
99 #define kmalloc(a,b,c) malloc(a)
100 #define kfree(a,b) free(a)
101 #define kprintf printf
102 #define KKASSERT(exp) assert(exp)
105 #include "hammer_alist.h"
107 void panic(const char *ctl, ...);
112 * static support functions
115 static int32_t hammer_alst_leaf_alloc_fwd(hammer_almeta_t scan,
116 int32_t blk, int count);
117 static int32_t hammer_alst_meta_alloc_fwd(hammer_alist_t live,
118 hammer_almeta_t scan,
119 int32_t blk, int32_t count,
120 int32_t radix, int skip);
121 static int32_t hammer_alst_leaf_alloc_rev(hammer_almeta_t scan,
122 int32_t blk, int count);
123 static int32_t hammer_alst_meta_alloc_rev(hammer_alist_t live,
124 hammer_almeta_t scan,
125 int32_t blk, int32_t count,
126 int32_t radix, int skip);
127 static void hammer_alst_leaf_free(hammer_almeta_t scan,
128 int32_t relblk, int count);
129 static void hammer_alst_meta_free(hammer_alist_t live, hammer_almeta_t scan,
130 int32_t freeBlk, int32_t count,
131 int32_t radix, int skip, int32_t blk);
132 static int32_t hammer_alst_radix_init(hammer_almeta_t scan,
133 int32_t radix, int skip, int32_t count);
135 static void hammer_alst_radix_print(hammer_alist_t live,
136 hammer_almeta_t scan, int32_t blk,
137 int32_t radix, int skip, int tab);
141 * Initialize an a-list config structure for use. The config structure
142 * describes the basic structure of an a-list's topology and may be
143 * shared by any number of a-lists which have the same topology.
145 * blocks is the total number of blocks, that is the number of blocks
146 * handled at this layer multiplied by the base radix.
148 * When base_radix != 1 the A-list has only meta elements and does not have
149 * any leaves, in order to be able to track partial allocations.
152 hammer_alist_template(hammer_alist_config_t bl, int32_t blocks,
153 int32_t base_radix, int32_t maxmeta)
159 * Calculate radix and skip field used for scanning. The leaf nodes
160 * in our tree are either BMAP or META nodes depending on whether
161 * we chain to a lower level allocation layer or not.
164 radix = HAMMER_ALIST_BMAP_RADIX;
166 radix = HAMMER_ALIST_META_RADIX;
169 while (radix < blocks / base_radix) {
170 radix *= HAMMER_ALIST_META_RADIX;
171 skip = skip * HAMMER_ALIST_META_RADIX + 1;
175 * Increase the radix based on the number of blocks a lower level
176 * allocator is able to handle at the 'base' of our allocator.
177 * If base_radix != 1 the caller will have to initialize the callback
178 * fields to implement the lower level allocator.
182 bzero(bl, sizeof(*bl));
184 bl->bl_blocks = blocks;
185 bl->bl_base_radix = base_radix;
186 bl->bl_radix = radix;
188 bl->bl_rootblks = hammer_alst_radix_init(NULL, bl->bl_radix,
189 bl->bl_skip, blocks);
190 ++bl->bl_rootblks; /* one more for freeblks header */
193 KKASSERT(maxmeta == 0 || bl->bl_rootblks <= maxmeta);
195 #if defined(ALIST_DEBUG)
197 "PRIMARY ALIST LAYER manages %d blocks"
198 ", requiring %dK (%d bytes) of ram\n",
199 bl->bl_blocks / bl->bl_base_radix,
200 (bl->bl_rootblks * sizeof(struct hammer_almeta) + 1023) / 1024,
201 (bl->bl_rootblks * sizeof(struct hammer_almeta))
203 kprintf("ALIST raw radix tree contains %d records\n", bl->bl_rootblks);
208 hammer_alist_init(hammer_alist_t live)
210 hammer_alist_config_t bl = live->config;
212 live->meta->bm_bighint = 0;
213 live->meta->bm_alist_freeblks = 0;
214 hammer_alst_radix_init(live->meta + 1, bl->bl_radix,
215 bl->bl_skip, bl->bl_blocks);
218 #if !defined(_KERNEL) && defined(ALIST_DEBUG)
221 * hammer_alist_create() (userland only)
223 * create a alist capable of handling up to the specified number of
224 * blocks. blocks must be greater then 0
226 * The smallest alist consists of a single leaf node capable of
227 * managing HAMMER_ALIST_BMAP_RADIX blocks, or (if base_radix != 1)
228 * a single meta node capable of managing HAMMER_ALIST_META_RADIX
229 * blocks which recurses into other storage layers for a total
230 * handling capability of (HAMMER_ALIST_META_RADIX * base_radix) blocks.
232 * Larger a-list's increase their capability exponentially by
233 * HAMMER_ALIST_META_RADIX.
235 * The block count is the total number of blocks inclusive of any
236 * layering. blocks can be less then base_radix and will result in
237 * a radix tree with a single leaf node which then chains down.
241 hammer_alist_create(int32_t blocks, int32_t base_radix,
242 struct malloc_type *mtype)
245 hammer_alist_config_t bl;
248 live = kmalloc(sizeof(*live), mtype, M_WAITOK);
249 live->config = bl = kmalloc(sizeof(*bl), mtype, M_WAITOK);
250 hammer_alist_template(bl, blocks, base_radix, 0);
252 metasize = sizeof(*live->meta) * bl->bl_rootblks;
253 live->meta = kmalloc(metasize, mtype, M_WAITOK);
254 bzero(live->meta, metasize);
256 #if defined(ALIST_DEBUG)
258 "ALIST representing %d blocks (%d MB of swap)"
259 ", requiring %dK (%d bytes) of ram\n",
261 bl->bl_blocks * 4 / 1024,
262 (bl->bl_rootblks * sizeof(*live->meta) + 1023) / 1024,
263 (bl->bl_rootblks * sizeof(*live->meta))
265 if (base_radix != 1) {
266 kprintf("ALIST recurses when it reaches a base_radix of %d\n",
269 kprintf("ALIST raw radix tree contains %d records\n", bl->bl_rootblks);
271 hammer_alist_init(live);
276 hammer_alist_destroy(hammer_alist_t live, struct malloc_type *mtype)
278 kfree(live->config, mtype);
279 kfree(live->meta, mtype);
288 * hammer_alist_alloc()
290 * Reserve space in the block bitmap. Return the base of a contiguous
291 * region or HAMMER_ALIST_BLOCK_NONE if space could not be allocated.
295 hammer_alist_alloc(hammer_alist_t live, int32_t count)
297 int32_t blk = HAMMER_ALIST_BLOCK_NONE;
298 hammer_alist_config_t bl = live->config;
300 KKASSERT((count | (count - 1)) == (count << 1) - 1);
302 if (bl && count <= bl->bl_radix) {
304 * When skip is 1 we are at a leaf. If we are the terminal
305 * allocator we use our native leaf functions and radix will
306 * be HAMMER_ALIST_BMAP_RADIX. Otherwise we are a meta node
307 * which will chain to another allocator.
309 if (bl->bl_skip == 1 && bl->bl_terminal) {
311 KKASSERT(bl->bl_radix == HAMMER_ALIST_BMAP_RADIX);
313 blk = hammer_alst_leaf_alloc_fwd(
314 live->meta + 1, 0, count);
316 blk = hammer_alst_meta_alloc_fwd(
317 live, live->meta + 1,
318 0, count, bl->bl_radix, bl->bl_skip);
320 if (blk != HAMMER_ALIST_BLOCK_NONE)
321 live->meta->bm_alist_freeblks -= count;
327 hammer_alist_alloc_rev(hammer_alist_t live, int32_t count)
329 hammer_alist_config_t bl = live->config;
330 int32_t blk = HAMMER_ALIST_BLOCK_NONE;
332 KKASSERT((count | (count - 1)) == (count << 1) - 1);
334 if (bl && count < bl->bl_radix) {
335 if (bl->bl_skip == 1 && bl->bl_terminal) {
337 KKASSERT(bl->bl_radix == HAMMER_ALIST_BMAP_RADIX);
339 blk = hammer_alst_leaf_alloc_rev(
340 live->meta + 1, 0, count);
342 blk = hammer_alst_meta_alloc_rev(
343 live, live->meta + 1,
344 0, count, bl->bl_radix, bl->bl_skip);
346 if (blk != HAMMER_ALIST_BLOCK_NONE)
347 live->meta->bm_alist_freeblks -= count;
355 * hammer_alist_alloc_from()
357 * An extended version of hammer_alist_alloc() which locates free space
358 * starting at the specified block either forwards or backwards.
359 * HAMMER_ALIST_BLOCK_NONE is returned if space could not be allocated.
361 * Note: when allocating from a particular point forwards space is never
362 * allocated behind that start point, and similarly when going backwards.
365 hammer_alist_alloc_from(hammer_alist_t live, int32_t count, int32_t start)
374 * Free up space in the block bitmap. Return the base of a contiguous
375 * region. Panic if an inconsistancy is found.
377 * Unlike allocations, there are no alignment requirements for blkno or
378 * count when freeing blocks.
382 hammer_alist_free(hammer_alist_t live, int32_t blkno, int32_t count)
384 hammer_alist_config_t bl = live->config;
386 KKASSERT(blkno + count <= bl->bl_blocks);
387 if (bl->bl_skip == 1 && bl->bl_terminal) {
389 KKASSERT(bl->bl_radix == HAMMER_ALIST_BMAP_RADIX);
391 hammer_alst_leaf_free(live->meta + 1, blkno, count);
393 hammer_alst_meta_free(live, live->meta + 1,
395 bl->bl_radix, bl->bl_skip, 0);
397 live->meta->bm_alist_freeblks += count;
403 * alist_print() - dump radix tree
407 hammer_alist_print(hammer_alist_t live, int tab)
409 hammer_alist_config_t bl = live->config;
411 kprintf("%*.*sALIST (%d free blocks) {\n",
412 tab, tab, "", live->meta->bm_alist_freeblks);
413 hammer_alst_radix_print(live, live->meta + 1, 0,
414 bl->bl_radix, bl->bl_skip, tab + 4);
415 kprintf("%*.*s}\n", tab, tab, "");
420 /************************************************************************
421 * ALLOCATION SUPPORT FUNCTIONS *
422 ************************************************************************
424 * These support functions do all the actual work. They may seem
425 * rather longish, but that's because I've commented them up. The
426 * actual code is straight forward.
431 * hammer_alist_leaf_alloc_fwd()
433 * Allocate at a leaf in the radix tree (a bitmap).
435 * This is the core of the allocator and is optimized for the 1 block
436 * and the HAMMER_ALIST_BMAP_RADIX block allocation cases. Other cases
437 * are somewhat slower. The 1 block allocation case is log2 and extremely
442 hammer_alst_leaf_alloc_fwd(hammer_almeta_t scan, int32_t blk, int count)
444 u_int32_t orig = scan->bm_bitmap;
447 * Optimize bitmap all-allocated case. Also, count = 1
448 * case assumes at least 1 bit is free in the bitmap, so
449 * we have to take care of this case here.
452 scan->bm_bighint = 0;
453 return(HAMMER_ALIST_BLOCK_NONE);
457 * Optimized code to allocate one bit out of the bitmap
461 int j = HAMMER_ALIST_BMAP_RADIX/2;
464 mask = (u_int32_t)-1 >> (HAMMER_ALIST_BMAP_RADIX/2);
467 if ((orig & mask) == 0) {
474 scan->bm_bitmap &= ~(1 << r);
479 * non-optimized code to allocate N bits out of the bitmap.
480 * The more bits, the faster the code runs. It will run
481 * the slowest allocating 2 bits, but since there aren't any
482 * memory ops in the core loop (or shouldn't be, anyway),
483 * you probably won't notice the difference.
485 * Similar to the blist case, the alist code also requires
486 * allocations to be power-of-2 sized and aligned to the
487 * size of the allocation, which simplifies the algorithm.
491 int n = HAMMER_ALIST_BMAP_RADIX - count;
494 mask = (u_int32_t)-1 >> n;
496 for (j = 0; j <= n; j += count) {
497 if ((orig & mask) == mask) {
498 scan->bm_bitmap &= ~mask;
501 mask = mask << count;
506 * We couldn't allocate count in this subtree, update bighint.
508 scan->bm_bighint = count - 1;
509 return(HAMMER_ALIST_BLOCK_NONE);
513 * This version allocates blocks in the reverse direction.
516 hammer_alst_leaf_alloc_rev(hammer_almeta_t scan, int32_t blk, int count)
518 u_int32_t orig = scan->bm_bitmap;
521 * Optimize bitmap all-allocated case. Also, count = 1
522 * case assumes at least 1 bit is free in the bitmap, so
523 * we have to take care of this case here.
526 scan->bm_bighint = 0;
527 return(HAMMER_ALIST_BLOCK_NONE);
531 * Optimized code to allocate one bit out of the bitmap
535 int j = HAMMER_ALIST_BMAP_RADIX/2;
536 int r = HAMMER_ALIST_BMAP_RADIX - 1;
538 mask = ~((u_int32_t)-1 >> (HAMMER_ALIST_BMAP_RADIX/2));
541 if ((orig & mask) == 0) {
548 scan->bm_bitmap &= ~(1 << r);
553 * non-optimized code to allocate N bits out of the bitmap.
554 * The more bits, the faster the code runs. It will run
555 * the slowest allocating 2 bits, but since there aren't any
556 * memory ops in the core loop (or shouldn't be, anyway),
557 * you probably won't notice the difference.
559 * Similar to the blist case, the alist code also requires
560 * allocations to be power-of-2 sized and aligned to the
561 * size of the allocation, which simplifies the algorithm.
563 * initial mask if count == 2: 1100....0000
567 int n = HAMMER_ALIST_BMAP_RADIX - count;
570 mask = ((u_int32_t)-1 >> n) << n;
572 for (j = n; j >= 0; j -= count) {
573 if ((orig & mask) == mask) {
574 scan->bm_bitmap &= ~mask;
577 mask = mask >> count;
582 * We couldn't allocate count in this subtree, update bighint.
584 scan->bm_bighint = count - 1;
585 return(HAMMER_ALIST_BLOCK_NONE);
589 * hammer_alist_meta_alloc_fwd()
591 * Allocate at a meta in the radix tree.
593 * Attempt to allocate at a meta node. If we can't, we update
594 * bighint and return a failure. Updating bighint optimize future
595 * calls that hit this node. We have to check for our collapse cases
596 * and we have a few optimizations strewn in as well.
599 hammer_alst_meta_alloc_fwd(hammer_alist_t live, hammer_almeta_t scan,
600 int32_t blk, int32_t count,
601 int32_t radix, int skip
603 hammer_alist_config_t bl;
610 * ALL-ALLOCATED special case
612 if (scan->bm_bitmap == 0) {
613 scan->bm_bighint = 0;
614 return(HAMMER_ALIST_BLOCK_NONE);
617 radix /= HAMMER_ALIST_META_RADIX;
621 * Radix now represents each bitmap entry for this meta node. If
622 * the number of blocks being allocated can be fully represented,
623 * we allocate directly out of this meta node.
625 * Meta node bitmaps use 2 bits per block.
628 * 01 PARTIALLY-FREE/PARTIALLY-ALLOCATED
632 if (count >= radix) {
633 int n = count / radix * 2; /* number of bits */
636 mask = (u_int32_t)-1 >> (HAMMER_ALIST_BMAP_RADIX - n);
637 for (j = 0; j < HAMMER_ALIST_META_RADIX; j += n / 2) {
638 if ((scan->bm_bitmap & mask) == mask) {
639 scan->bm_bitmap &= ~mask;
640 return(blk + j * radix);
644 if (scan->bm_bighint >= count)
645 scan->bm_bighint = count >> 1;
646 return(HAMMER_ALIST_BLOCK_NONE);
650 * If the count is too big we couldn't allocate anything from a
651 * recursion even if the sub-tree were entirely free.
657 * If not we have to recurse.
664 * If skip is 1 we are a meta leaf node, which means there
665 * is another allocation layer we have to dive down into.
667 for (i = 0; i < HAMMER_ALIST_META_RADIX; ++i) {
669 * If the next layer is completely free then call
670 * its init function to initialize it and mark it
673 * bl_radix_init returns an error code or 0 on
676 if ((scan->bm_bitmap & mask) == mask) {
679 v = bl->bl_blocks - blk;
682 if (bl->bl_radix_init(live->info, blk, radix, v) == 0) {
683 scan->bm_bitmap &= ~mask;
684 scan->bm_bitmap |= pmask;
689 * If there may be some free blocks try to allocate
690 * out of the layer. If the layer indicates that
691 * it is completely full then clear both bits to
692 * propogate the condition.
694 if ((scan->bm_bitmap & mask) == pmask) {
698 r = bl->bl_radix_alloc_fwd(live->info, blk,
699 radix, count, &full);
700 if (r != HAMMER_ALIST_BLOCK_NONE) {
702 scan->bm_bitmap &= ~mask;
712 * Otherwise there are sub-records in the current a-list
713 * layer. We can also peek into the sub-layers to get
714 * more accurate size hints.
716 next_skip = (skip - 1) / HAMMER_ALIST_META_RADIX;
717 for (i = 1; i <= skip; i += next_skip) {
718 if (scan[i].bm_bighint == (int32_t)-1) {
724 if ((scan->bm_bitmap & mask) == mask) {
725 scan[i].bm_bitmap = (u_int32_t)-1;
726 scan[i].bm_bighint = radix;
729 if (count <= scan[i].bm_bighint) {
731 * count fits in object, recurse into the
732 * next layer. If the next_skip is 1 it
733 * will be either a normal leaf or a meta
738 if (next_skip == 1 && bl->bl_terminal) {
739 r = hammer_alst_leaf_alloc_fwd(
740 &scan[i], blk, count);
742 r = hammer_alst_meta_alloc_fwd(
747 if (r != HAMMER_ALIST_BLOCK_NONE) {
748 if (scan[i].bm_bitmap == 0) {
749 scan->bm_bitmap &= ~mask;
751 scan->bm_bitmap &= ~mask;
752 scan->bm_bitmap |= pmask;
765 * We couldn't allocate count in this subtree, update bighint.
767 if (scan->bm_bighint >= count)
768 scan->bm_bighint = count >> 1;
769 return(HAMMER_ALIST_BLOCK_NONE);
773 * This version allocates blocks in the reverse direction.
776 hammer_alst_meta_alloc_rev(hammer_alist_t live, hammer_almeta_t scan,
777 int32_t blk, int32_t count,
778 int32_t radix, int skip
780 hammer_alist_config_t bl;
788 * ALL-ALLOCATED special case
790 if (scan->bm_bitmap == 0) {
791 scan->bm_bighint = 0;
792 return(HAMMER_ALIST_BLOCK_NONE);
795 radix /= HAMMER_ALIST_META_RADIX;
799 * Radix now represents each bitmap entry for this meta node. If
800 * the number of blocks being allocated can be fully represented,
801 * we allocate directly out of this meta node.
803 * Meta node bitmaps use 2 bits per block.
806 * 01 PARTIALLY-FREE/PARTIALLY-ALLOCATED
810 if (count >= radix) {
811 int n = count / radix * 2; /* number of bits */
815 * Initial mask if e.g. n == 2: 1100....0000
817 mask = (u_int32_t)-1 >> (HAMMER_ALIST_BMAP_RADIX - n) <<
818 (HAMMER_ALIST_BMAP_RADIX - n);
819 for (j = HAMMER_ALIST_META_RADIX - n / 2; j >= 0; j -= n / 2) {
820 if ((scan->bm_bitmap & mask) == mask) {
821 scan->bm_bitmap &= ~mask;
822 return(blk + j * radix);
826 if (scan->bm_bighint >= count)
827 scan->bm_bighint = count >> 1;
828 return(HAMMER_ALIST_BLOCK_NONE);
832 * If the count is too big we couldn't allocate anything from a
833 * recursion even if the sub-tree were entirely free.
840 * We need the recurse but we are at a meta node leaf, which
841 * means there is another layer under us.
845 blk += radix * HAMMER_ALIST_META_RADIX - radix;
847 for (i = 0; i < HAMMER_ALIST_META_RADIX; ++i) {
849 * If the next layer is completely free then call
850 * its init function to initialize it and mark it
853 if ((scan->bm_bitmap & mask) == mask) {
856 v = bl->bl_blocks - blk;
859 if (bl->bl_radix_init(live->info, blk, radix, v) == 0) {
860 scan->bm_bitmap &= ~mask;
861 scan->bm_bitmap |= pmask;
866 * If there may be some free blocks try to allocate
867 * out of the layer. If the layer indicates that
868 * it is completely full then clear both bits to
869 * propogate the condition.
871 if ((scan->bm_bitmap & mask) == pmask) {
875 r = bl->bl_radix_alloc_rev(live->info, blk,
876 radix, count, &full);
877 if (r != HAMMER_ALIST_BLOCK_NONE) {
879 scan->bm_bitmap &= ~mask;
889 * Since we are going in the reverse direction we need an
890 * extra loop to determine if there is a terminator, then
893 * This is a little weird but we do not want to overflow the
894 * mask/pmask in the loop.
896 next_skip = (skip - 1) / HAMMER_ALIST_META_RADIX;
898 for (i = 1; i <= skip; i += next_skip) {
899 if (scan[i].bm_bighint == (int32_t)-1)
906 mask = 0x00000003 << j;
907 pmask = 0x00000001 << j;
912 * Initialize the bitmap in the child if allocating
913 * from the all-free case.
915 if ((scan->bm_bitmap & mask) == mask) {
916 scan[i].bm_bitmap = (u_int32_t)-1;
917 scan[i].bm_bighint = radix;
921 * Handle various count cases. Bighint may be too
922 * large but is never too small.
924 if (count <= scan[i].bm_bighint) {
926 * count fits in object
929 if (next_skip == 1 && bl->bl_terminal) {
930 r = hammer_alst_leaf_alloc_rev(
931 &scan[i], blk, count);
933 r = hammer_alst_meta_alloc_rev(
938 if (r != HAMMER_ALIST_BLOCK_NONE) {
939 if (scan[i].bm_bitmap == 0) {
940 scan->bm_bitmap &= ~mask;
942 scan->bm_bitmap &= ~mask;
943 scan->bm_bitmap |= pmask;
947 } else if (count > radix) {
949 * count does not fit in object even if it were
963 * We couldn't allocate count in this subtree, update bighint.
964 * Since we are restricted to powers of 2, the next highest count
965 * we might be able to allocate is (count >> 1).
967 if (scan->bm_bighint >= count)
968 scan->bm_bighint = count >> 1;
969 return(HAMMER_ALIST_BLOCK_NONE);
975 * Free allocated blocks from leaf bitmap. The allocation code is
976 * restricted to powers of 2, the freeing code is not.
979 hammer_alst_leaf_free(hammer_almeta_t scan, int32_t blk, int count) {
981 * free some data in this bitmap
984 * 0000111111111110000
988 int n = blk & (HAMMER_ALIST_BMAP_RADIX - 1);
991 mask = ((u_int32_t)-1 << n) &
992 ((u_int32_t)-1 >> (HAMMER_ALIST_BMAP_RADIX - count - n));
994 if (scan->bm_bitmap & mask)
995 panic("hammer_alst_radix_free: freeing free block");
996 scan->bm_bitmap |= mask;
999 * We could probably do a better job here. We are required to make
1000 * bighint at least as large as the biggest contiguous block of
1001 * data. If we just shoehorn it, a little extra overhead will
1002 * be incured on the next allocation (but only that one typically).
1004 scan->bm_bighint = HAMMER_ALIST_BMAP_RADIX;
1010 * Free allocated blocks from radix tree meta info.
1012 * This support routine frees a range of blocks from the bitmap.
1013 * The range must be entirely enclosed by this radix node. If a
1014 * meta node, we break the range down recursively to free blocks
1015 * in subnodes (which means that this code can free an arbitrary
1016 * range whereas the allocation code cannot allocate an arbitrary
1021 hammer_alst_meta_free(hammer_alist_t live, hammer_almeta_t scan,
1022 int32_t freeBlk, int32_t count,
1023 int32_t radix, int skip, int32_t blk
1025 hammer_alist_config_t bl;
1032 * Break the free down into its components. Because it is so easy
1033 * to implement, frees are not limited to power-of-2 sizes.
1035 * Each block in a meta-node bitmap takes two bits.
1037 radix /= HAMMER_ALIST_META_RADIX;
1040 i = (freeBlk - blk) / radix;
1042 mask = 0x00000003 << (i * 2);
1043 pmask = 0x00000001 << (i * 2);
1047 * Our meta node is a leaf node, which means it must recurse
1048 * into another allocator.
1050 while (i < HAMMER_ALIST_META_RADIX && blk < freeBlk + count) {
1053 v = blk + radix - freeBlk;
1057 if (scan->bm_bighint == (int32_t)-1)
1058 panic("hammer_alst_meta_free: freeing unexpected range");
1060 if (freeBlk == blk && count >= radix) {
1062 * All-free case, no need to update sub-tree
1064 scan->bm_bitmap |= mask;
1065 scan->bm_bighint = radix * HAMMER_ALIST_META_RADIX;
1066 /* XXX bighint not being set properly */
1073 bl->bl_radix_free(live->info, freeBlk, v,
1074 radix, blk, &empty);
1076 scan->bm_bitmap |= mask;
1077 scan->bm_bighint = radix * HAMMER_ALIST_META_RADIX;
1078 /* XXX bighint not being set properly */
1080 scan->bm_bitmap |= pmask;
1081 if (scan->bm_bighint < radix / 2)
1082 scan->bm_bighint = radix / 2;
1083 /* XXX bighint not being set properly */
1094 next_skip = (skip - 1) / HAMMER_ALIST_META_RADIX;
1095 i = 1 + i * next_skip;
1097 while (i <= skip && blk < freeBlk + count) {
1100 v = blk + radix - freeBlk;
1104 if (scan->bm_bighint == (int32_t)-1)
1105 panic("hammer_alst_meta_free: freeing unexpected range");
1107 if (freeBlk == blk && count >= radix) {
1109 * All-free case, no need to update sub-tree
1111 scan->bm_bitmap |= mask;
1112 scan->bm_bighint = radix * HAMMER_ALIST_META_RADIX;
1113 /* XXX bighint not being set properly */
1118 if (next_skip == 1 && bl->bl_terminal) {
1119 hammer_alst_leaf_free(&scan[i], freeBlk, v);
1121 hammer_alst_meta_free(live, &scan[i],
1126 if (scan[i].bm_bitmap == (u_int32_t)-1)
1127 scan->bm_bitmap |= mask;
1129 scan->bm_bitmap |= pmask;
1130 if (scan->bm_bighint < scan[i].bm_bighint)
1131 scan->bm_bighint = scan[i].bm_bighint;
1144 * hammer_alst_radix_init()
1146 * Initialize our meta structures and bitmaps and calculate the exact
1147 * number of meta-nodes required to manage 'count' blocks.
1149 * The required space may be truncated due to early termination records.
1152 hammer_alst_radix_init(hammer_almeta_t scan, int32_t radix,
1153 int skip, int32_t count)
1157 int32_t memindex = 1;
1162 * Basic initialization of the almeta for meta or leaf nodes
1165 scan->bm_bighint = 0;
1166 scan->bm_bitmap = 0;
1170 * We are at a leaf, we only eat one meta element.
1176 * Meta node. If allocating the entire object we can special
1177 * case it. However, we need to figure out how much memory
1178 * is required to manage 'count' blocks, so we continue on anyway.
1180 radix /= HAMMER_ALIST_META_RADIX;
1181 next_skip = (skip - 1) / HAMMER_ALIST_META_RADIX;
1185 for (i = 1; i <= skip; i += next_skip) {
1187 * We eat up to this record
1191 if (count >= radix) {
1193 * Allocate the entire object
1195 memindex += hammer_alst_radix_init(
1196 ((scan) ? &scan[i] : NULL),
1202 /* already marked as wholely allocated */
1203 } else if (count > 0) {
1205 * Allocate a partial object
1207 memindex += hammer_alst_radix_init(
1208 ((scan) ? &scan[i] : NULL),
1216 * Mark as partially allocated
1219 scan->bm_bitmap |= pmask;
1222 * Add terminator and break out. The terminal
1223 * eats the meta node at scan[i].
1227 scan[i].bm_bighint = (int32_t)-1;
1228 /* already marked as wholely allocated */
1240 hammer_alst_radix_print(hammer_alist_t live, hammer_almeta_t scan,
1241 int32_t blk, int32_t radix, int skip, int tab)
1248 if (skip == 1 && live->config->bl_terminal) {
1250 "%*.*s(%04x,%d): bitmap %08x big=%d\n",
1259 if (scan->bm_bitmap == 0) {
1261 "%*.*s(%04x,%d) ALL ALLOCATED\n",
1268 if (scan->bm_bitmap == (u_int32_t)-1) {
1270 "%*.*s(%04x,%d) ALL FREE\n",
1279 "%*.*s(%04x,%d): %s (%d) bitmap=%08x big=%d {\n",
1282 (skip == 1 ? "LAYER" : "subtree"),
1288 radix /= HAMMER_ALIST_META_RADIX;
1293 for (i = 0; i < HAMMER_ALIST_META_RADIX; ++i) {
1294 if ((scan->bm_bitmap & mask) == mask) {
1296 "%*.*s(%04x,%d): ALL FREE\n",
1300 } else if ((scan->bm_bitmap & mask) == 0) {
1302 "%*.*s(%04x,%d): ALL ALLOCATED\n",
1307 live->config->bl_radix_print(
1308 live->info, blk, radix, tab);
1314 next_skip = ((u_int)skip / HAMMER_ALIST_META_RADIX);
1316 for (i = 1; i <= skip; i += next_skip) {
1317 if (scan[i].bm_bighint == (int32_t)-1) {
1319 "%*.*s(%04x,%d): Terminator\n",
1326 if ((scan->bm_bitmap & mask) == mask) {
1328 "%*.*s(%04x,%d): ALL FREE\n",
1332 } else if ((scan->bm_bitmap & mask) == 0) {
1334 "%*.*s(%04x,%d): ALL ALLOCATED\n",
1339 hammer_alst_radix_print(
1364 static struct hammer_alist_live **layers; /* initialized by main */
1365 static int32_t layer_radix = -1;
1369 debug_radix_init(void *info, int32_t blk, int32_t radix, int32_t count)
1371 hammer_alist_t layer;
1372 int layer_no = blk / layer_radix;
1374 printf("lower layer: init (%04x,%d) for %d blks\n", blk, radix, count);
1375 KKASSERT(layers[layer_no] == NULL);
1376 layer = layers[layer_no] = hammer_alist_create(count, 1, NULL);
1377 hammer_alist_free(layer, 0, count);
1383 debug_radix_alloc_fwd(void *info, int32_t blk, int32_t radix,
1384 int32_t count, int32_t *fullp)
1386 hammer_alist_t layer = layers[blk / layer_radix];
1388 return(hammer_alist_alloc(layer, count));
1393 debug_radix_alloc_rev(void *info, int32_t blk, int32_t radix,
1394 int32_t count, int32_t *fullp)
1396 hammer_alist_t layer = layers[blk / layer_radix];
1398 blk = hammer_alist_alloc_rev(layer, count);
1399 *fullp = (layer->meta->bm_alist_freeblks == 0);
1401 hammer_alist_destroy(layer, NULL);
1402 layers[blk / layer_radix] = NULL;
1409 debug_radix_free(void *info, int32_t freeBlk, int32_t count,
1410 int32_t radix, int32_t blk, int32_t *emptyp)
1412 int layer_no = blk / layer_radix;
1413 hammer_alist_t layer = layers[layer_no];
1415 if (layer == NULL) {
1417 * XXX layer_radix isn't correct if the total number
1418 * of blocks only partially fills this layer. Don't
1421 layer = hammer_alist_create(layer_radix, 1, NULL);
1422 layers[layer_no] = layer;
1424 hammer_alist_free(layer, freeBlk - blk, count);
1425 *emptyp = (layer->meta->bm_alist_freeblks == layer_radix);
1430 debug_radix_print(void *info, int32_t blk, int32_t radix, int tab)
1432 hammer_alist_t layer = layers[blk / layer_radix];
1434 hammer_alist_print(layer, tab);
1438 main(int ac, char **av)
1442 hammer_alist_t live;
1443 hammer_almeta_t meta = NULL;
1445 for (i = 1; i < ac; ++i) {
1446 const char *ptr = av[i];
1449 size = strtol(ptr, NULL, 0);
1450 else if (layer_radix == -1)
1451 layer_radix = strtol(ptr, NULL, 0);
1457 fprintf(stderr, "Bad option: %s\n", ptr - 2);
1462 if (layer_radix == -1)
1463 layer_radix = 1; /* no second storage layer */
1464 if ((size ^ (size - 1)) != (size << 1) - 1) {
1465 fprintf(stderr, "size must be a power of 2\n");
1468 if ((layer_radix ^ (layer_radix - 1)) != (layer_radix << 1) - 1) {
1469 fprintf(stderr, "the second layer radix must be a power of 2\n");
1473 live = hammer_alist_create(size, layer_radix, NULL);
1474 layers = calloc(size, sizeof(hammer_alist_t));
1476 printf("A-LIST TEST %d blocks, first-layer radix %d, "
1477 "second-layer radix %d\n",
1478 size, live->config->bl_radix / layer_radix, layer_radix);
1480 live->config->bl_radix_init = debug_radix_init;
1481 live->config->bl_radix_alloc_fwd = debug_radix_alloc_fwd;
1482 live->config->bl_radix_alloc_rev = debug_radix_alloc_rev;
1483 live->config->bl_radix_free = debug_radix_free;
1484 live->config->bl_radix_print = debug_radix_print;
1486 hammer_alist_free(live, 0, size);
1495 live->meta->bm_alist_freeblks, size);
1497 if (fgets(buf, sizeof(buf), stdin) == NULL)
1501 hammer_alist_print(live, 0);
1504 if (sscanf(buf + 1, "%d", &count) == 1) {
1505 blk = hammer_alist_alloc(live, count);
1506 kprintf(" R=%04x\n", blk);
1512 if (sscanf(buf + 1, "%d", &count) == 1) {
1513 blk = hammer_alist_alloc_rev(live, count);
1514 kprintf(" R=%04x\n", blk);
1520 if (sscanf(buf + 1, "%x %d", &da, &count) == 2) {
1521 hammer_alist_free(live, da, count);
1531 "r %d -allocate reverse\n"
1545 panic(const char *ctl, ...)
1549 __va_start(va, ctl);
1550 vfprintf(stderr, ctl, va);
1551 fprintf(stderr, "\n");