diff --git a/utils/src/buddy.c b/utils/src/buddy.c new file mode 100644 index 00000000..1a0582d5 --- /dev/null +++ b/utils/src/buddy.c @@ -0,0 +1,61 @@ +#include +#include +#include + +#include "sparse.h" +#include "util.h" +#include "buddy.h" + +/* + * Figure out how many blocks the radix will need by starting with leaf + * blocks and dividing by the slot fanout until we have one block. cow + * updates require two copies of every block. + */ +static u64 calc_blocks(struct buddy_info *binf, u64 bits) +{ + u64 blocks = DIV_ROUND_UP(bits, SCOUTFS_BUDDY_ORDER0_BITS); + u64 tot = 0; + int level = 0; + int i; + + for (i = 0; i < SCOUTFS_BUDDY_MAX_HEIGHT; i++) + binf->blknos[i] = SCOUTFS_BUDDY_BLKNO; + + for (;;) { + for (i = level - 1; i >= 0; i--) + binf->blknos[i] += (blocks * 2); + tot += (blocks * 2); + + level++; + if (blocks == 1) + break; + blocks = DIV_ROUND_UP(blocks, SCOUTFS_BUDDY_SLOTS); + } + + binf->height = level; + + return tot; +} + +/* + * Figure out how many buddy blocks we'll need to allocate the rest of + * the blocks in the device. The first time through we find the size of + * the radix needed to describe the whole device, but that doesn't take + * the buddy block overhead into account. We iterate getting a more + * precise estimate each time. This only takes a few rounds to + * stabilize. + */ +void buddy_init(struct buddy_info *binf, u64 total_blocks) +{ + u64 blocks = SCOUTFS_BUDDY_BLKNO; + u64 was; + + while(1) { + was = blocks; + blocks = calc_blocks(binf, total_blocks - blocks); + if (blocks == was) + break; + } + + binf->buddy_blocks = blocks; +} diff --git a/utils/src/buddy.h b/utils/src/buddy.h new file mode 100644 index 00000000..6e70230d --- /dev/null +++ b/utils/src/buddy.h @@ -0,0 +1,16 @@ +#ifndef _BUDDY_H_ +#define _BUDDY_H_ + +#include "format.h" + +struct buddy_info { + u8 height; + u64 buddy_blocks; + + /* starting blkno in each level, including mirrors */ + u64 blknos[SCOUTFS_BUDDY_MAX_HEIGHT]; +}; + +void buddy_init(struct buddy_info *binf, u64 total_blocks); + +#endif diff --git a/utils/src/format.h b/utils/src/format.h index 58fea85f..fe83a346 100644 --- a/utils/src/format.h +++ b/utils/src/format.h @@ -19,8 +19,7 @@ */ #define SCOUTFS_SUPER_BLKNO ((64 * 1024) >> SCOUTFS_BLOCK_SHIFT) #define SCOUTFS_SUPER_NR 2 -#define SCOUTFS_BUDDY_BM_BLKNO (SCOUTFS_SUPER_BLKNO + SCOUTFS_SUPER_NR) -#define SCOUTFS_BUDDY_BM_NR 2 +#define SCOUTFS_BUDDY_BLKNO (SCOUTFS_SUPER_BLKNO + SCOUTFS_SUPER_NR) #define SCOUTFS_MAX_TRANS_BLOCKS (128 * 1024 * 1024 / SCOUTFS_BLOCK_SIZE) @@ -48,42 +47,49 @@ struct scoutfs_block_ref { __le64 seq; } __packed; -struct scoutfs_bitmap_block { - struct scoutfs_block_header hdr; - __le64 bits[0]; -} __packed; - /* - * Track allocations from BLOCK_SIZE to (BLOCK_SIZE << ..._ORDERS). + * If the block was full of bits the largest possible order would be + * the block size shift + 3 (BITS_PER_BYTE). But the header uses + * up some space and then the buddy bits mean two bits per block. + * Then +1 for this being the number, not the greatest order. */ -#define SCOUTFS_BUDDY_ORDERS 8 +#define SCOUTFS_BUDDY_ORDERS (SCOUTFS_BLOCK_SHIFT + 3 - 2 + 1) struct scoutfs_buddy_block { struct scoutfs_block_header hdr; - __le32 order_counts[SCOUTFS_BUDDY_ORDERS]; - __le64 bits[0]; + __le16 first_set[SCOUTFS_BUDDY_ORDERS]; + __u8 level; + __u8 __pad[3]; /* naturally align bits */ + union { + struct scoutfs_buddy_slot { + __le64 seq; + __le16 free_orders; + /* XXX seems like we could hide a bit somewhere */ + __u8 blkno_off; + } __packed slots[0]; + __le64 bits[0]; + } __packed; } __packed; /* - * If we had log2(raw bits) orders we'd fully use all of the raw bits in - * the block. We're close enough that the amount of space wasted at the - * end (~1/256th of the block, ~64 bytes) isn't worth worrying about. + * Each buddy leaf block references order 0 blocks with half of its + * bitmap. The other half of the bits are used for the higher order + * bits. */ #define SCOUTFS_BUDDY_ORDER0_BITS \ (((SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_buddy_block)) * 8) / 2) -struct scoutfs_buddy_indirect { - struct scoutfs_block_header hdr; - __le64 order_totals[SCOUTFS_BUDDY_ORDERS]; - struct scoutfs_buddy_slot { - __u8 free_orders; - struct scoutfs_block_ref ref; - } slots[0]; +#define SCOUTFS_BUDDY_SLOTS \ + ((SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_buddy_block)) / \ + sizeof(struct scoutfs_buddy_slot)) + +struct scoutfs_buddy_root { + struct scoutfs_buddy_slot slot; + __u8 height; } __packed; -#define SCOUTFS_BUDDY_SLOTS \ - ((SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_buddy_indirect)) / \ - sizeof(struct scoutfs_buddy_slot)) +/* ((SCOUTFS_BUDDY_SLOTS^5) * SCOUTFS_BUDDY_ORDER0_BITS) > 2^52 */ +#define SCOUTFS_BUDDY_MAX_HEIGHT 6 /* * We should be able to make the offset smaller if neither dirents nor @@ -180,10 +186,10 @@ struct scoutfs_super_block { __u8 uuid[SCOUTFS_UUID_BYTES]; __le64 next_ino; __le64 total_blocks; - __le32 buddy_blocks; + __le64 free_blocks; + __le64 buddy_blocks; + struct scoutfs_buddy_root buddy_root; struct scoutfs_btree_root btree_root; - struct scoutfs_block_ref buddy_ind_ref; - struct scoutfs_block_ref buddy_bm_ref; } __packed; #define SCOUTFS_ROOT_INO 1 diff --git a/utils/src/mkfs.c b/utils/src/mkfs.c index 920361be..ac49cb74 100644 --- a/utils/src/mkfs.c +++ b/utils/src/mkfs.c @@ -18,6 +18,7 @@ #include "rand.h" #include "dev.h" #include "bitops.h" +#include "buddy.h" /* * Update the block's header and write it out. @@ -42,24 +43,14 @@ static int write_block(int fd, u64 blkno, struct scoutfs_super_block *super, return 0; } -/* - * Calculate the number of buddy blocks that are needed to manage - * allocation of a device with the given number of total blocks. - * - * We need a little bit of overhead to write each transaction's dirty - * buddy blocks to free space. We chose 16MB for now which is wild - * overkill and should be dependent on the max transaction size. - */ -static u32 calc_buddy_blocks(u64 total_blocks) +static u64 first_blkno(struct scoutfs_super_block *super) { - return DIV_ROUND_UP(total_blocks, SCOUTFS_BUDDY_ORDER0_BITS) + - ((16 * 1024 * 1024) / SCOUTFS_BLOCK_SIZE); + return SCOUTFS_BUDDY_BLKNO + le64_to_cpu(super->buddy_blocks); } -static u32 first_blkno(struct scoutfs_super_block *super) +static u64 last_blkno(struct scoutfs_super_block *super) { - return SCOUTFS_BUDDY_BM_BLKNO + SCOUTFS_BUDDY_BM_NR + - le32_to_cpu(super->buddy_blocks); + return le64_to_cpu(super->total_blocks) - 1; } /* the starting bit offset in the block bitmap of an order's bitmap */ @@ -78,6 +69,76 @@ static int order_nr(int order, int nr) return order_off(order) + nr; } +static void set_order_nr(struct scoutfs_buddy_block *bud, int order, u16 nr) +{ + u16 first = le16_to_cpu(bud->first_set[order]); + + if (nr <= first) + bud->first_set[order] = cpu_to_le16(nr); +} + +static void clear_order_nr(struct scoutfs_buddy_block *bud, int order, u16 nr) +{ + u16 first = le16_to_cpu(bud->first_set[order]); + int size; + int i; + + if (nr != first) + return; + + if (bud->level) { + for (i = nr + 1; i < SCOUTFS_BUDDY_SLOTS; i++) { + if (le16_to_cpu(bud->slots[i].free_orders) & + (1 << order)) + break; + } + if (i == SCOUTFS_BUDDY_SLOTS) + i = U16_MAX; + + } else { + size = order_off(order + 1); + i = find_next_bit_le(bud->bits, size, + order_nr(order, first) + 1); + if (i >= size) + i = U16_MAX; + else + i -= order_off(order); + } + + bud->first_set[order] = cpu_to_le16(i); +} + +#define for_each_changed_bit(nr, bit, old, new, tmp) \ + for (tmp = old ^ new; \ + tmp && (nr = ffs(tmp) - 1, bit = 1 << nr, 1); \ + tmp ^= bit) + +/* + * Set a slot's free_orders value and update first_set for each order + * that it changes. Returns true of the slot's free_orders was changed. + */ +static int set_slot_free_orders(struct scoutfs_buddy_block *bud, u16 sl, + u16 free_orders) +{ + u16 old = le16_to_cpu(bud->slots[sl].free_orders); + int order; + int tmp; + int bit; + + if (old == free_orders) + return 0; + + for_each_changed_bit(order, bit, old, free_orders, tmp) { + if (old & bit) + clear_order_nr(bud, order, sl); + else + set_order_nr(bud, order, sl); + } + + bud->slots[sl].free_orders = cpu_to_le16(free_orders); + return 1; +} + static int test_buddy_bit(struct scoutfs_buddy_block *bud, int order, int nr) { return test_bit_le(order_nr(order, nr), bud->bits); @@ -86,13 +147,13 @@ static int test_buddy_bit(struct scoutfs_buddy_block *bud, int order, int nr) static void set_buddy_bit(struct scoutfs_buddy_block *bud, int order, int nr) { if (!test_and_set_bit_le(order_nr(order, nr), bud->bits)) - le32_add_cpu(&bud->order_counts[order], 1); + set_order_nr(bud, order, nr); } static void clear_buddy_bit(struct scoutfs_buddy_block *bud, int order, int nr) { if (test_and_clear_bit_le(order_nr(order, nr), bud->bits)) - le32_add_cpu(&bud->order_counts[order], -1); + clear_order_nr(bud, order, nr); } /* merge lower orders buddies as we free up to the highest */ @@ -100,7 +161,7 @@ static void free_order_bit(struct scoutfs_buddy_block *bud, int order, int nr) { int i; - for (i = order; i < SCOUTFS_BUDDY_ORDERS - 1; i++) { + for (i = order; i < SCOUTFS_BUDDY_ORDERS - 2; i++) { if (!test_buddy_bit(bud, i, nr ^ 1)) break; @@ -112,40 +173,120 @@ static void free_order_bit(struct scoutfs_buddy_block *bud, int order, int nr) set_buddy_bit(bud, i, nr); } -static u8 calc_free_orders(struct scoutfs_buddy_block *bud) +static u16 calc_free_orders(struct scoutfs_buddy_block *bud) { - u8 free = 0; + u16 free = 0; int i; for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) - free |= (!!bud->order_counts[i]) << i; + if (le16_to_cpu(bud->first_set[i]) != U16_MAX) + free |= 1 << i; return free; } -/* - * Figure out the free orders for the slot that starts with the given - * blkno. The bits in the buddy bitmap are relative to the starting - * blkno and are aligned so the bits in the count of blocks in the slot - * reflect the presence of free orders in that slot. - */ -static u8 slot_free_orders(u64 sl_blkno, u64 total_blocks) +static void init_buddy_block(struct scoutfs_buddy_block *bud, int level) { - u64 count; - u64 mask; - u8 free; + int i; - if (sl_blkno >= total_blocks) - return 0; + memset(bud, 0, SCOUTFS_BLOCK_SIZE); + for (i = 0; i < array_size(bud->first_set); i++) + bud->first_set[i] = cpu_to_le16(U16_MAX); + bud->level = level; +} - count = min(total_blocks - sl_blkno, SCOUTFS_BUDDY_ORDER0_BITS); +/* + * Write either the left-most or right-most buddy bitmap leaf in the + * allocator and then ascend writing parent blocks to the root. + * + * If we're writing the left leaf then blk is the first free blk. If + * we're writing the right leaf then blk is the last usable blk. + * + * If we're writing the left leaf then we don't actually write the root + * block. We record the free_orders for the first child block from the + * root block. When we write the right leaf we'll ascend into the root + * block and initialize the free_order of the first slot for the path to + * the left leaf. + * + * We initialize free_orders in all the unused slots so that the kernel + * can try to descend in to them when searching by size and will + * initialize new full blocks blocks. + */ +static int write_buddy_blocks(int fd, struct scoutfs_super_block *super, + struct buddy_info *binf, + struct scoutfs_buddy_block *bud, u64 blk, + int left, u16 *free_orders) +{ + u64 blkno; + int level; + int first; + int last; + int ret; + u16 free; + u16 full; + int sl; + int i; - mask = (1 << SCOUTFS_BUDDY_ORDERS) - 1; - free = count & mask; - if (count > mask) - free |= (mask + 1) >> 1; + if (left) { + first = blk; + last = SCOUTFS_BUDDY_ORDER0_BITS - 1; + } else { + first = 0; + last = min(blk % SCOUTFS_BUDDY_ORDER0_BITS, + SCOUTFS_BUDDY_ORDER0_BITS); + } - return free; + /* write the leaf block */ + level = 0; + init_buddy_block(bud, level); + for (i = first; i <= last; i++) + free_order_bit(bud, 0, i); + + blk = blk / SCOUTFS_BUDDY_ORDER0_BITS; + blkno = binf->blknos[level] + (blk * 2); + + ret = write_block(fd, blkno, super, &bud->hdr); + if (ret) + return ret; + + free = calc_free_orders(bud); + full = SCOUTFS_BUDDY_ORDER0_BITS; + + /* write parents, stopping before root if left */ + while (++level < (left ? binf->height - 1 : binf->height)) { + + sl = blk % SCOUTFS_BUDDY_SLOTS; + blk = blk / SCOUTFS_BUDDY_SLOTS; + blkno = binf->blknos[level] + (blk * 2); + + init_buddy_block(bud, level); + + /* set full until right spine, 0th in root from left */ + for (i = 0; i < sl; i++) + set_slot_free_orders(bud, i, full); + + if (!left && level == (binf->height - 1)) { + set_slot_free_orders(bud, 0, *free_orders); + bud->slots[0].seq = super->hdr.seq; + } + + set_slot_free_orders(bud, sl, free); + bud->slots[sl].seq = super->hdr.seq; + + /* init full slots in full parents down the left spine */ + for (i = sl; left && i < SCOUTFS_BUDDY_SLOTS; i++) + set_slot_free_orders(bud, i, full); + + ret = write_block(fd, blkno, super, &bud->hdr); + if (ret) + return ret; + + free = calc_free_orders(bud); + } + + *free_orders = free; + + return 0; } static int write_new_fs(char *path, int fd) @@ -154,27 +295,25 @@ static int write_new_fs(char *path, int fd) struct scoutfs_inode *inode; struct scoutfs_btree_block *bt; struct scoutfs_btree_item *item; - struct scoutfs_buddy_block *bud; - struct scoutfs_buddy_indirect *ind; - struct scoutfs_bitmap_block *bm; struct scoutfs_key root_key; + struct buddy_info binf; struct timeval tv; char uuid_str[37]; unsigned int i; + u64 limit; u64 size; u64 blkno; + u64 count; u64 total_blocks; - u64 buddy_blocks; - u64 sl_blkno; + u16 free_orders; void *buf; int ret; gettimeofday(&tv, NULL); buf = malloc(SCOUTFS_BLOCK_SIZE); - bud = malloc(SCOUTFS_BLOCK_SIZE); super = malloc(SCOUTFS_BLOCK_SIZE); - if (!buf || !bud || !super) { + if (!buf || !super) { ret = -errno; fprintf(stderr, "failed to allocate a block: %s (%d)\n", strerror(errno), errno); @@ -190,12 +329,8 @@ static int write_new_fs(char *path, int fd) /* the block limit is totally arbitrary */ total_blocks = size / SCOUTFS_BLOCK_SIZE; - if (total_blocks < 32) { - fprintf(stderr, "%llu byte device only has room for %llu %u byte blocks, needs at least 32 blocks\n", - size, total_blocks, SCOUTFS_BLOCK_SIZE); - goto out; - } - buddy_blocks = calc_buddy_blocks(total_blocks); + + buddy_init(&binf, total_blocks); root_key.inode = cpu_to_le64(SCOUTFS_ROOT_INO); root_key.type = SCOUTFS_INODE_KEY; @@ -209,7 +344,16 @@ static int write_new_fs(char *path, int fd) uuid_generate(super->uuid); super->next_ino = cpu_to_le64(SCOUTFS_ROOT_INO + 1); super->total_blocks = cpu_to_le64(total_blocks); - super->buddy_blocks = cpu_to_le32(buddy_blocks); + super->buddy_blocks = cpu_to_le64(binf.buddy_blocks); + + /* require space for two leaf blocks for writing left/right paths */ + count = last_blkno(super) - first_blkno(super) + 1; + limit = (SCOUTFS_BUDDY_ORDER0_BITS * 2); + if (count < limit) { + fprintf(stderr, "%llu byte device only has room for %llu %u byte fs blocks, needs at least %llu fs blocks\n", + size, count, SCOUTFS_BLOCK_SIZE, limit); + goto out; + } blkno = first_blkno(super); @@ -240,68 +384,33 @@ static int write_new_fs(char *path, int fd) ret = write_block(fd, blkno, super, &bt->hdr); if (ret) goto out; + /* blkno is now first free */ + blkno++; /* the super references the btree block */ super->btree_root.height = 1; super->btree_root.ref.blkno = bt->hdr.blkno; super->btree_root.ref.seq = bt->hdr.seq; - /* free all the blocks in the first buddy block after btree block */ - memset(bud, 0, SCOUTFS_BLOCK_SIZE); - for (i = 1; i < min(total_blocks - first_blkno(super), - SCOUTFS_BUDDY_ORDER0_BITS); i++) - free_order_bit(bud, 0, i); + /* free_blocks reflects the fs blocks, not buddy blocks */ + super->free_blocks = cpu_to_le64(total_blocks - blkno); - blkno = SCOUTFS_BUDDY_BM_BLKNO + SCOUTFS_BUDDY_BM_NR; - ret = write_block(fd, blkno, super, &bud->hdr); + /* write left-most buddy block and all full parents, not root */ + ret = write_buddy_blocks(fd, super, &binf, buf, 0, 1, &free_orders); if (ret) goto out; - /* an indirect buddy block references the buddy bitmap block */ - memset(buf, 0, SCOUTFS_BLOCK_SIZE); - ind = buf; - for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) - ind->order_totals[i] = cpu_to_le64(le32_to_cpu( - bud->order_counts[i])); - for (i = 0; i < SCOUTFS_BUDDY_SLOTS; i++) { - ind->slots[i].free_orders = 0; - ind->slots[i].ref = (struct scoutfs_block_ref){0,}; - } - ind->slots[0].free_orders = calc_free_orders(bud); - ind->slots[0].ref.seq = super->hdr.seq; - ind->slots[0].ref.blkno = cpu_to_le64(blkno); - - /* initialize unpopulated slot bits so the kernel will use them */ - sl_blkno = first_blkno(super) + SCOUTFS_BUDDY_ORDER0_BITS; - for (i = 1; i < SCOUTFS_BUDDY_SLOTS; i++) { - ind->slots[i].free_orders = slot_free_orders(sl_blkno, - total_blocks); - sl_blkno += SCOUTFS_BUDDY_ORDER0_BITS; - } - - blkno++; - ret = write_block(fd, blkno, super, &ind->hdr); + /* write right-most buddy and parents and the root */ + ret = write_buddy_blocks(fd, super, &binf, buf, + last_blkno(super) - first_blkno(super), + 0, &free_orders); if (ret) goto out; - /* the super references the buddy indirect block */ - super->buddy_ind_ref.blkno = ind->hdr.blkno; - super->buddy_ind_ref.seq = ind->hdr.seq; - - /* a bitmap block records the two used buddy blocks */ - memset(buf, 0, SCOUTFS_BLOCK_SIZE); - bm = buf; - memset(bm->bits, 0xff, SCOUTFS_BLOCK_SIZE - - offsetof(struct scoutfs_bitmap_block, bits)); - bm->bits[0] = cpu_to_le64(~0ULL << 2); /* two low order bits clear */ - - ret = write_block(fd, SCOUTFS_BUDDY_BM_BLKNO, super, &bm->hdr); - if (ret) - goto out; - - /* the super references the buddy bitmap block */ - super->buddy_bm_ref.blkno = bm->hdr.blkno; - super->buddy_bm_ref.seq = bm->hdr.seq; + /* the super references the buddy leaf block */ + super->buddy_root.height = binf.height; + super->buddy_root.slot.seq = super->hdr.seq; + super->buddy_root.slot.free_orders = cpu_to_le16(free_orders); /* write the two super blocks */ for (i = 0; i < SCOUTFS_SUPER_NR; i++) { @@ -326,15 +435,13 @@ static int write_new_fs(char *path, int fd) " buddy blocks: %llu\n" " fsid: %llx\n" " uuid: %s\n", - total_blocks, buddy_blocks, + total_blocks, le64_to_cpu(super->buddy_blocks), le64_to_cpu(super->hdr.fsid), uuid_str); ret = 0; out: if (super) free(super); - if (bud) - free(bud); if (buf) free(buf); return ret; diff --git a/utils/src/print.c b/utils/src/print.c index 9877be90..31ff1447 100644 --- a/utils/src/print.c +++ b/utils/src/print.c @@ -15,6 +15,7 @@ #include "format.h" #include "cmd.h" #include "crc.h" +#include "buddy.h" /* XXX maybe these go somewhere */ #define SKF "%llu.%u.%llu" @@ -217,98 +218,65 @@ static int print_btree_block(int fd, __le64 blkno, u8 level) return ret; } -static int print_buddy_block(int fd, struct scoutfs_super_block *super, - u64 blkno) +/* print populated buddy blocks */ +static int print_buddy_block(int fd, struct buddy_info *binf, + int level, u64 base, u8 off) { struct scoutfs_buddy_block *bud; + struct scoutfs_buddy_slot *slot; + int ret = 0; + u64 blkno; + u16 first; + int err; int i; + blkno = binf->blknos[level] + base + off; bud = read_block(fd, blkno); if (!bud) return -ENOMEM; printf("buddy blkno %llu\n", blkno); print_block_header(&bud->hdr); - printf(" order_counts:"); - for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) - printf(" %u", le32_to_cpu(bud->order_counts[i])); + printf(" first_set:"); + for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) { + first = le16_to_cpu(bud->first_set[i]); + if (first == U16_MAX) + printf(" -"); + else + printf(" %u", first); + } printf("\n"); + printf(" level: %u\n", bud->level); - free(bud); + for (i = 0; level && i < SCOUTFS_BUDDY_SLOTS; i++) { + slot = &bud->slots[i]; - return 0; -} - -static int print_buddy_blocks(int fd, struct scoutfs_super_block *super) -{ - struct scoutfs_buddy_indirect *ind; - struct scoutfs_buddy_slot *slot; - u64 blkno; - int ret = 0; - int err; - int i; - - blkno = le64_to_cpu(super->buddy_ind_ref.blkno); - ind = read_block(fd, blkno); - if (!ind) - return -ENOMEM; - - printf("buddy indirect blkno %llu\n", blkno); - print_block_header(&ind->hdr); - printf(" total_counts:"); - for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) - printf(" %llu", le64_to_cpu(ind->order_totals[i])); - printf("\n"); - - for (i = 0; i < SCOUTFS_BUDDY_SLOTS; i++) { - slot = &ind->slots[i]; - - /* only print slots with non-zero fields */ - if (!slot->free_orders && !slot->ref.seq && !slot->ref.blkno) + if (slot->seq == 0) continue; - printf(" slot[%u]: free_orders: %x ref: seq %llu blkno %llu\n", - i, slot->free_orders, le64_to_cpu(slot->ref.seq), - le64_to_cpu(slot->ref.blkno)); + printf(" slots[%u]: seq %llu free_orders: %x blkno_off %u\n", + i, le64_to_cpu(slot->seq), + le16_to_cpu(slot->free_orders), slot->blkno_off); } - for (i = 0; i < SCOUTFS_BUDDY_SLOTS; i++) { - slot = &ind->slots[i]; + for (i = 0; level && i < SCOUTFS_BUDDY_SLOTS; i++) { + slot = &bud->slots[i]; - /* only print populated buddy blocks */ - if (slot->ref.blkno == 0) + if (slot->seq == 0) continue; - err = print_buddy_block(fd, super, - le64_to_cpu(slot->ref.blkno)); + err = print_buddy_block(fd, binf, level - 1, + (base * SCOUTFS_BUDDY_SLOTS) + (i * 2), + slot->blkno_off); if (err && !ret) ret = err; } - free(ind); + free(bud); return ret; } - -static int print_bitmap_block(int fd, struct scoutfs_super_block *super) -{ - struct scoutfs_bitmap_block *bm; - u64 blkno; - - blkno = le64_to_cpu(super->buddy_bm_ref.blkno); - bm = read_block(fd, blkno); - if (!bm) - return -ENOMEM; - - printf("bitmap blkno %llu\n", blkno); - print_block_header(&bm->hdr); - - free(bm); - - return 0; -} - static int print_super_blocks(int fd) { struct scoutfs_super_block *super; @@ -329,16 +297,17 @@ static int print_super_blocks(int fd) print_block_header(&super->hdr); printf(" id %llx uuid %s\n", le64_to_cpu(super->id), uuid_str); - printf(" next_ino %llu total_blocks %llu buddy_blocks %u\n", + printf(" next_ino %llu total_blocks %llu buddy_blocks %llu\n" + " free_blocks %llu\n", le64_to_cpu(super->next_ino), le64_to_cpu(super->total_blocks), - le32_to_cpu(super->buddy_blocks)); - printf(" buddy_bm_ref: seq %llu blkno %llu\n", - le64_to_cpu(super->buddy_bm_ref.seq), - le64_to_cpu(super->buddy_bm_ref.blkno)); - printf(" buddy_ind_ref: seq %llu blkno %llu\n", - le64_to_cpu(super->buddy_ind_ref.seq), - le64_to_cpu(super->buddy_ind_ref.blkno)); + le64_to_cpu(super->buddy_blocks), + le64_to_cpu(super->free_blocks)); + printf(" buddy_root: height %u seq %llu free_orders %x blkno_off %u\n", + super->buddy_root.height, + le64_to_cpu(super->buddy_root.slot.seq), + le16_to_cpu(super->buddy_root.slot.free_orders), + super->buddy_root.slot.blkno_off); printf(" btree_root: height %u seq %llu blkno %llu\n", super->btree_root.height, le64_to_cpu(super->btree_root.ref.seq), @@ -352,13 +321,17 @@ static int print_super_blocks(int fd) super = &recent; - err = print_bitmap_block(fd, super); - if (err && !ret) - ret = err; - err = print_buddy_blocks(fd, super); - if (err && !ret) - ret = err; + if (super->buddy_root.height) { + struct buddy_info binf; + + buddy_init(&binf, le64_to_cpu(super->total_blocks)); + err = print_buddy_block(fd, &binf, + super->buddy_root.height - 1, 0, + super->buddy_root.slot.blkno_off); + if (err && !ret) + ret = err; + } if (super->btree_root.height) { err = print_btree_block(fd, super->btree_root.ref.blkno,