Add support for full radix buddy blocks

Update mkfs and print for the full radix buddy allocators.  mkfs has to
calculate the number of blocks and the height of the tree and has to
initialize the paths down the left and right side of the tree.
Print needs to dump the new radix blockx and super block fields.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2016-10-28 11:00:21 -07:00
parent 40b9f19ec4
commit cd0d045c93
5 changed files with 372 additions and 209 deletions

61
utils/src/buddy.c Normal file
View File

@@ -0,0 +1,61 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#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;
}

16
utils/src/buddy.h Normal file
View File

@@ -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

View File

@@ -19,8 +19,7 @@
*/ */
#define SCOUTFS_SUPER_BLKNO ((64 * 1024) >> SCOUTFS_BLOCK_SHIFT) #define SCOUTFS_SUPER_BLKNO ((64 * 1024) >> SCOUTFS_BLOCK_SHIFT)
#define SCOUTFS_SUPER_NR 2 #define SCOUTFS_SUPER_NR 2
#define SCOUTFS_BUDDY_BM_BLKNO (SCOUTFS_SUPER_BLKNO + SCOUTFS_SUPER_NR) #define SCOUTFS_BUDDY_BLKNO (SCOUTFS_SUPER_BLKNO + SCOUTFS_SUPER_NR)
#define SCOUTFS_BUDDY_BM_NR 2
#define SCOUTFS_MAX_TRANS_BLOCKS (128 * 1024 * 1024 / SCOUTFS_BLOCK_SIZE) #define SCOUTFS_MAX_TRANS_BLOCKS (128 * 1024 * 1024 / SCOUTFS_BLOCK_SIZE)
@@ -48,42 +47,49 @@ struct scoutfs_block_ref {
__le64 seq; __le64 seq;
} __packed; } __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_buddy_block {
struct scoutfs_block_header hdr; struct scoutfs_block_header hdr;
__le32 order_counts[SCOUTFS_BUDDY_ORDERS]; __le16 first_set[SCOUTFS_BUDDY_ORDERS];
__le64 bits[0]; __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; } __packed;
/* /*
* If we had log2(raw bits) orders we'd fully use all of the raw bits in * Each buddy leaf block references order 0 blocks with half of its
* the block. We're close enough that the amount of space wasted at the * bitmap. The other half of the bits are used for the higher order
* end (~1/256th of the block, ~64 bytes) isn't worth worrying about. * bits.
*/ */
#define SCOUTFS_BUDDY_ORDER0_BITS \ #define SCOUTFS_BUDDY_ORDER0_BITS \
(((SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_buddy_block)) * 8) / 2) (((SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_buddy_block)) * 8) / 2)
struct scoutfs_buddy_indirect { #define SCOUTFS_BUDDY_SLOTS \
struct scoutfs_block_header hdr; ((SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_buddy_block)) / \
__le64 order_totals[SCOUTFS_BUDDY_ORDERS]; sizeof(struct scoutfs_buddy_slot))
struct scoutfs_buddy_slot {
__u8 free_orders; struct scoutfs_buddy_root {
struct scoutfs_block_ref ref; struct scoutfs_buddy_slot slot;
} slots[0]; __u8 height;
} __packed; } __packed;
#define SCOUTFS_BUDDY_SLOTS \ /* ((SCOUTFS_BUDDY_SLOTS^5) * SCOUTFS_BUDDY_ORDER0_BITS) > 2^52 */
((SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_buddy_indirect)) / \ #define SCOUTFS_BUDDY_MAX_HEIGHT 6
sizeof(struct scoutfs_buddy_slot))
/* /*
* We should be able to make the offset smaller if neither dirents nor * 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]; __u8 uuid[SCOUTFS_UUID_BYTES];
__le64 next_ino; __le64 next_ino;
__le64 total_blocks; __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_btree_root btree_root;
struct scoutfs_block_ref buddy_ind_ref;
struct scoutfs_block_ref buddy_bm_ref;
} __packed; } __packed;
#define SCOUTFS_ROOT_INO 1 #define SCOUTFS_ROOT_INO 1

View File

@@ -18,6 +18,7 @@
#include "rand.h" #include "rand.h"
#include "dev.h" #include "dev.h"
#include "bitops.h" #include "bitops.h"
#include "buddy.h"
/* /*
* Update the block's header and write it out. * 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; return 0;
} }
/* static u64 first_blkno(struct scoutfs_super_block *super)
* 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)
{ {
return DIV_ROUND_UP(total_blocks, SCOUTFS_BUDDY_ORDER0_BITS) + return SCOUTFS_BUDDY_BLKNO + le64_to_cpu(super->buddy_blocks);
((16 * 1024 * 1024) / SCOUTFS_BLOCK_SIZE);
} }
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 + return le64_to_cpu(super->total_blocks) - 1;
le32_to_cpu(super->buddy_blocks);
} }
/* the starting bit offset in the block bitmap of an order's bitmap */ /* 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; 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) static int test_buddy_bit(struct scoutfs_buddy_block *bud, int order, int nr)
{ {
return test_bit_le(order_nr(order, nr), bud->bits); 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) 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)) 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) 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)) 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 */ /* 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; 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)) if (!test_buddy_bit(bud, i, nr ^ 1))
break; 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); 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; int i;
for (i = 0; i < SCOUTFS_BUDDY_ORDERS; 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; return free;
} }
/* static void init_buddy_block(struct scoutfs_buddy_block *bud, int level)
* 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)
{ {
u64 count; int i;
u64 mask;
u8 free;
if (sl_blkno >= total_blocks) memset(bud, 0, SCOUTFS_BLOCK_SIZE);
return 0; 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; if (left) {
free = count & mask; first = blk;
if (count > mask) last = SCOUTFS_BUDDY_ORDER0_BITS - 1;
free |= (mask + 1) >> 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) 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_inode *inode;
struct scoutfs_btree_block *bt; struct scoutfs_btree_block *bt;
struct scoutfs_btree_item *item; 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 scoutfs_key root_key;
struct buddy_info binf;
struct timeval tv; struct timeval tv;
char uuid_str[37]; char uuid_str[37];
unsigned int i; unsigned int i;
u64 limit;
u64 size; u64 size;
u64 blkno; u64 blkno;
u64 count;
u64 total_blocks; u64 total_blocks;
u64 buddy_blocks; u16 free_orders;
u64 sl_blkno;
void *buf; void *buf;
int ret; int ret;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
buf = malloc(SCOUTFS_BLOCK_SIZE); buf = malloc(SCOUTFS_BLOCK_SIZE);
bud = malloc(SCOUTFS_BLOCK_SIZE);
super = malloc(SCOUTFS_BLOCK_SIZE); super = malloc(SCOUTFS_BLOCK_SIZE);
if (!buf || !bud || !super) { if (!buf || !super) {
ret = -errno; ret = -errno;
fprintf(stderr, "failed to allocate a block: %s (%d)\n", fprintf(stderr, "failed to allocate a block: %s (%d)\n",
strerror(errno), errno); strerror(errno), errno);
@@ -190,12 +329,8 @@ static int write_new_fs(char *path, int fd)
/* the block limit is totally arbitrary */ /* the block limit is totally arbitrary */
total_blocks = size / SCOUTFS_BLOCK_SIZE; 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", buddy_init(&binf, total_blocks);
size, total_blocks, SCOUTFS_BLOCK_SIZE);
goto out;
}
buddy_blocks = calc_buddy_blocks(total_blocks);
root_key.inode = cpu_to_le64(SCOUTFS_ROOT_INO); root_key.inode = cpu_to_le64(SCOUTFS_ROOT_INO);
root_key.type = SCOUTFS_INODE_KEY; root_key.type = SCOUTFS_INODE_KEY;
@@ -209,7 +344,16 @@ static int write_new_fs(char *path, int fd)
uuid_generate(super->uuid); uuid_generate(super->uuid);
super->next_ino = cpu_to_le64(SCOUTFS_ROOT_INO + 1); super->next_ino = cpu_to_le64(SCOUTFS_ROOT_INO + 1);
super->total_blocks = cpu_to_le64(total_blocks); 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); 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); ret = write_block(fd, blkno, super, &bt->hdr);
if (ret) if (ret)
goto out; goto out;
/* blkno is now first free */
blkno++;
/* the super references the btree block */ /* the super references the btree block */
super->btree_root.height = 1; super->btree_root.height = 1;
super->btree_root.ref.blkno = bt->hdr.blkno; super->btree_root.ref.blkno = bt->hdr.blkno;
super->btree_root.ref.seq = bt->hdr.seq; super->btree_root.ref.seq = bt->hdr.seq;
/* free all the blocks in the first buddy block after btree block */ /* free_blocks reflects the fs blocks, not buddy blocks */
memset(bud, 0, SCOUTFS_BLOCK_SIZE); super->free_blocks = cpu_to_le64(total_blocks - blkno);
for (i = 1; i < min(total_blocks - first_blkno(super),
SCOUTFS_BUDDY_ORDER0_BITS); i++)
free_order_bit(bud, 0, i);
blkno = SCOUTFS_BUDDY_BM_BLKNO + SCOUTFS_BUDDY_BM_NR; /* write left-most buddy block and all full parents, not root */
ret = write_block(fd, blkno, super, &bud->hdr); ret = write_buddy_blocks(fd, super, &binf, buf, 0, 1, &free_orders);
if (ret) if (ret)
goto out; goto out;
/* an indirect buddy block references the buddy bitmap block */ /* write right-most buddy and parents and the root */
memset(buf, 0, SCOUTFS_BLOCK_SIZE); ret = write_buddy_blocks(fd, super, &binf, buf,
ind = buf; last_blkno(super) - first_blkno(super),
for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) 0, &free_orders);
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);
if (ret) if (ret)
goto out; goto out;
/* the super references the buddy indirect block */ /* the super references the buddy leaf block */
super->buddy_ind_ref.blkno = ind->hdr.blkno; super->buddy_root.height = binf.height;
super->buddy_ind_ref.seq = ind->hdr.seq; super->buddy_root.slot.seq = super->hdr.seq;
super->buddy_root.slot.free_orders = cpu_to_le16(free_orders);
/* 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;
/* write the two super blocks */ /* write the two super blocks */
for (i = 0; i < SCOUTFS_SUPER_NR; i++) { 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" " buddy blocks: %llu\n"
" fsid: %llx\n" " fsid: %llx\n"
" uuid: %s\n", " uuid: %s\n",
total_blocks, buddy_blocks, total_blocks, le64_to_cpu(super->buddy_blocks),
le64_to_cpu(super->hdr.fsid), uuid_str); le64_to_cpu(super->hdr.fsid), uuid_str);
ret = 0; ret = 0;
out: out:
if (super) if (super)
free(super); free(super);
if (bud)
free(bud);
if (buf) if (buf)
free(buf); free(buf);
return ret; return ret;

