From 23711f05f6fc689dd5d48370b0727dadacb75884 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 18 Sep 2020 15:06:37 -0700 Subject: [PATCH] scoutfs-utils: alloc and data uses full extents Signed-off-by: Zach Brown --- utils/src/format.h | 108 +++++++++++++--- utils/src/mkfs.c | 272 ++++++++++++--------------------------- utils/src/print.c | 313 +++++++++++++++++++++------------------------ utils/src/radix.c | 106 --------------- utils/src/radix.h | 13 -- 5 files changed, 315 insertions(+), 497 deletions(-) delete mode 100644 utils/src/radix.c delete mode 100644 utils/src/radix.h diff --git a/utils/src/format.h b/utils/src/format.h index cd33a7c6..d5a78ade 100644 --- a/utils/src/format.h +++ b/utils/src/format.h @@ -11,6 +11,7 @@ #define SCOUTFS_BLOCK_MAGIC_RADIX 0xebeb5e65 #define SCOUTFS_BLOCK_MAGIC_SRCH_BLOCK 0x897e4a7d #define SCOUTFS_BLOCK_MAGIC_SRCH_PARENT 0xb23a2a05 +#define SCOUTFS_BLOCK_MAGIC_ALLOC_LIST 0x8a93ac83 /* * The super block, quorum block, and file data allocation granularity @@ -143,10 +144,10 @@ struct scoutfs_key { #define sks_ino _sk_first #define sks_nr _sk_second -/* packed extents */ -#define skpe_ino _sk_first -#define skpe_base _sk_second -#define skpe_part _sk_fourth +/* data extents */ +#define skdx_ino _sk_first +#define skdx_end _sk_second +#define skdx_len _sk_third /* log trees */ #define sklt_rid _sk_first @@ -162,6 +163,13 @@ struct scoutfs_key { /* mounted clients */ #define skmc_rid _sk_first +/* free extents by blkno */ +#define skfb_end _sk_second +#define skfb_len _sk_third +/* free extents by len */ +#define skfl_neglen _sk_second +#define skfl_blkno _sk_third + struct scoutfs_radix_block { struct scoutfs_block_header hdr; union { @@ -266,6 +274,53 @@ struct scoutfs_btree_block { #define SCOUTFS_BTREE_LEAF_ITEM_HASH_BYTES \ (SCOUTFS_BTREE_LEAF_ITEM_HASH_NR * sizeof(__le16)) +struct scoutfs_alloc_list_ref { + __le64 blkno; + __le64 seq; +}__packed; + +/* + * first_nr tracks the nr of the first block in the list and is used for + * allocation sizing. total_nr is the sum of the nr of all the blocks in + * the list and is used for calculating total free block counts. + */ +struct scoutfs_alloc_list_head { + struct scoutfs_alloc_list_ref ref; + __le64 total_nr; + __le32 first_nr; +}__packed; + +/* + * While the main allocator uses extent items in btree blocks, metadata + * allocations for a single transaction are recorded in arrays in + * blocks. This limits the number of allocations and frees needed to + * cow and modify the structure. The blocks can be stored in a list + * which lets us create a persistent log of pending frees that are + * generated as we cow btree blocks to insert freed extents. + * + * The array floats in the block so that both adding and removing blknos + * only modifies an index. + */ +struct scoutfs_alloc_list_block { + struct scoutfs_block_header hdr; + struct scoutfs_alloc_list_ref next; + __le32 start; + __le32 nr; + __le64 blknos[0]; /* naturally aligned for sorting */ +}__packed; + +#define SCOUTFS_ALLOC_LIST_MAX_BLOCKS \ + ((SCOUTFS_BLOCK_LG_SIZE - sizeof(struct scoutfs_alloc_list_block)) / \ + (member_sizeof(struct scoutfs_alloc_list_block, blknos[0]))) + +/* + * These can safely be initialized to all-zeros. + */ +struct scoutfs_alloc_root { + __le64 total_len; + struct scoutfs_btree_root root; +}__packed; + struct scoutfs_mounted_client_btree_val { __u8 flags; } __packed; @@ -338,8 +393,8 @@ struct scoutfs_srch_block { #define SCOUTFS_SRCH_COMPACT_NR (1 << SCOUTFS_SRCH_COMPACT_ORDER) struct scoutfs_srch_compact_input { - struct scoutfs_radix_root meta_avail; - struct scoutfs_radix_root meta_freed; + struct scoutfs_alloc_list_head meta_avail; + struct scoutfs_alloc_list_head meta_freed; __le64 id; __u8 nr; __u8 flags; @@ -347,8 +402,8 @@ struct scoutfs_srch_compact_input { } __packed; struct scoutfs_srch_compact_result { - struct scoutfs_radix_root meta_avail; - struct scoutfs_radix_root meta_freed; + struct scoutfs_alloc_list_head meta_avail; + struct scoutfs_alloc_list_head meta_freed; __le64 id; __u8 flags; struct scoutfs_srch_file sfl; @@ -365,24 +420,24 @@ struct scoutfs_srch_compact_result { * about item logs, it's about clients making changes to trees. */ struct scoutfs_log_trees { - struct scoutfs_radix_root meta_avail; - struct scoutfs_radix_root meta_freed; + struct scoutfs_alloc_list_head meta_avail; + struct scoutfs_alloc_list_head meta_freed; struct scoutfs_btree_root item_root; struct scoutfs_btree_ref bloom_ref; - struct scoutfs_radix_root data_avail; - struct scoutfs_radix_root data_freed; + struct scoutfs_alloc_root data_avail; + struct scoutfs_alloc_root data_freed; struct scoutfs_srch_file srch_file; __le64 rid; __le64 nr; } __packed; struct scoutfs_log_trees_val { - struct scoutfs_radix_root meta_avail; - struct scoutfs_radix_root meta_freed; + struct scoutfs_alloc_list_head meta_avail; + struct scoutfs_alloc_list_head meta_freed; struct scoutfs_btree_root item_root; struct scoutfs_btree_ref bloom_ref; - struct scoutfs_radix_root data_avail; - struct scoutfs_radix_root data_freed; + struct scoutfs_alloc_root data_avail; + struct scoutfs_alloc_root data_freed; struct scoutfs_srch_file srch_file; } __packed; @@ -434,6 +489,7 @@ struct scoutfs_bloom_block { #define SCOUTFS_TRANS_SEQ_ZONE 8 #define SCOUTFS_MOUNTED_CLIENT_ZONE 9 #define SCOUTFS_SRCH_ZONE 10 +#define SCOUTFS_FREE_EXTENT_ZONE 11 /* inode index zone */ #define SCOUTFS_INODE_INDEX_META_SEQ_TYPE 1 @@ -450,7 +506,7 @@ struct scoutfs_bloom_block { #define SCOUTFS_READDIR_TYPE 4 #define SCOUTFS_LINK_BACKREF_TYPE 5 #define SCOUTFS_SYMLINK_TYPE 6 -#define SCOUTFS_PACKED_EXTENT_TYPE 7 +#define SCOUTFS_DATA_EXTENT_TYPE 7 /* lock zone, only ever found in lock ranges, never in persistent items */ #define SCOUTFS_RENAME_TYPE 1 @@ -460,6 +516,10 @@ struct scoutfs_bloom_block { #define SCOUTFS_SRCH_BLOCKS_TYPE 2 #define SCOUTFS_SRCH_BUSY_TYPE 3 +/* free extents in allocator btrees in client and server, by blkno or len */ +#define SCOUTFS_FREE_EXTENT_BLKNO_TYPE 1 +#define SCOUTFS_FREE_EXTENT_LEN_TYPE 2 + /* * The extents that map blocks in a fixed-size logical region of a file * are packed and stored in item values. The packed extents are @@ -491,6 +551,12 @@ struct scoutfs_packed_extent { #define SCOUTFS_PACKEXT_BASE_MASK (~((__u64)SCOUTFS_PACKEXT_BLOCKS - 1)) #define SCOUTFS_PACKEXT_MAX_BYTES SCOUTFS_MAX_VAL_SIZE +/* file data extents have start and len in key */ +struct scoutfs_data_extent_val { + __le64 blkno; + __u8 flags; +} __packed; + #define SEF_OFFLINE (1 << 0) #define SEF_UNWRITTEN (1 << 1) #define SEF_UNKNOWN (U8_MAX << 2) @@ -575,10 +641,10 @@ struct scoutfs_super_block { __le64 unmount_barrier; __u8 quorum_count; struct scoutfs_inet_addr server_addr; - struct scoutfs_radix_root core_meta_avail; - struct scoutfs_radix_root core_meta_freed; - struct scoutfs_radix_root core_data_avail; - struct scoutfs_radix_root core_data_freed; + struct scoutfs_alloc_root meta_alloc[2]; + struct scoutfs_alloc_root data_alloc; + struct scoutfs_alloc_list_head server_meta_avail[2]; + struct scoutfs_alloc_list_head server_meta_freed[2]; struct scoutfs_btree_root fs_root; struct scoutfs_btree_root logs_root; struct scoutfs_btree_root lock_clients; diff --git a/utils/src/mkfs.c b/utils/src/mkfs.c index 373de609..569e403f 100644 --- a/utils/src/mkfs.c +++ b/utils/src/mkfs.c @@ -26,7 +26,6 @@ #include "dev.h" #include "key.h" #include "bitops.h" -#include "radix.h" #include "btree.h" #include "leaf_item_hash.h" @@ -92,185 +91,39 @@ static char *size_str(u64 nr, unsigned size) #define SIZE_ARGS(nr, sz) (nr), size_flt(nr, sz), size_str(nr, sz) /* - * Update a reference to a block of references that has been modified. We - * walk all the references and rebuild the ref tracking. + * Write the single btree block that contains the blkno and len indexed + * items to store the given extent, and update the root to point to it. */ -static void update_parent_ref(struct scoutfs_radix_ref *ref, - struct scoutfs_radix_block *rdx) +static int write_alloc_root(struct scoutfs_super_block *super, int fd, + struct scoutfs_alloc_root *root, + struct scoutfs_btree_block *bt, + u64 blkno, u64 start, u64 len) { - int i; + struct scoutfs_key key; - ref->sm_total = cpu_to_le64(0); - ref->lg_total = cpu_to_le64(0); + btree_init_root_single(&root->root, bt, blkno, 1, super->hdr.fsid); + root->total_len = cpu_to_le64(len); - for (i = 0; i < SCOUTFS_RADIX_REFS; i++) { - le64_add_cpu(&ref->sm_total, - le64_to_cpu(rdx->refs[i].sm_total)); - le64_add_cpu(&ref->lg_total, - le64_to_cpu(rdx->refs[i].lg_total)); - } -} + memset(&key, 0, sizeof(key)); + key.sk_zone = SCOUTFS_FREE_EXTENT_ZONE; + key.sk_type = SCOUTFS_FREE_EXTENT_BLKNO_TYPE; + key.skii_ino = cpu_to_le64(SCOUTFS_ROOT_INO); + key.skfb_end = cpu_to_le64(start + len - 1); + key.skfb_len = cpu_to_le64(len); + btree_append_item(bt, &key, NULL, 0); -/* - * Initialize all the blocks in a path to a leaf with the given blocks - * set. We know that we're being called to set all the bits in a region - * by setting the left and right partial leafs of the region. We first - * set the left and set full references down the left path, then we're - * called on the right and set full to the left and clear full refs past - * the right. - * - * The caller provides an array of block buffers and a starting block - * number to allocate blocks from and reference blocks within. It's the - * world's dumbest block cache. - */ -static void set_radix_path(struct scoutfs_super_block *super, int *inds, - struct scoutfs_radix_ref *ref, int level, bool left, - void **blocks, u64 blkno_base, u64 *next_blkno, - u64 first, u64 last) -{ - struct scoutfs_radix_block *rdx; - bool shared; - int lg_ind; - int lg_after; - u64 bno; - int ind; - int end; - int i; + memset(&key, 0, sizeof(key)); + key.sk_zone = SCOUTFS_FREE_EXTENT_ZONE; + key.sk_type = SCOUTFS_FREE_EXTENT_LEN_TYPE; + key.skii_ino = cpu_to_le64(SCOUTFS_ROOT_INO); + key.skfl_neglen = cpu_to_le64(-len); + key.skfl_blkno = cpu_to_le64(start); + btree_append_item(bt, &key, NULL, 0); - if (ref->blkno == 0) { - bno = (*next_blkno)++; - ref->blkno = cpu_to_le64(bno); - ref->seq = cpu_to_le64(1); - } + bt->hdr.crc = cpu_to_le32(crc_block(&bt->hdr, + SCOUTFS_BLOCK_LG_SIZE)); - rdx = blocks[le64_to_cpu(ref->blkno) - blkno_base]; - - if (level) { - ind = inds[level]; - - /* initialize empty parent blocks with empty refs */ - if (ref->sm_total == 0) { - for (i = 0; i < SCOUTFS_RADIX_REFS; i++) - radix_init_ref(&rdx->refs[i], level - 1, false); - shared = false; - } else { - shared = true; - } - - if (left) { - /* initialize full refs from left to end */ - for (i = ind + 1; i < SCOUTFS_RADIX_REFS; i++) - radix_init_ref(&rdx->refs[i], level - 1, true); - - } else if (shared) { - /* wipe full refs including right to end */ - for (i = ind; i < SCOUTFS_RADIX_REFS; i++) - radix_init_ref(&rdx->refs[i], level - 1, false); - } else { - /* initialize full refs from start to right */ - for (i = 0; i < ind - 1; i++) - radix_init_ref(&rdx->refs[i], level - 1, true); - } - - set_radix_path(super, inds, &rdx->refs[ind], level - 1, left, - blocks, blkno_base, next_blkno, first, last); - update_parent_ref(ref, rdx); - - } else { - - ind = first - radix_calc_leaf_bit(first); - end = last - radix_calc_leaf_bit(last); - for (i = ind; i <= end; i++) - set_bit_le(i, rdx->bits); - - ref->sm_total = cpu_to_le64(end - ind + 1); - - lg_ind = round_up(ind, SCOUTFS_RADIX_LG_BITS); - lg_after = round_down(end + 1, SCOUTFS_RADIX_LG_BITS); - - ref->lg_total = cpu_to_le64(lg_after - lg_ind); - } -} - -/* - * Initialize a new radix allocator with the region of bits set. We - * initialize and write populated blocks down the paths to the two ends - * of the interval and write full refs in between. - */ -static int write_radix_blocks(struct scoutfs_super_block *super, int fd, - struct scoutfs_radix_root *root, - u64 blkno, u64 first, u64 last) -{ - struct scoutfs_radix_block *rdx; - void **blocks; - u64 next_blkno; - u64 edge; - u8 height; - int alloced; - int used; - int *inds; - int ret; - int i; - - height = radix_height_from_last(last); - inds = alloca(sizeof(inds[0]) * height); - alloced = height * 2; - next_blkno = blkno; - - /* allocate all the blocks we might need */ - blocks = calloc(alloced, sizeof(*blocks)); - if (!blocks) - return -ENOMEM; - - for (i = 0; i < alloced; i++) { - blocks[i] = calloc(1, SCOUTFS_BLOCK_LG_SIZE); - if (blocks[i] == NULL) { - ret = -ENOMEM; - goto out; - } - } - - /* initialize empty root ref */ - memset(root, 0, sizeof(struct scoutfs_radix_root)); - root->height = height; - radix_init_ref(&root->ref, height - 1, false); - - edge = radix_calc_leaf_bit(first) + SCOUTFS_RADIX_BITS - 1; - radix_calc_level_inds(inds, height, first); - set_radix_path(super, inds, &root->ref, root->height - 1, true, blocks, - blkno, &next_blkno, first, min(edge, last)); - - edge = radix_calc_leaf_bit(last); - radix_calc_level_inds(inds, height, last); - set_radix_path(super, inds, &root->ref, root->height - 1, false, blocks, - blkno, &next_blkno, max(first, edge), last); - - used = next_blkno - blkno; - - /* write out all the dirtied blocks */ - for (i = 0; i < used; i++) { - rdx = blocks[i]; - rdx->hdr.magic = cpu_to_le32(SCOUTFS_BLOCK_MAGIC_RADIX); - rdx->hdr.fsid = super->hdr.fsid; - rdx->hdr.seq = cpu_to_le64(1); - rdx->hdr.blkno = cpu_to_le64(blkno + i); - rdx->hdr.crc = cpu_to_le32(crc_block(&rdx->hdr, - SCOUTFS_BLOCK_LG_SIZE)); - ret = write_raw_block(fd, blkno + i, SCOUTFS_BLOCK_LG_SHIFT, - rdx); - if (ret < 0) - goto out; - } - - ret = used; -out: - if (blocks) { - for (i = 0; i < alloced && blocks[i]; i++) - free(blocks[i]); - free(blocks); - } - - return ret; + return write_raw_block(fd, blkno, SCOUTFS_BLOCK_LG_SHIFT, bt); } /* @@ -283,6 +136,7 @@ static int write_new_fs(char *path, int fd, u8 quorum_count) { struct scoutfs_super_block *super; struct scoutfs_inode inode; + struct scoutfs_alloc_list_block *lblk; struct scoutfs_btree_block *bt; struct scoutfs_key key; struct timeval tv; @@ -291,11 +145,12 @@ static int write_new_fs(char *path, int fd, u8 quorum_count) u64 blkno; u64 limit; u64 size; - u64 meta_alloc_blocks; u64 next_meta; u64 last_meta; u64 first_data; u64 last_data; + u64 meta_start; + u64 meta_len; int ret; int i; @@ -386,31 +241,62 @@ static int write_new_fs(char *path, int fd, u8 quorum_count) if (ret) goto out; - /* write out radix allocator blocks for data */ - ret = write_radix_blocks(super, fd, &super->core_data_avail, next_meta, - first_data, last_data); + /* fill an avail list block for the first server transaction */ + blkno = next_meta++; + lblk = (void *)bt; + memset(lblk, 0, SCOUTFS_BLOCK_LG_SIZE); + + lblk->hdr.magic = cpu_to_le32(SCOUTFS_BLOCK_MAGIC_ALLOC_LIST); + lblk->hdr.fsid = super->hdr.fsid; + lblk->hdr.blkno = cpu_to_le64(blkno); + lblk->hdr.seq = cpu_to_le64(1); + + meta_len = (64 * 1024 * 1024) >> SCOUTFS_BLOCK_LG_SHIFT; + for (i = 0; i < meta_len; i++) { + lblk->blknos[i] = cpu_to_le64(next_meta); + next_meta++; + } + lblk->nr = cpu_to_le32(i); + + super->server_meta_avail[0].ref.blkno = lblk->hdr.blkno; + super->server_meta_avail[0].ref.seq = lblk->hdr.seq; + super->server_meta_avail[0].total_nr = le32_to_le64(lblk->nr); + super->server_meta_avail[0].first_nr = lblk->nr; + + lblk->hdr.crc = cpu_to_le32(crc_block(&bt->hdr, SCOUTFS_BLOCK_LG_SIZE)); + ret = write_raw_block(fd, blkno, SCOUTFS_BLOCK_LG_SHIFT, lblk); + if (ret) + goto out; + + /* the data allocator has a single extent */ + blkno = next_meta++; + ret = write_alloc_root(super, fd, &super->data_alloc, bt, + blkno, first_data, + le64_to_cpu(super->total_data_blocks)); if (ret < 0) goto out; - next_meta += ret; - - super->core_data_freed.height = super->core_data_avail.height; - radix_init_ref(&super->core_data_freed.ref, 0, false); - - meta_alloc_blocks = radix_blocks_needed(next_meta, last_meta); /* - * Write out radix alloc blocks, knowing that the region we mark - * has to start after the blocks we store the allocator itself in. + * Initialize all the meta_alloc roots with an equal portion of + * the free metadata extents, excluding the blocks we're going + * to use for the allocators. */ - ret = write_radix_blocks(super, fd, &super->core_meta_avail, - next_meta, next_meta + meta_alloc_blocks, - last_meta); - if (ret < 0) - goto out; - next_meta += ret; + meta_start = next_meta + array_size(super->meta_alloc); + meta_len = DIV_ROUND_UP(last_meta - meta_start + 1, + array_size(super->meta_alloc)); - super->core_meta_freed.height = super->core_meta_avail.height; - radix_init_ref(&super->core_meta_freed.ref, 0, false); + /* each meta alloc root contains a portion of free metadata extents */ + for (i = 0; i < array_size(super->meta_alloc); i++) { + blkno = next_meta++; + ret = write_alloc_root(super, fd, &super->meta_alloc[i], bt, + blkno, meta_start, + min(meta_len, + last_meta - meta_start + 1)); + if (ret < 0) + goto out; + + meta_start += meta_len; + } /* zero out quorum blocks */ for (i = 0; i < SCOUTFS_QUORUM_BLOCKS; i++) { diff --git a/utils/src/print.c b/utils/src/print.c index 82784f82..cac546dc 100644 --- a/utils/src/print.c +++ b/utils/src/print.c @@ -20,7 +20,6 @@ #include "cmd.h" #include "crc.h" #include "key.h" -#include "radix.h" #include "avl.h" #include "srch.h" #include "leaf_item_hash.h" @@ -149,70 +148,17 @@ static void print_symlink(struct scoutfs_key *key, void *val, int val_len) le64_to_cpu(key->sks_ino), le64_to_cpu(key->sks_nr), name); } -static void print_packed_extent(struct scoutfs_key *key, void *val, int val_len) +static void print_data_extent(struct scoutfs_key *key, void *val, int val_len) { - struct scoutfs_packed_extent *pe; - __le64 led; + struct scoutfs_data_extent_val *dv = val; u64 iblock; - u64 blkno = 0; - u64 diff; - int off = 0; - int i = 0; + iblock = le64_to_cpu(key->skdx_end) - le64_to_cpu(key->skdx_len) + 1; - /* - * Ugh, this is the only item that has state between items. It - * probably shouldn't. And I'm too lazy to plumb an arg through - * all the printers. - */ - static struct scoutfs_key next_key; - static u64 next_blkno; - - if (scoutfs_key_compare(key, &next_key) == 0) - blkno = next_blkno; - - iblock = le64_to_cpu(key->skpe_base) << SCOUTFS_PACKEXT_BASE_SHIFT; - - while (off < val_len) { - printf(" [%u] off %u: ibl %llu ", i, off, iblock); - - if (off + sizeof(struct scoutfs_packed_extent) > val_len) { - printf("(packed extent struct exceeds item)\n"); - return; - } - - pe = val + off; - printf("cnt %u dfb %u fl %x fin %u ", - le16_to_cpu(pe->count), pe->diff_bytes, pe->flags, - pe->final); - - off += sizeof(struct scoutfs_packed_extent); - - if (off + pe->diff_bytes > val_len) { - printf("(packed extent diff bytes exceeds item)\n"); - return; - } - - if (pe->diff_bytes) { - led = 0; - memcpy(&led, pe->le_blkno_diff, pe->diff_bytes); - diff = le64_to_cpu(led); - diff = (diff >> 1) ^ (-(diff & 1)); - blkno += diff; - printf("dif %lld blk %llu\n", (s64)diff, blkno); - blkno += le16_to_cpu(pe->count) - 1; - } else { - printf("(sparse)\n"); - } - - iblock += le16_to_cpu(pe->count); - off += pe->diff_bytes; - i++; - } - - next_blkno = blkno; - next_key = *key; - scoutfs_key_inc(&next_key); + printf(" extent: ino %llu iblock %llu len %llu blkno %llu flags %x\n", + le64_to_cpu(key->skdx_ino), iblock, + le64_to_cpu(key->skdx_len), + le64_to_cpu(dv->blkno), dv->flags); } static void print_inode_index(struct scoutfs_key *key, void *val, int val_len) @@ -243,8 +189,7 @@ static print_func_t find_printer(u8 zone, u8 type) case SCOUTFS_READDIR_TYPE: return print_dirent; case SCOUTFS_SYMLINK_TYPE: return print_symlink; case SCOUTFS_LINK_BACKREF_TYPE: return print_dirent; - case SCOUTFS_PACKED_EXTENT_TYPE: - return print_packed_extent; + case SCOUTFS_DATA_EXTENT_TYPE: return print_data_extent; } } @@ -302,17 +247,31 @@ static int print_logs_item(struct scoutfs_key *key, void *val, return 0; } -#define RADREF_F \ - "blkno %llu seq %llu sm_total %llu lg_total %llu" -#define RADREF_A(ref) \ - le64_to_cpu((ref)->blkno), le64_to_cpu((ref)->seq), \ - le64_to_cpu((ref)->sm_total), le64_to_cpu((ref)->lg_total) +#define BTREF_F \ + "blkno %llu seq %llu" +#define BTREF_A(ref) \ + le64_to_cpu((ref)->blkno), le64_to_cpu((ref)->seq) -#define RADROOT_F \ - "height %u next_find_bit %llu ref: "RADREF_F -#define RADROOT_A(root) \ - (root)->height, le64_to_cpu((root)->next_find_bit), \ - RADREF_A(&(root)->ref) +#define BTROOT_F \ + BTREF_F" height %u" +#define BTROOT_A(root) \ + BTREF_A(&(root)->ref), (root)->height + +#define AL_REF_F \ + "blkno %llu seq %llu" +#define AL_REF_A(p) \ + le64_to_cpu((p)->blkno), le64_to_cpu((p)->seq) + +#define AL_HEAD_F \ + AL_REF_F" total_nr %llu first_nr %u" +#define AL_HEAD_A(p) \ + AL_REF_A(&(p)->ref), le64_to_cpu((p)->total_nr),\ + le32_to_cpu((p)->first_nr) + +#define ALCROOT_F \ + BTROOT_F" total_len %llu" +#define ALCROOT_A(ar) \ + BTROOT_A(&(ar)->root), le64_to_cpu((ar)->total_len) #define SRE_FMT "%016llx.%llu.%llu" #define SRE_A(sre) \ @@ -338,22 +297,22 @@ static int print_log_trees_item(struct scoutfs_key *key, void *val, /* only items in leaf blocks have values */ if (val) { - printf(" meta_avail: "RADROOT_F"\n" - " meta_freed: "RADROOT_F"\n" + printf(" meta_avail: "AL_HEAD_F"\n" + " meta_freed: "AL_HEAD_F"\n" " item_root: height %u blkno %llu seq %llu\n" " bloom_ref: blkno %llu seq %llu\n" - " data_avail: "RADROOT_F"\n" - " data_freed: "RADROOT_F"\n" + " data_avail: "ALCROOT_F"\n" + " data_freed: "ALCROOT_F"\n" " srch_file: "SRF_FMT"\n", - RADROOT_A(<v->meta_avail), - RADROOT_A(<v->meta_freed), + AL_HEAD_A(<v->meta_avail), + AL_HEAD_A(<v->meta_freed), ltv->item_root.height, le64_to_cpu(ltv->item_root.ref.blkno), le64_to_cpu(ltv->item_root.ref.seq), le64_to_cpu(ltv->bloom_ref.blkno), le64_to_cpu(ltv->bloom_ref.seq), - RADROOT_A(<v->data_avail), - RADROOT_A(<v->data_freed), + ALCROOT_A(<v->data_avail), + ALCROOT_A(<v->data_freed), SRF_A(<v->srch_file)); } @@ -417,6 +376,24 @@ static int print_mounted_client_entry(struct scoutfs_key *key, void *val, return 0; } +static int print_alloc_item(struct scoutfs_key *key, void *val, + unsigned val_len, void *arg) +{ + if (key->sk_type == SCOUTFS_FREE_EXTENT_BLKNO_TYPE) + printf(" free extent: blkno %llu len %llu end %llu\n", + le64_to_cpu(key->skfb_end) - + le64_to_cpu(key->skfb_len) + 1, + le64_to_cpu(key->skfb_len), + le64_to_cpu(key->skfb_end)); + else + printf(" free extent: blkno %llu len %llu neglen %lld\n", + le64_to_cpu(key->skfl_blkno), + -le64_to_cpu(key->skfl_neglen), + (long long)le64_to_cpu(key->skfl_neglen)); + + return 0; +} + typedef int (*print_item_func)(struct scoutfs_key *key, void *val, unsigned val_len, void *arg); @@ -566,67 +543,55 @@ static int print_btree(int fd, struct scoutfs_super_block *super, char *which, return ret; } -static int print_radix_block(int fd, struct scoutfs_radix_ref *par, int level) +static int print_alloc_list_block(int fd, char *str, + struct scoutfs_alloc_list_ref *ref) { - struct scoutfs_radix_block *rdx; + struct scoutfs_alloc_list_block *lblk; + struct scoutfs_alloc_list_ref next; u64 blkno; - int prev; - int ret; - int err; + u64 start; + u64 len; + int wid; int i; - /* XXX not printing bitmap leaf blocks */ - blkno = le64_to_cpu(par->blkno); - if (blkno == 0 || blkno == U64_MAX || level == 0) + blkno = le64_to_cpu(ref->blkno); + if (blkno == 0) return 0; - rdx = read_block(fd, le64_to_cpu(par->blkno) , SCOUTFS_BLOCK_LG_SHIFT); - if (!rdx) { - ret = -ENOMEM; - goto out; + lblk = read_block(fd, blkno, SCOUTFS_BLOCK_LG_SHIFT); + if (!lblk) + return -ENOMEM; + + printf("%s alloc_list_block blkno %llu\n", str, blkno); + print_block_header(&lblk->hdr, SCOUTFS_BLOCK_LG_SIZE); + printf(" next "AL_REF_F" start %u nr %u\n", + AL_REF_A(&lblk->next), le32_to_cpu(lblk->start), + le32_to_cpu(lblk->nr)); + + if (lblk->nr) { + wid = printf(" exts: "); + start = 0; + len = 0; + for (i = 0; i < le32_to_cpu(lblk->nr); i++) { + if (len == 0) + start = le64_to_cpu(lblk->blknos[i]); + len++; + + if (i == (le32_to_cpu(lblk->nr) - 1) || + start + len != le64_to_cpu(lblk->blknos[i + 1])) { + if (wid >= 72) + wid = printf("\n "); + + wid += printf("%llu,%llu ", start, len); + len = 0; + } + } + printf("\n"); } - printf("radix parent block blkno %llu\n", le64_to_cpu(par->blkno)); - print_block_header(&rdx->hdr, SCOUTFS_BLOCK_LG_SIZE); - - prev = 0; - for (i = 0; i < SCOUTFS_RADIX_REFS; i++) { - /* only skip if the next ref is identically full/empty */ - if ((le64_to_cpu(rdx->refs[i].blkno) == 0 || - le64_to_cpu(rdx->refs[i].blkno) == U64_MAX) && - (i + 1) < SCOUTFS_RADIX_REFS && - (le64_to_cpu(rdx->refs[i].blkno) == - le64_to_cpu(rdx->refs[i + 1].blkno))) { - prev++; - continue; - } - - if (prev) { - printf(" [%u - %u]: (%s): ", i - prev, i, - (le64_to_cpu(rdx->refs[i].blkno) == 0) ? "empty" : - "full"); - prev = 0; - } else { - printf(" [%u]: ", i); - } - - printf(RADREF_F"\n", RADREF_A(&rdx->refs[i])); - } - - ret = 0; - for (i = 0; i < SCOUTFS_RADIX_REFS; i++) { - if (le64_to_cpu(rdx->refs[i].blkno) != 0 && - le64_to_cpu(rdx->refs[i].blkno) != U64_MAX) { - err = print_radix_block(fd, &rdx->refs[i], level - 1); - if (err < 0 && ret == 0) - ret = err; - } - } - -out: - free(rdx); - - return ret; + next = lblk->next; + free(lblk); + return print_alloc_list_block(fd, str, &next); } static int print_srch_block(int fd, struct scoutfs_srch_ref *ref, int level) @@ -718,20 +683,20 @@ static int print_log_trees_roots(struct scoutfs_key *key, void *val, /* XXX doesn't print the bloom block */ - err = print_radix_block(pa->fd, <v->meta_avail.ref, - ltv->meta_avail.height - 1); + err = print_alloc_list_block(pa->fd, "ltv_meta_avail", + <v->meta_avail.ref); if (err && !ret) ret = err; - err = print_radix_block(pa->fd, <v->meta_freed.ref, - ltv->meta_avail.height - 1); + err = print_alloc_list_block(pa->fd, "ltv_meta_freed", + <v->meta_freed.ref); if (err && !ret) ret = err; - err = print_radix_block(pa->fd, <v->data_avail.ref, - ltv->data_avail.height - 1); + err = print_btree(pa->fd, pa->super, "data_avail", + <v->data_avail.root, print_alloc_item, NULL); if (err && !ret) ret = err; - err = print_radix_block(pa->fd, <v->meta_freed.ref, - ltv->data_avail.height - 1); + err = print_btree(pa->fd, pa->super, "data_freed", + <v->data_freed.root, print_alloc_item, NULL); if (err && !ret) ret = err; err = print_srch_block(pa->fd, <v->srch_file.ref, @@ -917,10 +882,13 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno) " total_data_blocks %llu first_data_blkno %llu last_data_blkno %llu free_data_blocks %llu\n" " quorum_fenced_term %llu quorum_server_term %llu unmount_barrier %llu\n" " quorum_count %u server_addr %s\n" - " core_meta_avail: "RADROOT_F"\n" - " core_meta_freed: "RADROOT_F"\n" - " core_data_avail: "RADROOT_F"\n" - " core_data_freed: "RADROOT_F"\n" + " meta_alloc[0]: "ALCROOT_F"\n" + " meta_alloc[1]: "ALCROOT_F"\n" + " data_alloc: "ALCROOT_F"\n" + " server_meta_avail[0]: "AL_HEAD_F"\n" + " server_meta_avail[1]: "AL_HEAD_F"\n" + " server_meta_freed[0]: "AL_HEAD_F"\n" + " server_meta_freed[1]: "AL_HEAD_F"\n" " lock_clients root: height %u blkno %llu seq %llu\n" " mounted_clients root: height %u blkno %llu seq %llu\n" " srch_root root: height %u blkno %llu seq %llu\n" @@ -941,10 +909,13 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno) le64_to_cpu(super->unmount_barrier), super->quorum_count, server_addr, - RADROOT_A(&super->core_meta_avail), - RADROOT_A(&super->core_meta_freed), - RADROOT_A(&super->core_data_avail), - RADROOT_A(&super->core_data_freed), + ALCROOT_A(&super->meta_alloc[0]), + ALCROOT_A(&super->meta_alloc[1]), + ALCROOT_A(&super->data_alloc), + AL_HEAD_A(&super->server_meta_avail[0]), + AL_HEAD_A(&super->server_meta_avail[1]), + AL_HEAD_A(&super->server_meta_freed[0]), + AL_HEAD_A(&super->server_meta_freed[1]), super->lock_clients.height, le64_to_cpu(super->lock_clients.ref.blkno), le64_to_cpu(super->lock_clients.ref.seq), @@ -968,8 +939,10 @@ static int print_volume(int fd) { struct scoutfs_super_block *super = NULL; struct print_recursion_args pa; + char str[80]; int ret = 0; int err; + int i; super = read_block(fd, SCOUTFS_SUPER_BLKNO, SCOUTFS_BLOCK_SM_SHIFT); if (!super) @@ -994,20 +967,32 @@ static int print_volume(int fd) if (err && !ret) ret = err; - err = print_radix_block(fd, &super->core_meta_avail.ref, - super->core_meta_avail.height - 1); - if (err && !ret) - ret = err; - err = print_radix_block(fd, &super->core_meta_freed.ref, - super->core_meta_freed.height - 1); - if (err && !ret) - ret = err; - err = print_radix_block(fd, &super->core_data_avail.ref, - super->core_data_avail.height - 1); - if (err && !ret) - ret = err; - err = print_radix_block(fd, &super->core_data_freed.ref, - super->core_data_freed.height - 1); + for (i = 0; i < array_size(super->server_meta_avail); i++) { + snprintf(str, sizeof(str), "server_meta_avail[%u]", i); + err = print_alloc_list_block(fd, str, + &super->server_meta_avail[i].ref); + if (err && !ret) + ret = err; + } + + for (i = 0; i < array_size(super->server_meta_freed); i++) { + snprintf(str, sizeof(str), "server_meta_freed[%u]", i); + err = print_alloc_list_block(fd, str, + &super->server_meta_freed[i].ref); + if (err && !ret) + ret = err; + } + + for (i = 0; i < array_size(super->meta_alloc); i++) { + snprintf(str, sizeof(str), "meta_alloc[%u]", i); + err = print_btree(fd, super, str, &super->meta_alloc[i].root, + print_alloc_item, NULL); + if (err && !ret) + ret = err; + } + + err = print_btree(fd, super, "data_alloc", &super->data_alloc.root, + print_alloc_item, NULL); if (err && !ret) ret = err; diff --git a/utils/src/radix.c b/utils/src/radix.c deleted file mode 100644 index 66a400a3..00000000 --- a/utils/src/radix.c +++ /dev/null @@ -1,106 +0,0 @@ -#include - -#include "sparse.h" -#include "util.h" -#include "format.h" -#include "radix.h" - -/* return the height of a tree needed to store the last bit */ -u8 radix_height_from_last(u64 last) -{ - u64 bit = SCOUTFS_RADIX_BITS - 1; - u64 mult = SCOUTFS_RADIX_BITS; - int i; - - for (i = 1; i <= U8_MAX; i++) { - if (bit >= last) - return i; - bit += (u64)(SCOUTFS_RADIX_REFS - 1) * mult; - mult *= SCOUTFS_RADIX_REFS; - } - - return U8_MAX; -} - -u64 radix_full_subtree_total(int level) -{ - u64 total = SCOUTFS_RADIX_BITS; - int i; - - for (i = 1; i <= level; i++) - total *= SCOUTFS_RADIX_REFS; - - return total; -} - -/* - * Initialize a reference to a block at the given level. - */ -void radix_init_ref(struct scoutfs_radix_ref *ref, int level, bool full) -{ - u64 tot; - - if (full) { - tot = radix_full_subtree_total(level); - - ref->blkno = cpu_to_le64(U64_MAX); - ref->seq = cpu_to_le64(0); - ref->sm_total = cpu_to_le64(tot); - ref->lg_total = cpu_to_le64(tot); - } else { - ref->blkno = cpu_to_le64(0); - ref->seq = cpu_to_le64(0); - ref->sm_total = cpu_to_le64(0); - ref->lg_total = cpu_to_le64(0); - } -} - -void radix_calc_level_inds(int *inds, u8 height, u64 bit) -{ - u32 ind; - int i; - - ind = bit % SCOUTFS_RADIX_BITS; - bit = bit / SCOUTFS_RADIX_BITS; - inds[0] = ind; - - for (i = 1; i < height; i++) { - ind = bit % SCOUTFS_RADIX_REFS; - bit = bit / SCOUTFS_RADIX_REFS; - inds[i] = ind; - } -} - -u64 radix_calc_leaf_bit(u64 bit) -{ - return bit - (bit % SCOUTFS_RADIX_BITS); -} - -/* - * The number of blocks needed to initialize a radix with left and right - * paths. The first time we find a level where the parent refs are at - * different indices determines where the paths diverge at lower levels. - * If the refs never diverge then the two paths traverse the same blocks - * and we just need blocks for the height of the tree. - */ -int radix_blocks_needed(u64 a, u64 b) -{ - u8 height = radix_height_from_last(b); - int *a_inds; - int *b_inds; - int i; - - a_inds = alloca(sizeof(a_inds[0] * height)); - b_inds = alloca(sizeof(b_inds[0] * height)); - - radix_calc_level_inds(a_inds, height, a); - radix_calc_level_inds(b_inds, height, b); - - for (i = height - 1; i > 0; i--) { - if (a_inds[i] != b_inds[i]) { - return (i * 2) + (height - i); - } - } - - return height; -} diff --git a/utils/src/radix.h b/utils/src/radix.h deleted file mode 100644 index 31f4db8c..00000000 --- a/utils/src/radix.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _RADIX_H_ -#define _RADIX_H_ - -#include - -u8 radix_height_from_last(u64 last); -u64 radix_full_subtree_total(int level); -void radix_init_ref(struct scoutfs_radix_ref *ref, int level, bool full); -void radix_calc_level_inds(int *inds, u8 height, u64 bit); -u64 radix_calc_leaf_bit(u64 bit); -int radix_blocks_needed(u64 a, u64 b); - -#endif