Get rid of bricks

Get rid of the explicit distinction between brick and block numbers.
The format is now defined it terms of fixed 4k blocks.  Logs become a
logical structure that's made up of a fixed number of blocks.  The
allocator still manages large log sized regions.
This commit is contained in:
Zach Brown
2016-02-19 15:40:04 -08:00
parent a7b8f955fe
commit de1bf39614
5 changed files with 240 additions and 276 deletions

View File

@@ -32,8 +32,8 @@ u64 crc32c_64(u32 crc, const void *data, unsigned int len)
crc32c(~crc, data + len - half, half);
}
u32 crc_header(struct scoutfs_header *hdr, size_t size)
u32 crc_block(struct scoutfs_block_header *hdr)
{
return crc32c(~0, (char *)hdr + sizeof(hdr->crc),
size - sizeof(hdr->crc));
SCOUTFS_BLOCK_SIZE - sizeof(hdr->crc));
}

View File

@@ -7,6 +7,6 @@
u32 crc32c(u32 crc, const void *data, unsigned int len);
u64 crc32c_64(u32 crc, const void *data, unsigned int len);
u32 crc_header(struct scoutfs_header *hdr, size_t size);
u32 crc_block(struct scoutfs_block_header *hdr);
#endif

View File

@@ -7,53 +7,66 @@
#define SCOUTFS_SUPER_ID 0x2e736674756f6373ULL /* "scoutfs." */
/*
* Some fs structures are stored in smaller fixed size 4k bricks.
* Structures are stored and referenced in fixed 4k chunks to
* simplify block buffer access at run time.
*/
#define SCOUTFS_BRICK_SHIFT 12
#define SCOUTFS_BRICK_SIZE (1 << SCOUTFS_BRICK_SHIFT)
/*
* A large block size reduces the amount of per-block overhead throughout
* the system: block IO, manifest communications and storage, etc.
*/
#define SCOUTFS_BLOCK_SHIFT 22
#define SCOUTFS_BLOCK_SHIFT 12
#define SCOUTFS_BLOCK_SIZE (1 << SCOUTFS_BLOCK_SHIFT)
/* for shifting between brick and block numbers */
#define SCOUTFS_BLOCK_BRICK (SCOUTFS_BLOCK_SHIFT - SCOUTFS_BRICK_SHIFT)
/*
* Logs are a logical structure that is made up of a fixed number of
* contiguously allocated blocks.
*
* The allocator manages log-sized regions. Smaller metadata blocks
* like the ring and super blocks are stored inside large log
* allocations.
*/
#define SCOUTFS_LOG_SHIFT 22
#define SCOUTFS_LOG_SIZE (1 << SCOUTFS_LOG_SHIFT)
#define SCOUTFS_LOG_BLOCK_SHIFT (SCOUTFS_LOG_SHIFT - SCOUTFS_BLOCK_SHIFT)
#define SCOUTFS_BLOCKS_PER_LOG (1 << SCOUTFS_LOG_BLOCK_SHIFT)
/*
* The super bricks leave a bunch of room at the start of the first
* block for platform structures like boot loaders.
* The super blocks leave some room at the start of the first block for
* platform structures like boot loaders.
*/
#define SCOUTFS_SUPER_BRICK 16
#define SCOUTFS_SUPER_BLKNO ((64 * 1024) >> SCOUTFS_BLOCK_SHIFT)
#define SCOUTFS_SUPER_NR 2
/*
* This header is found at the start of every brick and block
* so that we can verify that it's what we were looking for.
* This header is found at the start of every block so that we can
* verify that it's what we were looking for. The crc and padding
* starts the block so that its calculation operations on a nice 64bit
* aligned region.
*/
struct scoutfs_header {
struct scoutfs_block_header {
__le32 crc;
__le32 _pad;
__le64 fsid;
__le64 seq;
__le64 nr;
__le64 blkno;
} __packed;
#define SCOUTFS_UUID_BYTES 16
/*
* The super is stored in a pair of bricks in the first block.
* The super is stored in a pair of blocks in log 0 on the device.
*
* The ring layout blocks describe the location of the ring blocks. The
* ring start and length refers to the logical ring blocks within that
* storage which contain live data.
*/
struct scoutfs_super {
struct scoutfs_header hdr;
struct scoutfs_super_block {
struct scoutfs_block_header hdr;
__le64 id;
__u8 uuid[SCOUTFS_UUID_BYTES];
__le64 total_blocks;
__le64 ring_layout_block;
__le64 total_logs;
__le64 ring_layout_blkno;
__le64 ring_layout_nr_blocks;
__le64 ring_layout_seq;
__le64 last_ring_brick;
__le64 last_ring_seq;
__le64 last_block_seq;
__le64 ring_block;
__le64 ring_nr_blocks;
__le64 ring_seq;
} __packed;
/*
@@ -71,10 +84,10 @@ struct scoutfs_key {
#define SCOUTFS_INODE_KEY 128
#define SCOUTFS_DIRENT_KEY 192
struct scoutfs_ring_layout {
struct scoutfs_header hdr;
struct scoutfs_layout_block {
struct scoutfs_block_header hdr;
__le32 nr_blocks;
__le64 blocks[0];
__le64 blknos[0];
} __packed;
struct scoutfs_ring_entry {
@@ -83,16 +96,16 @@ struct scoutfs_ring_entry {
} __packed;
/*
* Ring blocks are 4k blocks stored inside the large ring blocks
* referenced by the ring descriptor block.
* Ring blocks are 4k blocks stored inside the regions described by the
* ring layout block referenced by the super.
*
* The manifest entries describe the position of a given block in the
* manifest. They're keyed by the block number so that we can log
* movement of a block in the manifest with one log entry and we can log
* deletion with just the block number.
*/
struct scoutfs_ring_brick {
struct scoutfs_header hdr;
struct scoutfs_ring_block {
struct scoutfs_block_header hdr;
__le16 nr_entries;
} __packed;
@@ -108,7 +121,7 @@ enum {
* without the key.
*/
struct scoutfs_ring_remove_manifest {
__le64 block;
__le64 blkno;
} __packed;
/*
@@ -119,7 +132,7 @@ struct scoutfs_ring_remove_manifest {
* blocks when we didn't need to.
*/
struct scoutfs_ring_add_manifest {
__le64 block;
__le64 blkno;
__le64 seq;
__u8 level;
struct scoutfs_key first;
@@ -132,23 +145,15 @@ struct scoutfs_ring_bitmap {
} __packed;
/*
* This bloom size is chosen to have a roughly 1% false positive rate
* for ~90k items which is roughly the worst case for a block full of
* dirents with reasonably small names. Pathologically smaller items
* could be even more dense.
* To start the logs are a trivial single item block. We'll flesh this out
* into larger blocks once the rest of the architecture is in
* place.
*/
#define SCOUTFS_BLOOM_FILTER_BYTES (128 * 1024)
#define SCOUTFS_BLOOM_FILTER_BITS (SCOUTFS_BLOOM_FILTER_BYTES * 8)
#define SCOUTFS_BLOOM_INDEX_BITS (ilog2(SCOUTFS_BLOOM_FILTER_BITS))
#define SCOUTFS_BLOOM_INDEX_MASK ((1 << SCOUTFS_BLOOM_INDEX_BITS) - 1)
#define SCOUTFS_BLOOM_INDEX_NR 7
struct scoutfs_lsm_block {
struct scoutfs_header hdr;
struct scoutfs_item_block {
struct scoutfs_block_header hdr;
struct scoutfs_key first;
struct scoutfs_key last;
__le32 nr_items;
/* u8 bloom[SCOUTFS_BLOOM_BYTES]; */
/* struct scoutfs_item_header items[0] .. */
} __packed;

View File

@@ -17,77 +17,56 @@
#include "crc.h"
#include "rand.h"
/*
* Update the buffer's header and write it out.
* Update the block's header and write it out.
*/
static int write_header(int fd, u64 nr, struct scoutfs_header *hdr, size_t size)
static int write_block(int fd, u64 blkno, struct scoutfs_block_header *hdr)
{
off_t off = nr * size;
ssize_t ret;
hdr->nr = cpu_to_le64(nr);
hdr->crc = cpu_to_le32(crc_header(hdr, size));
hdr->blkno = cpu_to_le64(blkno);
hdr->crc = cpu_to_le32(crc_block(hdr));
ret = pwrite(fd, hdr, size, off);
if (ret != size) {
fprintf(stderr, "write at nr %llu (offset %llu, size %zu) returned %zd: %s (%d)\n",
nr, (long long)off, size, ret, strerror(errno), errno);
ret = pwrite(fd, hdr, SCOUTFS_BLOCK_SIZE, blkno << SCOUTFS_BLOCK_SHIFT);
if (ret != SCOUTFS_BLOCK_SIZE) {
fprintf(stderr, "write to blkno %llu returned %zd: %s (%d)\n",
blkno, ret, strerror(errno), errno);
return -errno;
}
return 0;
}
static int write_brick(int fd, u64 nr, struct scoutfs_header *hdr)
{
return write_header(fd, nr, hdr, SCOUTFS_BRICK_SIZE);
}
static int write_block(int fd, u64 nr, struct scoutfs_header *hdr)
{
return write_header(fd, nr, hdr, SCOUTFS_BLOCK_SIZE);
}
/*
* - config blocks that describe ring
* - ring entries for lots of free blocks
* - manifest that references single block
* - block with inode
*/
/*
* So what does mkfs really need to do?
*
* - super blocks that describe ring log
* - ring log with free bitmap entries
* - ring log with manifest entries
* - single item block with root dir
*/
static int write_new_fs(char *path, int fd)
{
struct scoutfs_super *super;
struct scoutfs_super_block *super;
struct scoutfs_block_header hdr;
struct scoutfs_inode *inode;
struct scoutfs_ring_layout *rlo;
struct scoutfs_ring_brick *ring;
struct scoutfs_layout_block *lout;
struct scoutfs_ring_block *ring;
struct scoutfs_ring_entry *ent;
struct scoutfs_ring_add_manifest *mani;
struct scoutfs_ring_bitmap *bm;
struct scoutfs_lsm_block *lblk;
struct scoutfs_item_block *iblk;
struct scoutfs_item_header *ihdr;
struct scoutfs_key root_key;
struct timeval tv;
char uuid_str[37];
struct stat st;
unsigned int i;
u64 total_blocks;
u64 total_logs;
u64 blkno;
void *buf;
int ret;
gettimeofday(&tv, NULL);
/* crc and blkno written for each write */
hdr._pad = 0;
pseudo_random_bytes(&hdr.fsid, sizeof(hdr.fsid));
hdr.seq = cpu_to_le64(1);
super = malloc(SCOUTFS_BRICK_SIZE);
buf = malloc(SCOUTFS_BLOCK_SIZE);
if (!super || !buf) {
if (!buf) {
ret = -errno;
fprintf(stderr, "failed to allocate a block: %s (%d)\n",
strerror(errno), errno);
@@ -101,75 +80,23 @@ static int write_new_fs(char *path, int fd)
goto out;
}
total_blocks = st.st_size >> SCOUTFS_BLOCK_SHIFT;
total_logs = st.st_size >> SCOUTFS_LOG_SHIFT;
root_key.inode = cpu_to_le64(SCOUTFS_ROOT_INO);
root_key.type = SCOUTFS_INODE_KEY;
root_key.offset = 0;
/* initialize the super */
memset(super, 0, sizeof(struct scoutfs_super));
pseudo_random_bytes(&super->hdr.fsid, sizeof(super->hdr.fsid));
super->hdr.seq = cpu_to_le64(1);
super->id = cpu_to_le64(SCOUTFS_SUPER_ID);
uuid_generate(super->uuid);
super->total_blocks = cpu_to_le64(total_blocks);
super->ring_layout_block = cpu_to_le64(1);
super->ring_layout_seq = cpu_to_le64(1);
super->last_ring_brick = cpu_to_le64(1);
super->last_ring_seq = cpu_to_le64(1);
super->last_block_seq = cpu_to_le64(1);
/* super in log 0, first fs log block in log 1 */
blkno = 1 << SCOUTFS_LOG_BLOCK_SHIFT;
/* the ring has a single block for now */
/* write a single log block with the root inode item */
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
rlo = buf;
rlo->hdr.fsid = super->hdr.fsid;
rlo->hdr.seq = super->ring_layout_seq;
rlo->nr_blocks = cpu_to_le32(1);
rlo->blocks[0] = cpu_to_le64(2);
ret = write_block(fd, 1, &rlo->hdr);
if (ret)
goto out;
/* log the root inode block manifest and free bitmap */
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
ring = buf;
ring->hdr.fsid = super->hdr.fsid;
ring->hdr.seq = super->last_ring_seq;
ring->nr_entries = cpu_to_le16(2);
ent = (void *)(ring + 1);
ent->type = SCOUTFS_RING_ADD_MANIFEST;
ent->len = cpu_to_le16(sizeof(*mani));
mani = (void *)(ent + 1);
mani->block = cpu_to_le64(3);
mani->seq = super->last_block_seq;
mani->level = 0;
mani->first = root_key;
mani->last = root_key;
ent = (void *)(mani + 1);
ent->type = SCOUTFS_RING_BITMAP;
ent->len = cpu_to_le16(sizeof(*bm));
bm = (void *)(ent + 1);
memset(bm->bits, 0xff, sizeof(bm->bits));
/* the first three blocks are allocated */
bm->bits[0] = cpu_to_le64(~7ULL);
bm->bits[1] = cpu_to_le64(~0ULL);
ret = write_brick(fd, 2 << SCOUTFS_BLOCK_BRICK, &ring->hdr);
if (ret)
goto out;
/* write a single lsm block with the root inode item */
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
lblk = buf;
lblk->hdr.fsid = super->hdr.fsid;
lblk->hdr.seq = super->last_block_seq;
lblk->first = root_key;
lblk->last = root_key;
lblk->nr_items = cpu_to_le32(1);
/* XXX set bloom */
ihdr = (void *)((char *)(lblk + 1) + SCOUTFS_BLOOM_FILTER_BYTES);
iblk = buf;
iblk->hdr = hdr;
iblk->first = root_key;
iblk->last = root_key;
iblk->nr_items = cpu_to_le32(1);
ihdr = (void *)(iblk + 1);
ihdr->key = root_key;
ihdr->len = cpu_to_le16(sizeof(struct scoutfs_inode));
inode = (void *)(ihdr + 1);
@@ -182,14 +109,67 @@ static int write_new_fs(char *path, int fd)
inode->mtime.sec = inode->atime.sec;
inode->mtime.nsec = inode->atime.nsec;
ret = write_block(fd, 3, &ring->hdr);
ret = write_block(fd, blkno, &iblk->hdr);
if (ret)
goto out;
/* write the two super bricks */
for (i = 0; i < 2; i++) {
super->hdr.seq = cpu_to_le64(i);
ret = write_brick(fd, SCOUTFS_SUPER_BRICK + i, &super->hdr);
/* write the ring block whose manifest entry references the log block */
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
ring = buf;
ring->hdr = hdr;
ring->nr_entries = cpu_to_le16(2);
ent = (void *)(ring + 1);
ent->type = SCOUTFS_RING_ADD_MANIFEST;
ent->len = cpu_to_le16(sizeof(*mani));
mani = (void *)(ent + 1);
mani->blkno = cpu_to_le64(blkno);
mani->seq = hdr.seq;
mani->level = 0;
mani->first = root_key;
mani->last = root_key;
ent = (void *)(mani + 1);
ent->type = SCOUTFS_RING_BITMAP;
ent->len = cpu_to_le16(sizeof(*bm));
bm = (void *)(ent + 1);
memset(bm->bits, 0xff, sizeof(bm->bits));
/* the first three blocks are allocated */
bm->bits[0] = cpu_to_le64(~7ULL);
bm->bits[1] = cpu_to_le64(~0ULL);
blkno += SCOUTFS_BLOCKS_PER_LOG;
ret = write_block(fd, blkno, &ring->hdr);
if (ret)
goto out;
/* the ring has a single block for now */
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
lout = buf;
lout->hdr = hdr;
lout->nr_blocks = cpu_to_le32(1);
lout->blknos[0] = cpu_to_le64(blkno);
blkno += SCOUTFS_BLOCKS_PER_LOG;
ret = write_block(fd, blkno, &lout->hdr);
if (ret)
goto out;
/* write the two super blocks */
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
super = buf;
super->hdr = hdr;
super->id = cpu_to_le64(SCOUTFS_SUPER_ID);
uuid_generate(super->uuid);
super->total_logs = cpu_to_le64(total_logs);
super->ring_layout_blkno = cpu_to_le64(blkno);
super->ring_layout_nr_blocks = cpu_to_le64(1);
super->ring_layout_seq = hdr.seq;
super->ring_block = cpu_to_le64(0);
super->ring_nr_blocks = cpu_to_le64(1);
super->ring_seq = hdr.seq;
for (i = 0; i < SCOUTFS_SUPER_NR; i++) {
super->hdr.seq = cpu_to_le64(i + 1);
ret = write_block(fd, SCOUTFS_SUPER_BLKNO + i, &super->hdr);
if (ret)
goto out;
}
@@ -204,14 +184,13 @@ static int write_new_fs(char *path, int fd)
uuid_unparse(super->uuid, uuid_str);
printf("Created scoutfs filesystem:\n"
" total blocks: %llu\n"
" total logs: %llu\n"
" fsid: %llx\n"
" uuid: %s\n",
total_blocks, le64_to_cpu(super->hdr.fsid), uuid_str);
total_logs, le64_to_cpu(super->hdr.fsid), uuid_str);
ret = 0;
out:
free(super);
free(buf);
return ret;
}

View File

@@ -22,20 +22,19 @@
#define SKA(k) le64_to_cpu((k)->inode), (k)->type, \
le64_to_cpu((k)->offset)
static void *read_buf(int fd, u64 nr, size_t size)
static void *read_block(int fd, u64 blkno)
{
off_t off = nr * size;
ssize_t ret;
void *buf;
buf = malloc(size);
buf = malloc(SCOUTFS_BLOCK_SIZE);
if (!buf)
return NULL;
ret = pread(fd, buf, size, off);
if (ret != size) {
fprintf(stderr, "read at blkno %llu (offset %llu) returned %zd: %s (%d)\n",
nr, (long long)off, ret, strerror(errno), errno);
ret = pread(fd, buf, SCOUTFS_BLOCK_SIZE, blkno << SCOUTFS_BLOCK_SHIFT);
if (ret != SCOUTFS_BLOCK_SIZE) {
fprintf(stderr, "read blkno %llu returned %zd: %s (%d)\n",
blkno, ret, strerror(errno), errno);
free(buf);
buf = NULL;
}
@@ -43,19 +42,9 @@ static void *read_buf(int fd, u64 nr, size_t size)
return buf;
}
static void *read_brick(int fd, u64 nr)
static void print_block_header(struct scoutfs_block_header *hdr)
{
return read_buf(fd, nr, SCOUTFS_BRICK_SIZE);
}
static void *read_block(int fd, u64 nr)
{
return read_buf(fd, nr, SCOUTFS_BLOCK_SIZE);
}
static void print_header(struct scoutfs_header *hdr, size_t size)
{
u32 crc = crc_header(hdr, size);
u32 crc = crc_block(hdr);
char valid_str[40];
if (crc != le32_to_cpu(hdr->crc))
@@ -67,19 +56,9 @@ static void print_header(struct scoutfs_header *hdr, size_t size)
" crc: %08x %s\n"
" fsid: %llx\n"
" seq: %llu\n"
" nr: %llu\n",
" blkno: %llu\n",
le32_to_cpu(hdr->crc), valid_str, le64_to_cpu(hdr->fsid),
le64_to_cpu(hdr->seq), le64_to_cpu(hdr->nr));
}
static void print_brick_header(struct scoutfs_header *hdr)
{
return print_header(hdr, SCOUTFS_BRICK_SIZE);
}
static void print_block_header(struct scoutfs_header *hdr)
{
return print_header(hdr, SCOUTFS_BLOCK_SIZE);
le64_to_cpu(hdr->seq), le64_to_cpu(hdr->blkno));
}
static void print_inode(struct scoutfs_inode *inode)
@@ -108,12 +87,12 @@ static void print_inode(struct scoutfs_inode *inode)
le32_to_cpu(inode->mtime.nsec));
}
static void print_item(struct scoutfs_item_header *ihdr, size_t off)
static void print_item(struct scoutfs_item_header *ihdr)
{
printf(" item: &%zu\n"
printf(" item:\n"
" key: "SKF"\n"
" len: %u\n",
off, SKA(&ihdr->key), le16_to_cpu(ihdr->len));
SKA(&ihdr->key), le16_to_cpu(ihdr->len));
switch(ihdr->key.type) {
case SCOUTFS_INODE_KEY:
@@ -122,49 +101,49 @@ static void print_item(struct scoutfs_item_header *ihdr, size_t off)
}
}
static int print_block(int fd, u64 nr)
static int print_item_block(int fd, u64 nr)
{
struct scoutfs_item_header *ihdr;
struct scoutfs_lsm_block *lblk;
struct scoutfs_item_block *iblk;
size_t off;
int i;
lblk = read_block(fd, nr);
if (!lblk)
iblk = read_block(fd, nr);
if (!iblk)
return -ENOMEM;
printf("block: &%llu\n", le64_to_cpu(lblk->hdr.nr));
print_block_header(&lblk->hdr);
printf("item block:\n");
print_block_header(&iblk->hdr);
printf(" first: "SKF"\n"
" last: "SKF"\n"
" nr_items: %u\n",
SKA(&lblk->first), SKA(&lblk->last),
le32_to_cpu(lblk->nr_items));
off = (char *)(lblk + 1) - (char *)lblk + SCOUTFS_BLOOM_FILTER_BYTES;
SKA(&iblk->first), SKA(&iblk->last),
le32_to_cpu(iblk->nr_items));
for (i = 0; i < le32_to_cpu(lblk->nr_items); i++) {
ihdr = (void *)((char *)lblk + off);
print_item(ihdr, off);
off = sizeof(struct scoutfs_item_block);
for (i = 0; i < le32_to_cpu(iblk->nr_items); i++) {
ihdr = (void *)((char *)iblk + off);
print_item(ihdr);
off += sizeof(struct scoutfs_item_header) +
le16_to_cpu(ihdr->len);
}
free(lblk);
free(iblk);
return 0;
}
static int print_blocks(int fd, __le64 *live_blocks, u64 total_blocks)
static int print_log_blocks(int fd, __le64 *live_logs, u64 total_logs)
{
int ret = 0;
int err;
s64 nr;
while ((nr = find_first_le_bit(live_blocks, total_blocks)) >= 0) {
clear_le_bit(live_blocks, nr);
while ((nr = find_first_le_bit(live_logs, total_logs)) >= 0) {
clear_le_bit(live_logs, nr);
err = print_block(fd, nr);
err = print_item_block(fd, nr << SCOUTFS_LOG_BLOCK_SHIFT);
if (!ret && err)
ret = err;
}
@@ -186,32 +165,31 @@ static char *ent_type_str(u8 type)
}
}
static void print_ring_entry(int fd, struct scoutfs_ring_entry *ent,
size_t off)
static void print_ring_entry(int fd, struct scoutfs_ring_entry *ent)
{
struct scoutfs_ring_remove_manifest *rem;
struct scoutfs_ring_add_manifest *add;
struct scoutfs_ring_bitmap *bm;
printf(" entry: &%zu\n"
printf(" entry:\n"
" type: %u # %s\n"
" len: %u\n",
off, ent->type, ent_type_str(ent->type), le16_to_cpu(ent->len));
ent->type, ent_type_str(ent->type), le16_to_cpu(ent->len));
switch(ent->type) {
case SCOUTFS_RING_REMOVE_MANIFEST:
rem = (void *)(ent + 1);
printf(" block: %llu\n",
le64_to_cpu(rem->block));
printf(" blkno: %llu\n",
le64_to_cpu(rem->blkno));
break;
case SCOUTFS_RING_ADD_MANIFEST:
add = (void *)(ent + 1);
printf(" block: %llu\n"
printf(" blkno: %llu\n"
" seq: %llu\n"
" level: %u\n"
" first: "SKF"\n"
" last: "SKF"\n",
le64_to_cpu(add->block), le64_to_cpu(add->seq),
le64_to_cpu(add->blkno), le64_to_cpu(add->seq),
add->level, SKA(&add->first), SKA(&add->last));
break;
case SCOUTFS_RING_BITMAP:
@@ -224,51 +202,51 @@ static void print_ring_entry(int fd, struct scoutfs_ring_entry *ent,
}
}
static void update_live_blocks(struct scoutfs_ring_entry *ent,
__le64 *live_blocks)
static void update_live_logs(struct scoutfs_ring_entry *ent,
__le64 *live_logs)
{
struct scoutfs_ring_remove_manifest *rem;
struct scoutfs_ring_add_manifest *add;
u64 bit;
switch(ent->type) {
case SCOUTFS_RING_REMOVE_MANIFEST:
rem = (void *)(ent + 1);
clear_le_bit(live_blocks, le64_to_cpu(rem->block));
bit = le64_to_cpu(rem->blkno) >> SCOUTFS_LOG_BLOCK_SHIFT;
clear_le_bit(live_logs, bit);
break;
case SCOUTFS_RING_ADD_MANIFEST:
add = (void *)(ent + 1);
set_le_bit(live_blocks, le64_to_cpu(add->block));
bit = le64_to_cpu(add->blkno) >> SCOUTFS_LOG_BLOCK_SHIFT;
set_le_bit(live_logs, bit);
break;
}
}
static int print_ring_block(int fd, u64 block_nr, __le64 *live_blocks)
static int print_ring_block(int fd, u64 blkno, __le64 *live_logs)
{
struct scoutfs_ring_brick *ring;
struct scoutfs_ring_block *ring;
struct scoutfs_ring_entry *ent;
size_t off;
int ret = 0;
u64 nr;
int i;
/* XXX just printing the first brick for now */
/* XXX just printing the first block for now */
nr = block_nr << SCOUTFS_BLOCK_BRICK;
ring = read_brick(fd, nr);
ring = read_block(fd, blkno);
if (!ring)
return -ENOMEM;
printf("ring brick: &%llu\n", nr);
print_brick_header(&ring->hdr);
printf("ring block:\n");
print_block_header(&ring->hdr);
printf(" nr_entries: %u\n", le16_to_cpu(ring->nr_entries));
off = sizeof(struct scoutfs_ring_brick);
off = sizeof(struct scoutfs_ring_block);
for (i = 0; i < le16_to_cpu(ring->nr_entries); i++) {
ent = (void *)((char *)ring + off);
update_live_blocks(ent, live_blocks);
print_ring_entry(fd, ent, off);
update_live_logs(ent, live_logs);
print_ring_entry(fd, ent);
off += sizeof(struct scoutfs_ring_entry) +
le16_to_cpu(ent->len);
@@ -278,95 +256,97 @@ static int print_ring_block(int fd, u64 block_nr, __le64 *live_blocks)
return ret;
}
static int print_ring_layout(int fd, u64 blkno, __le64 *live_blocks)
static int print_layout_block(int fd, u64 blkno, __le64 *live_logs)
{
struct scoutfs_ring_layout *rlo;
struct scoutfs_layout_block *lout;
int ret = 0;
int err;
int i;
rlo = read_block(fd, blkno);
if (!rlo)
lout = read_block(fd, blkno);
if (!lout)
return -ENOMEM;
printf("ring layout: &%llu\n", blkno);
print_block_header(&rlo->hdr);
printf(" nr_blocks: %u\n", le32_to_cpu(rlo->nr_blocks));
printf("layout block:\n");
print_block_header(&lout->hdr);
printf(" nr_blocks: %u\n", le32_to_cpu(lout->nr_blocks));
printf(" blocks: ");
for (i = 0; i < le32_to_cpu(rlo->nr_blocks); i++)
printf(" %llu\n", le64_to_cpu(rlo->blocks[i]));
printf(" blknos: ");
for (i = 0; i < le32_to_cpu(lout->nr_blocks); i++)
printf(" %llu\n", le64_to_cpu(lout->blknos[i]));
for (i = 0; i < le32_to_cpu(rlo->nr_blocks); i++) {
err = print_ring_block(fd, le64_to_cpu(rlo->blocks[i]),
live_blocks);
for (i = 0; i < le32_to_cpu(lout->nr_blocks); i++) {
err = print_ring_block(fd, le64_to_cpu(lout->blknos[i]),
live_logs);
if (err && !ret)
ret = err;
}
free(rlo);
free(lout);
return 0;
}
static int print_super_brick(int fd)
{
struct scoutfs_super *super;
struct scoutfs_super_block *super;
char uuid_str[37];
__le64 *live_blocks;
u64 total_blocks;
__le64 *live_logs;
u64 total_logs;
size_t bytes;
int ret = 0;
int err;
/* XXX print both */
super = read_brick(fd, SCOUTFS_SUPER_BRICK);
super = read_block(fd, SCOUTFS_SUPER_BLKNO);
if (!super)
return -ENOMEM;
uuid_unparse(super->uuid, uuid_str);
total_blocks = le64_to_cpu(super->total_blocks);
total_logs = le64_to_cpu(super->total_logs);
printf("super: &%llu\n", le64_to_cpu(super->hdr.nr));
print_brick_header(&super->hdr);
printf("super:\n");
print_block_header(&super->hdr);
printf(" id: %llx\n"
" uuid: %s\n"
" total_blocks: %llu\n"
" ring_layout_block: %llu\n"
" total_logs: %llu\n"
" ring_layout_blkno: %llu\n"
" ring_layout_nr_blocks: %llu\n"
" ring_layout_seq: %llu\n"
" last_ring_brick: %llu\n"
" last_ring_seq: %llu\n"
" last_block_seq: %llu\n",
" ring_block: %llu\n"
" ring_seq: %llu\n"
" ring_nr_blocks: %llu\n",
le64_to_cpu(super->id),
uuid_str,
total_blocks,
le64_to_cpu(super->ring_layout_block),
total_logs,
le64_to_cpu(super->ring_layout_blkno),
le64_to_cpu(super->ring_layout_nr_blocks),
le64_to_cpu(super->ring_layout_seq),
le64_to_cpu(super->last_ring_brick),
le64_to_cpu(super->last_ring_seq),
le64_to_cpu(super->last_block_seq));
le64_to_cpu(super->ring_block),
le64_to_cpu(super->ring_nr_blocks),
le64_to_cpu(super->ring_seq));
/* XXX by hand? */
bytes = (total_blocks + 63) / 8;
live_blocks = malloc(bytes);
if (!live_blocks) {
bytes = (total_logs + 63) / 8;
live_logs = malloc(bytes);
if (!live_logs) {
ret = -ENOMEM;
goto out;
}
memset(live_blocks, 0, bytes);
memset(live_logs, 0, bytes);
err = print_ring_layout(fd, le64_to_cpu(super->ring_layout_block),
live_blocks);
err = print_layout_block(fd, le64_to_cpu(super->ring_layout_blkno),
live_logs);
if (err && !ret)
ret = err;
err = print_blocks(fd, live_blocks, total_blocks);
err = print_log_blocks(fd, live_logs, total_logs);
if (err && !ret)
ret = err;
out:
free(super);
free(live_blocks);
free(live_logs);
return ret;
}