]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/dtrace/blist.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / bsd / dev / dtrace / blist.c
1 /*
2 * BLIST.C - Bitmap allocator/deallocator, using a radix tree with hinting
3 *
4 * (c)Copyright 1998, Matthew Dillon. Terms for use and redistribution
5 * are covered by the BSD Copyright as found in /usr/src/COPYRIGHT.
6 *
7 * This module implements a general bitmap allocator/deallocator. The
8 * allocator eats around 2 bits per 'block'. The module does not
9 * try to interpret the meaning of a 'block' other then to return
10 * SWAPBLK_NONE on an allocation failure.
11 *
12 * A radix tree is used to maintain the bitmap. Two radix constants are
13 * involved: One for the bitmaps contained in the leaf nodes (typically
14 * 32), and one for the meta nodes (typically 16). Both meta and leaf
15 * nodes have a hint field. This field gives us a hint as to the largest
16 * free contiguous range of blocks under the node. It may contain a
17 * value that is too high, but will never contain a value that is too
18 * low. When the radix tree is searched, allocation failures in subtrees
19 * update the hint.
20 *
21 * The radix tree also implements two collapsed states for meta nodes:
22 * the ALL-ALLOCATED state and the ALL-FREE state. If a meta node is
23 * in either of these two states, all information contained underneath
24 * the node is considered stale. These states are used to optimize
25 * allocation and freeing operations.
26 *
27 * The hinting greatly increases code efficiency for allocations while
28 * the general radix structure optimizes both allocations and frees. The
29 * radix tree should be able to operate well no matter how much
30 * fragmentation there is and no matter how large a bitmap is used.
31 *
32 * Unlike the rlist code, the blist code wires all necessary memory at
33 * creation time. Neither allocations nor frees require interaction with
34 * the memory subsystem. In contrast, the rlist code may allocate memory
35 * on an rlist_free() call. The non-blocking features of the blist code
36 * are used to great advantage in the swap code (vm/nswap_pager.c). The
37 * rlist code uses a little less overall memory then the blist code (but
38 * due to swap interleaving not all that much less), but the blist code
39 * scales much, much better.
40 *
41 * LAYOUT: The radix tree is layed out recursively using a
42 * linear array. Each meta node is immediately followed (layed out
43 * sequentially in memory) by BLIST_META_RADIX lower level nodes. This
44 * is a recursive structure but one that can be easily scanned through
45 * a very simple 'skip' calculation. In order to support large radixes,
46 * portions of the tree may reside outside our memory allocation. We
47 * handle this with an early-termination optimization (when bighint is
48 * set to -1) on the scan. The memory allocation is only large enough
49 * to cover the number of blocks requested at creation time even if it
50 * must be encompassed in larger root-node radix.
51 *
52 * NOTE: the allocator cannot currently allocate more then
53 * BLIST_BMAP_RADIX blocks per call. It will panic with 'allocation too
54 * large' if you try. This is an area that could use improvement. The
55 * radix is large enough that this restriction does not effect the swap
56 * system, though. Currently only the allocation code is effected by
57 * this algorithmic unfeature. The freeing code can handle arbitrary
58 * ranges.
59 *
60 * This code can be compiled stand-alone for debugging.
61 *
62 * $FreeBSD: src/sys/kern/subr_blist.c,v 1.5.2.1 2000/03/17 10:47:29 ps Exp $
63 */
64
65 #if !defined(__APPLE__)
66 #ifdef _KERNEL
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/lock.h>
71 #include <sys/kernel.h>
72 #include <sys/blist.h>
73 #include <sys/malloc.h>
74 #include <vm/vm.h>
75 #include <vm/vm_object.h>
76 #include <vm/vm_kern.h>
77 #include <vm/vm_extern.h>
78 #include <vm/vm_page.h>
79
80 #else
81
82 #ifndef BLIST_NO_DEBUG
83 #define BLIST_DEBUG
84 #endif
85
86 #define SWAPBLK_NONE ((daddr_t)-1)
87
88 #include <sys/types.h>
89 #include <stdio.h>
90 #include <string.h>
91 #include <stdlib.h>
92 #include <stdarg.h>
93
94 #define malloc(a, b, c) malloc(a)
95 #define free(a, b) free(a)
96
97 typedef unsigned int u_daddr_t;
98
99 #include <sys/blist.h>
100
101 void panic(const char *ctl, ...);
102
103 #endif
104 #else /* is MacOS X */
105 #ifdef KERNEL
106 #ifndef _KERNEL
107 #define _KERNEL /* Solaris vs. Darwin */
108 #endif
109 #endif
110
111 typedef unsigned int u_daddr_t;
112
113 #include <sys/param.h>
114 #include <sys/systm.h>
115 #include <sys/lock.h>
116 #include <sys/kernel.h>
117 /* #include <sys/blist.h> */
118 #include "blist.h"
119 #include <sys/malloc.h>
120
121 #define SWAPBLK_NONE ((daddr_t)-1)
122 #define malloc _MALLOC
123 #define free _FREE
124 #define M_SWAP M_TEMP
125
126 #endif /* __APPLE__ */
127
128 /*
129 * static support functions
130 */
131
132 static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count);
133 static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t blk,
134 daddr_t count, daddr_t radix, int skip);
135 static void blst_leaf_free(blmeta_t *scan, daddr_t relblk, int count);
136 static void blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count,
137 daddr_t radix, int skip, daddr_t blk);
138 static void blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix,
139 daddr_t skip, blist_t dest, daddr_t count);
140 static daddr_t blst_radix_init(blmeta_t *scan, daddr_t radix,
141 int skip, daddr_t count);
142 #ifndef _KERNEL
143 static void blst_radix_print(blmeta_t *scan, daddr_t blk,
144 daddr_t radix, int skip, int tab);
145 #endif
146
147 #if !defined(__APPLE__)
148 #ifdef _KERNEL
149 static MALLOC_DEFINE(M_SWAP, "SWAP", "Swap space");
150 #endif
151 #endif /* __APPLE__ */
152
153 /*
154 * blist_create() - create a blist capable of handling up to the specified
155 * number of blocks
156 *
157 * blocks must be greater then 0
158 *
159 * The smallest blist consists of a single leaf node capable of
160 * managing BLIST_BMAP_RADIX blocks.
161 */
162
163 blist_t
164 blist_create(daddr_t blocks)
165 {
166 blist_t bl;
167 int radix;
168 int skip = 0;
169
170 /*
171 * Calculate radix and skip field used for scanning.
172 */
173 radix = BLIST_BMAP_RADIX;
174
175 while (radix < blocks) {
176 radix <<= BLIST_META_RADIX_SHIFT;
177 skip = (skip + 1) << BLIST_META_RADIX_SHIFT;
178 }
179
180 bl = malloc(sizeof(struct blist), M_SWAP, M_WAITOK);
181
182 bzero(bl, sizeof(*bl));
183
184 bl->bl_blocks = blocks;
185 bl->bl_radix = radix;
186 bl->bl_skip = skip;
187 bl->bl_rootblks = 1 +
188 blst_radix_init(NULL, bl->bl_radix, bl->bl_skip, blocks);
189 bl->bl_root = malloc(sizeof(blmeta_t) * bl->bl_rootblks, M_SWAP, M_WAITOK);
190
191 #if defined(BLIST_DEBUG)
192 printf(
193 "BLIST representing %d blocks (%d MB of swap)"
194 ", requiring %dK of ram\n",
195 bl->bl_blocks,
196 bl->bl_blocks * 4 / 1024,
197 (bl->bl_rootblks * sizeof(blmeta_t) + 1023) / 1024
198 );
199 printf("BLIST raw radix tree contains %d records\n", bl->bl_rootblks);
200 #endif
201 blst_radix_init(bl->bl_root, bl->bl_radix, bl->bl_skip, blocks);
202
203 return bl;
204 }
205
206 void
207 blist_destroy(blist_t bl)
208 {
209 free(bl->bl_root, M_SWAP);
210 free(bl, M_SWAP);
211 }
212
213 /*
214 * blist_alloc() - reserve space in the block bitmap. Return the base
215 * of a contiguous region or SWAPBLK_NONE if space could
216 * not be allocated.
217 */
218
219 daddr_t
220 blist_alloc(blist_t bl, daddr_t count)
221 {
222 daddr_t blk = SWAPBLK_NONE;
223
224 if (bl) {
225 if (bl->bl_radix == BLIST_BMAP_RADIX) {
226 blk = blst_leaf_alloc(bl->bl_root, 0, count);
227 } else {
228 blk = blst_meta_alloc(bl->bl_root, 0, count,
229 bl->bl_radix, bl->bl_skip);
230 }
231 if (blk != SWAPBLK_NONE) {
232 bl->bl_free -= count;
233 }
234 }
235 return blk;
236 }
237
238 /*
239 * blist_free() - free up space in the block bitmap. Return the base
240 * of a contiguous region. Panic if an inconsistancy is
241 * found.
242 */
243
244 void
245 blist_free(blist_t bl, daddr_t blkno, daddr_t count)
246 {
247 if (bl) {
248 if (bl->bl_radix == BLIST_BMAP_RADIX) {
249 blst_leaf_free(bl->bl_root, blkno, count);
250 } else {
251 blst_meta_free(bl->bl_root, blkno, count,
252 bl->bl_radix, bl->bl_skip, 0);
253 }
254 bl->bl_free += count;
255 }
256 }
257
258 /*
259 * blist_resize() - resize an existing radix tree to handle the
260 * specified number of blocks. This will reallocate
261 * the tree and transfer the previous bitmap to the new
262 * one. When extending the tree you can specify whether
263 * the new blocks are to left allocated or freed.
264 */
265
266 void
267 blist_resize(blist_t *pbl, daddr_t count, int freenew)
268 {
269 blist_t newbl = blist_create(count);
270 blist_t save = *pbl;
271
272 *pbl = newbl;
273 if (count > save->bl_blocks) {
274 count = save->bl_blocks;
275 }
276 blst_copy(save->bl_root, 0, save->bl_radix, save->bl_skip, newbl, count);
277
278 /*
279 * If resizing upwards, should we free the new space or not?
280 */
281 if (freenew && count < newbl->bl_blocks) {
282 blist_free(newbl, count, newbl->bl_blocks - count);
283 }
284 blist_destroy(save);
285 }
286
287 #ifdef BLIST_DEBUG
288
289 /*
290 * blist_print() - dump radix tree
291 */
292
293 void
294 blist_print(blist_t bl)
295 {
296 printf("BLIST {\n");
297 blst_radix_print(bl->bl_root, 0, bl->bl_radix, bl->bl_skip, 4);
298 printf("}\n");
299 }
300
301 #endif
302
303 /************************************************************************
304 * ALLOCATION SUPPORT FUNCTIONS *
305 ************************************************************************
306 *
307 * These support functions do all the actual work. They may seem
308 * rather longish, but that's because I've commented them up. The
309 * actual code is straight forward.
310 *
311 */
312
313 /*
314 * blist_leaf_alloc() - allocate at a leaf in the radix tree (a bitmap).
315 *
316 * This is the core of the allocator and is optimized for the 1 block
317 * and the BLIST_BMAP_RADIX block allocation cases. Other cases are
318 * somewhat slower. The 1 block allocation case is log2 and extremely
319 * quick.
320 */
321
322 static daddr_t
323 blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count)
324 {
325 u_daddr_t orig = scan->u.bmu_bitmap;
326
327 if (orig == 0) {
328 /*
329 * Optimize bitmap all-allocated case. Also, count = 1
330 * case assumes at least 1 bit is free in the bitmap, so
331 * we have to take care of this case here.
332 */
333 scan->bm_bighint = 0;
334 return SWAPBLK_NONE;
335 }
336 if (count == 1) {
337 /*
338 * Optimized code to allocate one bit out of the bitmap
339 */
340 u_daddr_t mask;
341 int j = BLIST_BMAP_RADIX / 2;
342 int r = 0;
343
344 mask = (u_daddr_t)-1 >> (BLIST_BMAP_RADIX / 2);
345
346 while (j) {
347 if ((orig & mask) == 0) {
348 r += j;
349 orig >>= j;
350 }
351 j >>= 1;
352 mask >>= j;
353 }
354 scan->u.bmu_bitmap &= ~(1 << r);
355 return blk + r;
356 }
357 #if !defined(__APPLE__)
358 if (count <= BLIST_BMAP_RADIX) {
359 #else
360 if (count <= (int)BLIST_BMAP_RADIX) {
361 #endif /* __APPLE__ */
362 /*
363 * non-optimized code to allocate N bits out of the bitmap.
364 * The more bits, the faster the code runs. It will run
365 * the slowest allocating 2 bits, but since there aren't any
366 * memory ops in the core loop (or shouldn't be, anyway),
367 * you probably won't notice the difference.
368 */
369 int j;
370 int n = BLIST_BMAP_RADIX - count;
371 u_daddr_t mask;
372
373 mask = (u_daddr_t)-1 >> n;
374
375 for (j = 0; j <= n; ++j) {
376 if ((orig & mask) == mask) {
377 scan->u.bmu_bitmap &= ~mask;
378 return blk + j;
379 }
380 mask = (mask << 1);
381 }
382 }
383 /*
384 * We couldn't allocate count in this subtree, update bighint.
385 */
386 scan->bm_bighint = count - 1;
387 return SWAPBLK_NONE;
388 }
389
390 /*
391 * blist_meta_alloc() - allocate at a meta in the radix tree.
392 *
393 * Attempt to allocate at a meta node. If we can't, we update
394 * bighint and return a failure. Updating bighint optimize future
395 * calls that hit this node. We have to check for our collapse cases
396 * and we have a few optimizations strewn in as well.
397 */
398
399 static daddr_t
400 blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, daddr_t radix,
401 int skip)
402 {
403 int i;
404 int next_skip = (skip >> BLIST_META_RADIX_SHIFT);
405
406 if (scan->u.bmu_avail == 0) {
407 /*
408 * ALL-ALLOCATED special case
409 */
410 scan->bm_bighint = count;
411 return SWAPBLK_NONE;
412 }
413
414 if (scan->u.bmu_avail == radix) {
415 radix >>= BLIST_META_RADIX_SHIFT;
416
417 /*
418 * ALL-FREE special case, initialize uninitialize
419 * sublevel.
420 */
421 for (i = 1; i <= skip; i += next_skip) {
422 if (scan[i].bm_bighint == (daddr_t)-1) {
423 break;
424 }
425 if (next_skip == 1) {
426 scan[i].u.bmu_bitmap = (u_daddr_t)-1;
427 scan[i].bm_bighint = BLIST_BMAP_RADIX;
428 } else {
429 scan[i].bm_bighint = radix;
430 scan[i].u.bmu_avail = radix;
431 }
432 }
433 } else {
434 radix >>= BLIST_META_RADIX_SHIFT;
435 }
436
437 for (i = 1; i <= skip; i += next_skip) {
438 if (count <= scan[i].bm_bighint) {
439 /*
440 * count fits in object
441 */
442 daddr_t r;
443 if (next_skip == 1) {
444 r = blst_leaf_alloc(&scan[i], blk, count);
445 } else {
446 r = blst_meta_alloc(&scan[i], blk, count,
447 radix, next_skip - 1);
448 }
449 if (r != SWAPBLK_NONE) {
450 scan->u.bmu_avail -= count;
451 if (scan->bm_bighint > scan->u.bmu_avail) {
452 scan->bm_bighint = scan->u.bmu_avail;
453 }
454 return r;
455 }
456 } else if (scan[i].bm_bighint == (daddr_t)-1) {
457 /*
458 * Terminator
459 */
460 break;
461 } else if (count > radix) {
462 /*
463 * count does not fit in object even if it were
464 * complete free.
465 */
466 panic("blist_meta_alloc: allocation too large");
467 }
468 blk += radix;
469 }
470
471 /*
472 * We couldn't allocate count in this subtree, update bighint.
473 */
474 if (scan->bm_bighint >= count) {
475 scan->bm_bighint = count - 1;
476 }
477 return SWAPBLK_NONE;
478 }
479
480 /*
481 * BLST_LEAF_FREE() - free allocated block from leaf bitmap
482 *
483 */
484
485 static void
486 blst_leaf_free(blmeta_t *scan, daddr_t blk, int count)
487 {
488 /*
489 * free some data in this bitmap
490 *
491 * e.g.
492 * 0000111111111110000
493 * \_________/\__/
494 * v n
495 */
496 int n = blk & (BLIST_BMAP_RADIX - 1);
497 u_daddr_t mask;
498
499 mask = ((u_daddr_t)-1 << n) &
500 ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - count - n));
501
502 if (scan->u.bmu_bitmap & mask) {
503 panic("blst_radix_free: freeing free block");
504 }
505 scan->u.bmu_bitmap |= mask;
506
507 /*
508 * We could probably do a better job here. We are required to make
509 * bighint at least as large as the biggest contiguous block of
510 * data. If we just shoehorn it, a little extra overhead will
511 * be incured on the next allocation (but only that one typically).
512 */
513 scan->bm_bighint = BLIST_BMAP_RADIX;
514 }
515
516 /*
517 * BLST_META_FREE() - free allocated blocks from radix tree meta info
518 *
519 * This support routine frees a range of blocks from the bitmap.
520 * The range must be entirely enclosed by this radix node. If a
521 * meta node, we break the range down recursively to free blocks
522 * in subnodes (which means that this code can free an arbitrary
523 * range whereas the allocation code cannot allocate an arbitrary
524 * range).
525 */
526
527 static void
528 blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, daddr_t radix,
529 int skip, daddr_t blk)
530 {
531 int i;
532 int next_skip = (skip >> BLIST_META_RADIX_SHIFT);
533
534 #if 0
535 printf("FREE (%x,%d) FROM (%x,%d)\n",
536 freeBlk, count,
537 blk, radix
538 );
539 #endif
540
541 if (scan->u.bmu_avail == 0) {
542 /*
543 * ALL-ALLOCATED special case, with possible
544 * shortcut to ALL-FREE special case.
545 */
546 scan->u.bmu_avail = count;
547 scan->bm_bighint = count;
548
549 if (count != radix) {
550 for (i = 1; i <= skip; i += next_skip) {
551 if (scan[i].bm_bighint == (daddr_t)-1) {
552 break;
553 }
554 scan[i].bm_bighint = 0;
555 if (next_skip == 1) {
556 scan[i].u.bmu_bitmap = 0;
557 } else {
558 scan[i].u.bmu_avail = 0;
559 }
560 }
561 /* fall through */
562 }
563 } else {
564 scan->u.bmu_avail += count;
565 /* scan->bm_bighint = radix; */
566 }
567
568 /*
569 * ALL-FREE special case.
570 */
571
572 if (scan->u.bmu_avail == radix) {
573 return;
574 }
575 if (scan->u.bmu_avail > radix) {
576 panic("blst_meta_free: freeing already free blocks (%d) %d/%d", count, scan->u.bmu_avail, radix);
577 }
578
579 /*
580 * Break the free down into its components
581 */
582
583 radix >>= BLIST_META_RADIX_SHIFT;
584
585 i = (freeBlk - blk) / radix;
586 blk += i * radix;
587 i = i * next_skip + 1;
588
589 while (i <= skip && blk < freeBlk + count) {
590 daddr_t v;
591
592 v = blk + radix - freeBlk;
593 if (v > count) {
594 v = count;
595 }
596
597 if (scan->bm_bighint == (daddr_t)-1) {
598 panic("blst_meta_free: freeing unexpected range");
599 }
600
601 if (next_skip == 1) {
602 blst_leaf_free(&scan[i], freeBlk, v);
603 } else {
604 blst_meta_free(&scan[i], freeBlk, v, radix,
605 next_skip - 1, blk);
606 }
607 if (scan->bm_bighint < scan[i].bm_bighint) {
608 scan->bm_bighint = scan[i].bm_bighint;
609 }
610 count -= v;
611 freeBlk += v;
612 blk += radix;
613 i += next_skip;
614 }
615 }
616
617 /*
618 * BLIST_RADIX_COPY() - copy one radix tree to another
619 *
620 * Locates free space in the source tree and frees it in the destination
621 * tree. The space may not already be free in the destination.
622 */
623
624 static void
625 blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix,
626 daddr_t skip, blist_t dest, daddr_t count)
627 {
628 int next_skip;
629 int i;
630
631 /*
632 * Leaf node
633 */
634
635 if (radix == BLIST_BMAP_RADIX) {
636 u_daddr_t v = scan->u.bmu_bitmap;
637
638 if (v == (u_daddr_t)-1) {
639 blist_free(dest, blk, count);
640 } else if (v != 0) {
641 #if !defined(__APPLE__)
642 int i;
643
644 for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) {
645 if (v & (1 << i)) {
646 blist_free(dest, blk + i, 1);
647 }
648 }
649 #else
650 int j; /* Avoid shadow warnings */
651
652 for (j = 0; j < (int)BLIST_BMAP_RADIX && j < count; ++j) {
653 if (v & (1 << j)) {
654 blist_free(dest, blk + j, 1);
655 }
656 }
657 #endif /* __APPLE__ */
658 }
659 return;
660 }
661
662 /*
663 * Meta node
664 */
665
666 /*
667 * Source all allocated, leave dest allocated
668 */
669 if (scan->u.bmu_avail == 0) {
670 return;
671 }
672 if (scan->u.bmu_avail == radix) {
673 /*
674 * Source all free, free entire dest
675 */
676 if (count < radix) {
677 blist_free(dest, blk, count);
678 } else {
679 blist_free(dest, blk, radix);
680 }
681 return;
682 }
683
684 radix >>= BLIST_META_RADIX_SHIFT;
685 next_skip = (skip >> BLIST_META_RADIX_SHIFT);
686
687 for (i = 1; count && i <= skip; i += next_skip) {
688 if (scan[i].bm_bighint == (daddr_t)-1) {
689 break;
690 }
691
692 if (count >= radix) {
693 blst_copy(
694 &scan[i],
695 blk,
696 radix,
697 next_skip - 1,
698 dest,
699 radix
700 );
701 count -= radix;
702 } else {
703 if (count) {
704 blst_copy(
705 &scan[i],
706 blk,
707 radix,
708 next_skip - 1,
709 dest,
710 count
711 );
712 }
713 count = 0;
714 }
715 blk += radix;
716 }
717 }
718
719 /*
720 * BLST_RADIX_INIT() - initialize radix tree
721 *
722 * Initialize our meta structures and bitmaps and calculate the exact
723 * amount of space required to manage 'count' blocks - this space may
724 * be considerably less then the calculated radix due to the large
725 * RADIX values we use.
726 */
727
728 static daddr_t
729 blst_radix_init(blmeta_t *scan, daddr_t radix, int skip, daddr_t count)
730 {
731 int i;
732 int next_skip;
733 daddr_t memindex = 0;
734
735 /*
736 * Leaf node
737 */
738
739 if (radix == BLIST_BMAP_RADIX) {
740 if (scan) {
741 scan->bm_bighint = 0;
742 scan->u.bmu_bitmap = 0;
743 }
744 return memindex;
745 }
746
747 /*
748 * Meta node. If allocating the entire object we can special
749 * case it. However, we need to figure out how much memory
750 * is required to manage 'count' blocks, so we continue on anyway.
751 */
752
753 if (scan) {
754 scan->bm_bighint = 0;
755 scan->u.bmu_avail = 0;
756 }
757
758 radix >>= BLIST_META_RADIX_SHIFT;
759 next_skip = (skip >> BLIST_META_RADIX_SHIFT);
760
761 for (i = 1; i <= skip; i += next_skip) {
762 if (count >= radix) {
763 /*
764 * Allocate the entire object
765 */
766 memindex = i + blst_radix_init(
767 ((scan) ? &scan[i] : NULL),
768 radix,
769 next_skip - 1,
770 radix
771 );
772 count -= radix;
773 } else if (count > 0) {
774 /*
775 * Allocate a partial object
776 */
777 memindex = i + blst_radix_init(
778 ((scan) ? &scan[i] : NULL),
779 radix,
780 next_skip - 1,
781 count
782 );
783 count = 0;
784 } else {
785 /*
786 * Add terminator and break out
787 */
788 if (scan) {
789 scan[i].bm_bighint = (daddr_t)-1;
790 }
791 break;
792 }
793 }
794 if (memindex < i) {
795 memindex = i;
796 }
797 return memindex;
798 }
799
800 #ifdef BLIST_DEBUG
801
802 static void
803 blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int skip, int tab)
804 {
805 int i;
806 int next_skip;
807 int lastState = 0;
808
809 if (radix == BLIST_BMAP_RADIX) {
810 printf(
811 "%*.*s(%04x,%d): bitmap %08x big=%d\n",
812 tab, tab, "",
813 blk, radix,
814 scan->u.bmu_bitmap,
815 scan->bm_bighint
816 );
817 return;
818 }
819
820 if (scan->u.bmu_avail == 0) {
821 printf(
822 "%*.*s(%04x,%d) ALL ALLOCATED\n",
823 tab, tab, "",
824 blk,
825 radix
826 );
827 return;
828 }
829 if (scan->u.bmu_avail == radix) {
830 printf(
831 "%*.*s(%04x,%d) ALL FREE\n",
832 tab, tab, "",
833 blk,
834 radix
835 );
836 return;
837 }
838
839 printf(
840 "%*.*s(%04x,%d): subtree (%d/%d) big=%d {\n",
841 tab, tab, "",
842 blk, radix,
843 scan->u.bmu_avail,
844 radix,
845 scan->bm_bighint
846 );
847
848 radix >>= BLIST_META_RADIX_SHIFT;
849 next_skip = (skip >> BLIST_META_RADIX_SHIFT);
850 tab += 4;
851
852 for (i = 1; i <= skip; i += next_skip) {
853 if (scan[i].bm_bighint == (daddr_t)-1) {
854 printf(
855 "%*.*s(%04x,%d): Terminator\n",
856 tab, tab, "",
857 blk, radix
858 );
859 lastState = 0;
860 break;
861 }
862 blst_radix_print(
863 &scan[i],
864 blk,
865 radix,
866 next_skip - 1,
867 tab
868 );
869 blk += radix;
870 }
871 tab -= 4;
872
873 printf(
874 "%*.*s}\n",
875 tab, tab, ""
876 );
877 }
878
879 #endif
880
881 #ifdef BLIST_DEBUG
882
883 int
884 main(int ac, char **av)
885 {
886 int size = 1024;
887 int i;
888 blist_t bl;
889
890 for (i = 1; i < ac; ++i) {
891 const char *ptr = av[i];
892 if (*ptr != '-') {
893 size = strtol(ptr, NULL, 0);
894 continue;
895 }
896 ptr += 2;
897 fprintf(stderr, "Bad option: %s\n", ptr - 2);
898 exit(1);
899 }
900 bl = blist_create(size);
901 blist_free(bl, 0, size);
902
903 for (;;) {
904 char buf[1024];
905 daddr_t da = 0;
906 daddr_t count = 0;
907
908
909 printf("%d/%d/%d> ", bl->bl_free, size, bl->bl_radix);
910 fflush(stdout);
911 if (fgets(buf, sizeof(buf), stdin) == NULL) {
912 break;
913 }
914 switch (buf[0]) {
915 case 'r':
916 if (sscanf(buf + 1, "%d", &count) == 1) {
917 blist_resize(&bl, count, 1);
918 } else {
919 printf("?\n");
920 }
921 case 'p':
922 blist_print(bl);
923 break;
924 case 'a':
925 if (sscanf(buf + 1, "%d", &count) == 1) {
926 daddr_t blk = blist_alloc(bl, count);
927 printf(" R=%04x\n", blk);
928 } else {
929 printf("?\n");
930 }
931 break;
932 case 'f':
933 if (sscanf(buf + 1, "%x %d", &da, &count) == 2) {
934 blist_free(bl, da, count);
935 } else {
936 printf("?\n");
937 }
938 break;
939 case '?':
940 case 'h':
941 puts(
942 "p -print\n"
943 "a %d -allocate\n"
944 "f %x %d -free\n"
945 "r %d -resize\n"
946 "h/? -help"
947 );
948 break;
949 default:
950 printf("?\n");
951 break;
952 }
953 }
954 return 0;
955 }
956
957 void
958 panic(const char *ctl, ...)
959 {
960 va_list va;
961
962 va_start(va, ctl);
963 vfprintf(stderr, ctl, va);
964 fprintf(stderr, "\n");
965 va_end(va);
966 exit(1);
967 }
968
969 #endif