mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-15 19:56:36 +00:00
scoutfs-utils: support server extent allocation
Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+18
-26
@@ -236,17 +236,17 @@ struct scoutfs_manifest_btree_val {
|
||||
struct scoutfs_key last_key;
|
||||
} __packed;
|
||||
|
||||
#define SCOUTFS_ALLOC_REGION_SHIFT 8
|
||||
#define SCOUTFS_ALLOC_REGION_BITS (1 << SCOUTFS_ALLOC_REGION_SHIFT)
|
||||
#define SCOUTFS_ALLOC_REGION_MASK (SCOUTFS_ALLOC_REGION_BITS - 1)
|
||||
|
||||
struct scoutfs_alloc_region_btree_key {
|
||||
__be64 index;
|
||||
} __packed;
|
||||
|
||||
/* The bits need to be aligned so that the hosts can use native long bit ops */
|
||||
struct scoutfs_alloc_region_btree_val {
|
||||
__le64 bits[SCOUTFS_ALLOC_REGION_BITS / 64];
|
||||
/*
|
||||
* Free extents are stored in the server in an allocation btree. The
|
||||
* type differentiates whether start or length is in stored in the major
|
||||
* value and is the primary sort key. 'start' is set to the final block
|
||||
* in the extent so that overlaping queries can be done with next
|
||||
* instead prev.
|
||||
*/
|
||||
struct scoutfs_extent_btree_key {
|
||||
__u8 type;
|
||||
__be64 major;
|
||||
__be64 minor;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
@@ -303,7 +303,7 @@ struct scoutfs_segment_block {
|
||||
#define SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE 2
|
||||
#define SCOUTFS_INODE_INDEX_NR 3 /* don't forget to update */
|
||||
|
||||
/* node zone */
|
||||
/* node zone (also used in server alloc btree) */
|
||||
#define SCOUTFS_FREE_EXTENT_BLKNO_TYPE 1
|
||||
#define SCOUTFS_FREE_EXTENT_BLOCKS_TYPE 2
|
||||
|
||||
@@ -367,9 +367,9 @@ struct scoutfs_super_block {
|
||||
__u8 uuid[SCOUTFS_UUID_BYTES];
|
||||
__le64 next_ino;
|
||||
__le64 next_seq;
|
||||
__le64 alloc_uninit;
|
||||
__le64 total_segs;
|
||||
__le64 free_segs;
|
||||
__le64 total_blocks;
|
||||
__le64 free_blocks;
|
||||
__le64 alloc_cursor;
|
||||
struct scoutfs_btree_ring bring;
|
||||
__le64 next_seg_seq;
|
||||
struct scoutfs_btree_root alloc_root;
|
||||
@@ -555,18 +555,10 @@ struct scoutfs_net_manifest_entry {
|
||||
__u8 keys[0];
|
||||
} __packed;
|
||||
|
||||
/* XXX I dunno, totally made up */
|
||||
#define SCOUTFS_BULK_ALLOC_COUNT 32
|
||||
|
||||
struct scoutfs_net_segnos {
|
||||
__le16 nr;
|
||||
__le64 segnos[0];
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_net_statfs {
|
||||
__le64 total_segs; /* total segments in device */
|
||||
__le64 total_blocks; /* total blocks in device */
|
||||
__le64 next_ino; /* next unused inode number */
|
||||
__le64 bfree; /* total free small blocks */
|
||||
__le64 bfree; /* free blocks */
|
||||
__u8 uuid[SCOUTFS_UUID_BYTES]; /* logical volume uuid */
|
||||
} __packed;
|
||||
|
||||
@@ -582,9 +574,9 @@ struct scoutfs_net_statfs {
|
||||
|
||||
enum {
|
||||
SCOUTFS_NET_ALLOC_INODES = 0,
|
||||
SCOUTFS_NET_ALLOC_EXTENT,
|
||||
SCOUTFS_NET_ALLOC_SEGNO,
|
||||
SCOUTFS_NET_RECORD_SEGMENT,
|
||||
SCOUTFS_NET_BULK_ALLOC,
|
||||
SCOUTFS_NET_ADVANCE_SEQ,
|
||||
SCOUTFS_NET_GET_LAST_SEQ,
|
||||
SCOUTFS_NET_GET_MANIFEST_ROOT,
|
||||
|
||||
+73
-21
@@ -9,6 +9,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sparse.h"
|
||||
#include "cmd.h"
|
||||
@@ -94,20 +95,27 @@ static u64 calc_btree_blocks(u64 nr, u64 max_key, u64 max_val)
|
||||
|
||||
/*
|
||||
* Figure out how many btree ring blocks we'll need for all the btree
|
||||
* items that could be needed to describe this many segments. The
|
||||
* allocator regions are nice and dense but the manifest entries can be
|
||||
* absolutely enormous.
|
||||
* items that could be needed to describe this many segments.
|
||||
*
|
||||
* We can have either a free extent or manifest ref for every segment in
|
||||
* the system. Free extent items are smaller than manifest refs, and
|
||||
* they merge if they're adjacent, so the largest possible tree is a ref
|
||||
* for every segment.
|
||||
*/
|
||||
static u64 calc_btree_ring_blocks(u64 total_segs)
|
||||
{
|
||||
u64 blocks;
|
||||
|
||||
blocks = calc_btree_blocks(DIV_ROUND_UP(total_segs,
|
||||
SCOUTFS_ALLOC_REGION_BITS),
|
||||
sizeof(struct scoutfs_alloc_region_btree_key),
|
||||
sizeof(struct scoutfs_alloc_region_btree_val));
|
||||
/* key is smaller for wider parent fanout */
|
||||
assert(sizeof(struct scoutfs_extent_btree_key) <=
|
||||
sizeof(struct scoutfs_manifest_btree_key));
|
||||
|
||||
blocks += calc_btree_blocks(total_segs,
|
||||
/* 2 extent items is smaller than a manifest ref */
|
||||
assert((2 * sizeof(struct scoutfs_extent_btree_key)) <=
|
||||
(sizeof(struct scoutfs_manifest_btree_key) +
|
||||
sizeof(struct scoutfs_manifest_btree_val)));
|
||||
|
||||
blocks = calc_btree_blocks(total_segs,
|
||||
sizeof(struct scoutfs_manifest_btree_key),
|
||||
sizeof(struct scoutfs_manifest_btree_val));
|
||||
|
||||
@@ -158,6 +166,7 @@ static int write_new_fs(char *path, int fd)
|
||||
struct scoutfs_segment_block *sblk;
|
||||
struct scoutfs_manifest_btree_key *mkey;
|
||||
struct scoutfs_manifest_btree_val *mval;
|
||||
struct scoutfs_extent_btree_key *ebk;
|
||||
struct scoutfs_btree_block *bt;
|
||||
struct scoutfs_btree_item *btitem;
|
||||
struct scoutfs_segment_item *item;
|
||||
@@ -170,7 +179,10 @@ static int write_new_fs(char *path, int fd)
|
||||
u64 size;
|
||||
u64 ring_blocks;
|
||||
u64 total_segs;
|
||||
u64 total_blocks;
|
||||
u64 first_segno;
|
||||
u64 free_start;
|
||||
u64 free_len;
|
||||
int ret;
|
||||
u64 i;
|
||||
|
||||
@@ -202,6 +214,7 @@ static int write_new_fs(char *path, int fd)
|
||||
}
|
||||
|
||||
total_segs = size / SCOUTFS_SEGMENT_SIZE;
|
||||
total_blocks = size / SCOUTFS_BLOCK_SIZE;
|
||||
|
||||
/* partially initialize the super so we can use it to init others */
|
||||
memset(super, 0, SCOUTFS_BLOCK_SIZE);
|
||||
@@ -212,7 +225,7 @@ static int write_new_fs(char *path, int fd)
|
||||
uuid_generate(super->uuid);
|
||||
super->next_ino = cpu_to_le64(SCOUTFS_ROOT_INO + 1);
|
||||
super->next_seq = cpu_to_le64(1);
|
||||
super->total_segs = cpu_to_le64(total_segs);
|
||||
super->total_blocks = cpu_to_le64(total_blocks);
|
||||
super->next_seg_seq = cpu_to_le64(2);
|
||||
|
||||
/* align the btree ring to the segment after the supers */
|
||||
@@ -221,16 +234,57 @@ static int write_new_fs(char *path, int fd)
|
||||
/* first usable segno follows manifest ring */
|
||||
ring_blocks = calc_btree_ring_blocks(total_segs);
|
||||
first_segno = (blkno + ring_blocks) / SCOUTFS_SEGMENT_BLOCKS;
|
||||
free_start = ((first_segno + 1) << SCOUTFS_SEGMENT_BLOCK_SHIFT);
|
||||
free_len = total_blocks - free_start;
|
||||
|
||||
super->free_blocks = cpu_to_le64(free_len);
|
||||
super->bring.first_blkno = cpu_to_le64(blkno);
|
||||
super->bring.nr_blocks = cpu_to_le64(ring_blocks);
|
||||
super->bring.next_block = cpu_to_le64(1);
|
||||
super->bring.next_block = cpu_to_le64(2);
|
||||
super->bring.next_seq = cpu_to_le64(2);
|
||||
|
||||
/* allocator btree is empty, allocations start from super fields */
|
||||
super->alloc_root.ref.blkno = cpu_to_le64(0);
|
||||
super->alloc_root.ref.seq = cpu_to_le64(0);
|
||||
super->alloc_root.height = 0;
|
||||
/* allocator btree has item with space after first segno */
|
||||
super->alloc_root.ref.blkno = cpu_to_le64(blkno);
|
||||
super->alloc_root.ref.seq = cpu_to_le64(1);
|
||||
super->alloc_root.height = 1;
|
||||
|
||||
memset(bt, 0, SCOUTFS_BLOCK_SIZE);
|
||||
bt->fsid = super->hdr.fsid;
|
||||
bt->blkno = cpu_to_le64(blkno);
|
||||
bt->seq = cpu_to_le64(1);
|
||||
bt->nr_items = cpu_to_le16(2);
|
||||
|
||||
/* btree item allocated from the back of the block */
|
||||
ebk = (void *)bt + SCOUTFS_BLOCK_SIZE - sizeof(*ebk);
|
||||
btitem = (void *)ebk - sizeof(*btitem);
|
||||
|
||||
bt->item_hdrs[0].off = cpu_to_le16((long)btitem - (long)bt);
|
||||
bt->free_end = bt->item_hdrs[0].off;
|
||||
btitem->key_len = cpu_to_le16(sizeof(*ebk));
|
||||
btitem->val_len = cpu_to_le16(0);
|
||||
|
||||
ebk->type = SCOUTFS_FREE_EXTENT_BLKNO_TYPE;
|
||||
ebk->major = cpu_to_be64(free_start + free_len - 1);
|
||||
ebk->minor = cpu_to_be64(free_len);
|
||||
|
||||
ebk = (void *)btitem - sizeof(*ebk);
|
||||
btitem = (void *)ebk - sizeof(*btitem);
|
||||
|
||||
bt->item_hdrs[1].off = cpu_to_le16((long)btitem - (long)bt);
|
||||
bt->free_end = bt->item_hdrs[1].off;
|
||||
btitem->key_len = cpu_to_le16(sizeof(*ebk));
|
||||
btitem->val_len = cpu_to_le16(0);
|
||||
|
||||
ebk->type = SCOUTFS_FREE_EXTENT_BLOCKS_TYPE;
|
||||
ebk->major = cpu_to_be64(free_len);
|
||||
ebk->minor = cpu_to_be64(free_start + free_len - 1);
|
||||
|
||||
bt->crc = cpu_to_le32(crc_btree_block(bt));
|
||||
|
||||
ret = write_raw_block(fd, blkno, bt);
|
||||
if (ret)
|
||||
goto out;
|
||||
blkno++;
|
||||
|
||||
/* manifest btree has a block with an item for the segment */
|
||||
super->manifest.root.ref.blkno = cpu_to_le64(blkno);
|
||||
@@ -276,10 +330,6 @@ static int write_new_fs(char *path, int fd)
|
||||
goto out;
|
||||
blkno += ring_blocks;
|
||||
|
||||
/* alloc from uninit, don't need regions yet */
|
||||
super->alloc_uninit = cpu_to_le64(first_segno + 1);
|
||||
super->free_segs = cpu_to_le64(total_segs - (first_segno + 1));
|
||||
|
||||
/* write seg with root inode */
|
||||
sblk->segno = cpu_to_le64(first_segno);
|
||||
sblk->seq = cpu_to_le64(1);
|
||||
@@ -359,17 +409,19 @@ static int write_new_fs(char *path, int fd)
|
||||
" format hash: %llx\n"
|
||||
" uuid: %s\n"
|
||||
" device bytes: "SIZE_FMT"\n"
|
||||
" device blocks: "SIZE_FMT"\n"
|
||||
" btree ring blocks: "SIZE_FMT"\n"
|
||||
" usable segments: "SIZE_FMT"\n",
|
||||
" free blocks: "SIZE_FMT"\n",
|
||||
path,
|
||||
le64_to_cpu(super->hdr.fsid),
|
||||
le64_to_cpu(super->format_hash),
|
||||
uuid_str,
|
||||
SIZE_ARGS(size, 1),
|
||||
SIZE_ARGS(total_blocks, SCOUTFS_BLOCK_SIZE),
|
||||
SIZE_ARGS(le64_to_cpu(super->bring.nr_blocks),
|
||||
SCOUTFS_BLOCK_SIZE),
|
||||
SIZE_ARGS(le64_to_cpu(super->free_segs) + 1,
|
||||
SCOUTFS_SEGMENT_SIZE));
|
||||
SIZE_ARGS(le64_to_cpu(super->free_blocks),
|
||||
SCOUTFS_BLOCK_SIZE));
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
|
||||
+23
-21
@@ -317,23 +317,24 @@ static int print_manifest_entry(void *key, unsigned key_len, void *val,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_alloc_region(void *key, unsigned key_len, void *val,
|
||||
unsigned val_len, void *arg)
|
||||
static int print_alloc_item(void *key, unsigned key_len, void *val,
|
||||
unsigned val_len, void *arg)
|
||||
{
|
||||
struct scoutfs_alloc_region_btree_key *reg_key = key;
|
||||
struct scoutfs_alloc_region_btree_val *reg_val = val;
|
||||
int i;
|
||||
struct scoutfs_extent_btree_key *ebk = key;
|
||||
u64 start;
|
||||
u64 len;
|
||||
|
||||
/* XXX check sizes */
|
||||
|
||||
printf(" index %llu bits", be64_to_cpu(reg_key->index));
|
||||
len = be64_to_cpu(ebk->minor);
|
||||
start = be64_to_cpu(ebk->major);
|
||||
if (ebk->type == SCOUTFS_FREE_EXTENT_BLOCKS_TYPE)
|
||||
swap(start, len);
|
||||
start -= len - 1;
|
||||
|
||||
if (val == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < array_size(reg_val->bits); i++)
|
||||
printf(" %016llx", le64_to_cpu(reg_val->bits[i]));
|
||||
printf("\n");
|
||||
printf(" type %u major %llu minor %llu (start %llu len %llu)\n",
|
||||
ebk->type, be64_to_cpu(ebk->major),
|
||||
be64_to_cpu(ebk->minor), start, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -456,7 +457,7 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno)
|
||||
|
||||
/* XXX these are all in a crazy order */
|
||||
printf(" next_ino %llu next_seq %llu next_seg_seq %llu\n"
|
||||
" alloc_uninit %llu total_segs %llu free_segs %llu\n"
|
||||
" total_blocks %llu free_blocks %llu alloc_cursor %llu\n"
|
||||
" btree ring: first_blkno %llu nr_blocks %llu next_block %llu "
|
||||
"next_seq %llu\n"
|
||||
" alloc btree root: height %u blkno %llu seq %llu mig_len %u\n"
|
||||
@@ -464,9 +465,9 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno)
|
||||
le64_to_cpu(super->next_ino),
|
||||
le64_to_cpu(super->next_seq),
|
||||
le64_to_cpu(super->next_seg_seq),
|
||||
le64_to_cpu(super->alloc_uninit),
|
||||
le64_to_cpu(super->total_segs),
|
||||
le64_to_cpu(super->free_segs),
|
||||
le64_to_cpu(super->total_blocks),
|
||||
le64_to_cpu(super->free_blocks),
|
||||
le64_to_cpu(super->alloc_cursor),
|
||||
le64_to_cpu(super->bring.first_blkno),
|
||||
le64_to_cpu(super->bring.nr_blocks),
|
||||
le64_to_cpu(super->bring.next_block),
|
||||
@@ -494,6 +495,7 @@ static int print_super_blocks(int fd)
|
||||
struct scoutfs_super_block *super;
|
||||
struct scoutfs_super_block recent = { .hdr.seq = 0 };
|
||||
unsigned long *seg_map;
|
||||
u64 nr_segs;
|
||||
int ret = 0;
|
||||
int err;
|
||||
int i;
|
||||
@@ -516,24 +518,24 @@ static int print_super_blocks(int fd)
|
||||
|
||||
print_super_block(super, SCOUTFS_SUPER_BLKNO + r);
|
||||
|
||||
seg_map = alloc_bits(le64_to_cpu(super->total_segs));
|
||||
nr_segs = le64_to_cpu(super->total_blocks) / SCOUTFS_SEGMENT_BLOCKS;
|
||||
seg_map = alloc_bits(nr_segs);
|
||||
if (!seg_map) {
|
||||
ret = -ENOMEM;
|
||||
fprintf(stderr, "failed to alloc %llu seg map: %s (%d)\n",
|
||||
le64_to_cpu(super->total_segs),
|
||||
strerror(errno), errno);
|
||||
nr_segs, strerror(errno), errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = print_btree(fd, super, "alloc", &super->alloc_root,
|
||||
print_alloc_region, NULL);
|
||||
print_alloc_item, NULL);
|
||||
|
||||
err = print_btree(fd, super, "manifest", &super->manifest.root,
|
||||
print_manifest_entry, seg_map);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
err = print_segments(fd, seg_map, le64_to_cpu(super->total_segs));
|
||||
err = print_segments(fd, seg_map, nr_segs);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user