Add mkfs and print support for buddy alloc

Initialize the block count fields in the super block on mkfs and print
out the buddy allocator fields and blocks.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2016-04-30 12:25:59 -07:00
parent 1235f04c4a
commit 77c673f984
3 changed files with 130 additions and 5 deletions
+38
View File
@@ -19,6 +19,7 @@
*/
#define SCOUTFS_SUPER_BLKNO ((64 * 1024) >> SCOUTFS_BLOCK_SHIFT)
#define SCOUTFS_SUPER_NR 2
#define SCOUTFS_BUDDY_BLKNO (SCOUTFS_SUPER_BLKNO + SCOUTFS_SUPER_NR)
/*
* This header is found at the start of every block so that we can
@@ -102,6 +103,38 @@ struct scoutfs_btree_item {
#define SCOUTFS_UUID_BYTES 16
/*
* Arbitrarily choose a reasonably fine grained 64byte chunk. This is a
* balance between write amplification of writing chunks with a single
* modified bit, storage overhead of partial blocks losing a chunk to
* make room for the block header and having a pos field per chunk, and
* runtime memory overhead of a bit per chunk.
*/
#define SCOUTFS_BUDDY_CHUNK_LE64S 8
#define SCOUTFS_BUDDY_CHUNK_BYTES (SCOUTFS_BUDDY_CHUNK_LE64S * 8)
#define SCOUTFS_BUDDY_CHUNK_BITS (SCOUTFS_BUDDY_CHUNK_BYTES * 8)
/*
* After the pair of super blocks are a preallocated ring of blocks
* which record modified regions of the buddy bitmap allocator.
*
* The seq's header needs to match the unwrapped ring index of the
* block.
*/
struct scoutfs_buddy_block {
struct scoutfs_block_header hdr;
u8 nr_chunks;
struct scoutfs_buddy_chunk {
__le32 pos;
__le64 bits[SCOUTFS_BUDDY_CHUNK_LE64S];
} __packed chunks[0];
} __packed;
#define SCOUTFS_BUDDY_CHUNKS_PER_BLOCK \
((SCOUTFS_BLOCK_SIZE - offsetof(struct scoutfs_buddy_block, chunks)) /\
SCOUTFS_BUDDY_CHUNK_BYTES)
/*
* The super is stored in a pair of blocks in the first chunk on the
* device.
@@ -116,6 +149,11 @@ struct scoutfs_super_block {
struct scoutfs_block_header hdr;
__le64 id;
__u8 uuid[SCOUTFS_UUID_BYTES];
__le64 total_blocks;
__le32 buddy_blocks;
__le32 buddy_sweep_bit;
__le64 buddy_head;
__le64 buddy_tail;
struct scoutfs_btree_root btree_root;
} __packed;
+35 -2
View File
@@ -39,6 +39,24 @@ static int write_block(int fd, u64 blkno, struct scoutfs_block_header *hdr)
return 0;
}
/*
* Calculate the number of buddy blocks that are needed to track the
* allocation of a device with the given byte size. We need an even
* number of buddy blocks that contain 8 bits for every device block. This
* is a bit overly conservative in that it doesn't subtract the buddy
* blocks and super block from the calculation.
*/
static u32 calc_buddy_blocks(u64 total_blocks)
{
u64 buddy_bits = total_blocks * 8;
u64 chunks = DIV_ROUND_UP(buddy_bits, SCOUTFS_BUDDY_CHUNK_BITS);
u64 blocks = DIV_ROUND_UP(chunks, SCOUTFS_BUDDY_CHUNKS_PER_BLOCK);
/* XXX check u32 overflow? */
return round_up(blocks, 2);
}
static int write_new_fs(char *path, int fd)
{
struct scoutfs_super_block *super;
@@ -51,6 +69,8 @@ static int write_new_fs(char *path, int fd)
unsigned int i;
u64 size;
u64 blkno;
u64 total_blocks;
u64 buddy_blocks;
void *buf;
int ret;
@@ -72,6 +92,15 @@ static int write_new_fs(char *path, int fd)
goto out;
}
/* 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);
root_key.inode = cpu_to_le64(SCOUTFS_ROOT_INO);
root_key.type = SCOUTFS_INODE_KEY;
root_key.offset = 0;
@@ -85,6 +114,8 @@ static int write_new_fs(char *path, int fd)
super->hdr.seq = cpu_to_le64(1);
super->id = cpu_to_le64(SCOUTFS_SUPER_ID);
uuid_generate(super->uuid);
super->total_blocks = cpu_to_le64(total_blocks);
super->buddy_blocks = cpu_to_le32(buddy_blocks);
/* write a btree leaf root inode item */
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
@@ -142,10 +173,12 @@ static int write_new_fs(char *path, int fd)
uuid_unparse(super->uuid, uuid_str);
printf("Created scoutfs filesystem:\n"
" block size: %u\n"
" total blocks: %llu\n"
" buddy blocks: %llu\n"
" fsid: %llx\n"
" uuid: %s\n",
SCOUTFS_BLOCK_SIZE, le64_to_cpu(super->hdr.fsid), uuid_str);
total_blocks, buddy_blocks,
le64_to_cpu(super->hdr.fsid), uuid_str);
ret = 0;
out:
+57 -3
View File
@@ -178,6 +178,49 @@ static int print_btree_block(int fd, __le64 blkno, u8 level)
return ret;
}
static int print_buddy_blocks(int fd, struct scoutfs_super_block *super)
{
struct scoutfs_buddy_chunk *chunk;
struct scoutfs_buddy_block *bb;
u64 blkno;
u64 blocks;
u64 head;
u64 tail;
int i;
int j;
blocks = le32_to_cpu(super->buddy_blocks);
head = le64_to_cpu(super->buddy_head);
tail = le64_to_cpu(super->buddy_tail);
/* XXX make sure values are sane */
for (; head < tail; head++) {
blkno = SCOUTFS_BUDDY_BLKNO + (head % blocks);
bb = read_block(fd, blkno);
if (!bb)
return -ENOMEM;
printf("buddy blkno %llu\n", blkno);
print_block_header(&bb->hdr);
printf(" nr_chunks %u\n", bb->nr_chunks);
for (i = 0; i < bb->nr_chunks; i++) {
chunk = &bb->chunks[i];
printf(" [%u]: pos %u bits ",
i, le32_to_cpu(chunk->pos));
for (j = 0; j < SCOUTFS_BUDDY_CHUNK_LE64S; j++)
printf("%016llx", le64_to_cpu(chunk->bits[j]));
printf("\n");
}
free(bb);
}
return 0;
}
static int print_super_blocks(int fd)
{
struct scoutfs_super_block *super;
@@ -198,6 +241,13 @@ 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(" total_blocks %llu buddy_blocks %u buddy_sweep_bit %u\n"
" buddy_head %llu buddy_tail %llu\n",
le64_to_cpu(super->total_blocks),
le32_to_cpu(super->buddy_blocks),
le32_to_cpu(super->buddy_sweep_bit),
le64_to_cpu(super->buddy_head),
le64_to_cpu(super->buddy_tail));
printf(" btree_root: height %u seq %llu blkno %llu\n",
super->btree_root.height,
le64_to_cpu(super->btree_root.ref.seq),
@@ -211,11 +261,15 @@ static int print_super_blocks(int fd)
super = &recent;
if (super->btree_root.height)
ret = print_buddy_blocks(fd, super);
if (super->btree_root.height) {
err = print_btree_block(fd, super->btree_root.ref.blkno,
super->btree_root.height - 1);
if (err && !ret)
ret = err;
if (err && !ret)
ret = err;
}
return ret;
}