scoutfs-utils: alloc and data uses full extents

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2020-10-26 15:19:41 -07:00
committed by Zach Brown
parent d87e2e0166
commit 23711f05f6
5 changed files with 315 additions and 497 deletions
+87 -21
View File
@@ -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;
+79 -193
View File
@@ -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++) {
+149 -164
View File
@@ -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(&ltv->meta_avail),
RADROOT_A(&ltv->meta_freed),
AL_HEAD_A(&ltv->meta_avail),
AL_HEAD_A(&ltv->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(&ltv->data_avail),
RADROOT_A(&ltv->data_freed),
ALCROOT_A(&ltv->data_avail),
ALCROOT_A(&ltv->data_freed),
SRF_A(&ltv->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, &ltv->meta_avail.ref,
ltv->meta_avail.height - 1);
err = print_alloc_list_block(pa->fd, "ltv_meta_avail",
&ltv->meta_avail.ref);
if (err && !ret)
ret = err;
err = print_radix_block(pa->fd, &ltv->meta_freed.ref,
ltv->meta_avail.height - 1);
err = print_alloc_list_block(pa->fd, "ltv_meta_freed",
&ltv->meta_freed.ref);
if (err && !ret)
ret = err;
err = print_radix_block(pa->fd, &ltv->data_avail.ref,
ltv->data_avail.height - 1);
err = print_btree(pa->fd, pa->super, "data_avail",
&ltv->data_avail.root, print_alloc_item, NULL);
if (err && !ret)
ret = err;
err = print_radix_block(pa->fd, &ltv->meta_freed.ref,
ltv->data_avail.height - 1);
err = print_btree(pa->fd, pa->super, "data_freed",
&ltv->data_freed.root, print_alloc_item, NULL);
if (err && !ret)
ret = err;
err = print_srch_block(pa->fd, &ltv->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;
-106
View File
@@ -1,106 +0,0 @@
#include <stdbool.h>
#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;
}
-13
View File
@@ -1,13 +0,0 @@
#ifndef _RADIX_H_
#define _RADIX_H_
#include <stdbool.h>
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