View File

@@ -15,6 +15,7 @@
#include "format.h" #include "format.h"
#include "cmd.h" #include "cmd.h"
#include "crc.h" #include "crc.h"
#include "buddy.h"
/* XXX maybe these go somewhere */ /* XXX maybe these go somewhere */
#define SKF "%llu.%u.%llu" #define SKF "%llu.%u.%llu"
@@ -217,98 +218,65 @@ static int print_btree_block(int fd, __le64 blkno, u8 level)
return ret; return ret;
} }
static int print_buddy_block(int fd, struct scoutfs_super_block *super, /* print populated buddy blocks */
u64 blkno) 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_block *bud;
struct scoutfs_buddy_slot *slot;
int ret = 0;
u64 blkno;
u16 first;
int err;
int i; int i;
blkno = binf->blknos[level] + base + off;
bud = read_block(fd, blkno); bud = read_block(fd, blkno);
if (!bud) if (!bud)
return -ENOMEM; return -ENOMEM;
printf("buddy blkno %llu\n", blkno); printf("buddy blkno %llu\n", blkno);
print_block_header(&bud->hdr); print_block_header(&bud->hdr);
printf(" order_counts:"); printf(" first_set:");
for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) for (i = 0; i < SCOUTFS_BUDDY_ORDERS; i++) {
printf(" %u", le32_to_cpu(bud->order_counts[i])); first = le16_to_cpu(bud->first_set[i]);
if (first == U16_MAX)
printf(" -");
else
printf(" %u", first);
}
printf("\n"); 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; if (slot->seq == 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)
continue; continue;
printf(" slot[%u]: free_orders: %x ref: seq %llu blkno %llu\n", printf(" slots[%u]: seq %llu free_orders: %x blkno_off %u\n",
i, slot->free_orders, le64_to_cpu(slot->ref.seq), i, le64_to_cpu(slot->seq),
le64_to_cpu(slot->ref.blkno)); le16_to_cpu(slot->free_orders), slot->blkno_off);
} }
for (i = 0; i < SCOUTFS_BUDDY_SLOTS; i++) { for (i = 0; level && i < SCOUTFS_BUDDY_SLOTS; i++) {
slot = &ind->slots[i]; slot = &bud->slots[i];
/* only print populated buddy blocks */ if (slot->seq == 0)
if (slot->ref.blkno == 0)
continue; continue;
err = print_buddy_block(fd, super, err = print_buddy_block(fd, binf, level - 1,
le64_to_cpu(slot->ref.blkno)); (base * SCOUTFS_BUDDY_SLOTS) + (i * 2),
slot->blkno_off);
if (err && !ret) if (err && !ret)
ret = err; ret = err;
} }
free(ind); free(bud);
return ret; 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) static int print_super_blocks(int fd)
{ {
struct scoutfs_super_block *super; struct scoutfs_super_block *super;
@@ -329,16 +297,17 @@ static int print_super_blocks(int fd)
print_block_header(&super->hdr); print_block_header(&super->hdr);
printf(" id %llx uuid %s\n", printf(" id %llx uuid %s\n",
le64_to_cpu(super->id), uuid_str); 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->next_ino),
le64_to_cpu(super->total_blocks), le64_to_cpu(super->total_blocks),
le32_to_cpu(super->buddy_blocks)); le64_to_cpu(super->buddy_blocks),
printf(" buddy_bm_ref: seq %llu blkno %llu\n", le64_to_cpu(super->free_blocks));
le64_to_cpu(super->buddy_bm_ref.seq), printf(" buddy_root: height %u seq %llu free_orders %x blkno_off %u\n",
le64_to_cpu(super->buddy_bm_ref.blkno)); super->buddy_root.height,
printf(" buddy_ind_ref: seq %llu blkno %llu\n", le64_to_cpu(super->buddy_root.slot.seq),
le64_to_cpu(super->buddy_ind_ref.seq), le16_to_cpu(super->buddy_root.slot.free_orders),
le64_to_cpu(super->buddy_ind_ref.blkno)); super->buddy_root.slot.blkno_off);
printf(" btree_root: height %u seq %llu blkno %llu\n", printf(" btree_root: height %u seq %llu blkno %llu\n",
super->btree_root.height, super->btree_root.height,
le64_to_cpu(super->btree_root.ref.seq), le64_to_cpu(super->btree_root.ref.seq),
@@ -352,13 +321,17 @@ static int print_super_blocks(int fd)
super = &recent; super = &recent;
err = print_bitmap_block(fd, super);
if (err && !ret)
ret = err;
err = print_buddy_blocks(fd, super); if (super->buddy_root.height) {
if (err && !ret) struct buddy_info binf;
ret = err;
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) { if (super->btree_root.height) {
err = print_btree_block(fd, super->btree_root.ref.blkno, err = print_btree_block(fd, super->btree_root.ref.blkno,