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