mirror of
https://github.com/versity/scoutfs.git
synced 2026-07-29 19:43:13 +00:00
scoutfs-utils: alloc and data uses full extents
Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+87
-21
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user