Support simpler ring entries

Add mkfs and print support for the simpler rings that the segment bitmap
allocator and manifest are now using.  Some other recent format header
updates come along for the ride.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2017-04-11 16:09:52 -07:00
parent bd54995599
commit e09a216762
5 changed files with 258 additions and 196 deletions

View File

@@ -38,11 +38,9 @@ u32 crc_block(struct scoutfs_block_header *hdr)
SCOUTFS_BLOCK_SIZE - sizeof(hdr->crc));
}
__le32 crc_node(struct scoutfs_treap_node *node)
u32 crc_ring_block(struct scoutfs_ring_block *rblk)
{
unsigned int skip = sizeof(node->crc);
unsigned int bytes = offsetof(struct scoutfs_treap_node,
data[le16_to_cpu(node->bytes)]);
unsigned long skip = (char *)(&rblk->crc + 1) - (char *)rblk;
return cpu_to_le32(crc32c(~0, (char *)node + skip, bytes - skip));
return crc32c(~0, (char *)rblk + skip, SCOUTFS_BLOCK_SIZE - skip);
}

View File

@@ -8,6 +8,6 @@
u32 crc32c(u32 crc, const void *data, unsigned int len);
u64 crc32c_64(u32 crc, const void *data, unsigned int len);
u32 crc_block(struct scoutfs_block_header *hdr);
__le32 crc_node(struct scoutfs_treap_node *node);
u32 crc_ring_block(struct scoutfs_ring_block *rblk);
#endif

View File

@@ -50,43 +50,30 @@ struct scoutfs_block_header {
__le64 blkno;
} __packed;
struct scoutfs_treap_ref {
__le64 off;
__le64 gen;
__u8 aug_bits;
struct scoutfs_ring_entry {
__le16 data_len;
__u8 flags;
__u8 data[0];
} __packed;
/*
* The lesser and greater bits are persistent on disk so that we can migrate
* nodes from the older half of the ring.
*
* The dirty bit is only used for in-memory nodes.
*/
#define SCOUTFS_TREAP_AUG_LESSER (1 << 0)
#define SCOUTFS_TREAP_AUG_GREATER (1 << 1)
#define SCOUTFS_TREAP_AUG_HALVES (SCOUTFS_TREAP_AUG_LESSER | \
SCOUTFS_TREAP_AUG_GREATER)
#define SCOUTFS_TREAP_AUG_DIRTY (1 << 2)
#define SCOUTFS_RING_ENTRY_FLAG_DELETION (1 << 0)
/*
* Treap nodes are stored at byte offset in the ring of blocks described
* by the super block. Each reference contains the off and gen that it
* will find in the node for verification. Each node has the header
* and data payload covered by a crc.
*/
struct scoutfs_treap_node {
struct scoutfs_ring_block {
__le32 crc;
__le64 off;
__le64 gen;
__le64 prio;
struct scoutfs_treap_ref left;
struct scoutfs_treap_ref right;
__le16 bytes;
u8 data[0];
__le32 pad;
__le64 fsid;
__le64 seq;
__le64 block;
__le32 nr_entries;
struct scoutfs_ring_entry entries[0];
} __packed;
struct scoutfs_treap_root {
struct scoutfs_treap_ref ref;
struct scoutfs_ring_descriptor {
__le64 blkno;
__le64 total_blocks;
__le64 first_block;
__le64 first_seq;
__le64 nr_blocks;
} __packed;
/*
@@ -98,7 +85,7 @@ struct scoutfs_treap_root {
#define SCOUTFS_MANIFEST_FANOUT 10
struct scoutfs_manifest {
struct scoutfs_treap_root root;
struct scoutfs_ring_descriptor ring;
__le64 level_counts[SCOUTFS_MANIFEST_MAX_LEVEL];
} __packed;
@@ -172,7 +159,10 @@ struct scoutfs_segment_block {
#define SCOUTFS_EXTENT_KEY 9
#define SCOUTFS_ORPHAN_KEY 10
#define SCOUTFS_DATA_KEY 11
#define SCOUTFS_MAX_UNUSED_KEY 255
/* not found in the fs */
#define SCOUTFS_MAX_UNUSED_KEY 253
#define SCOUTFS_NET_ADDR_KEY 254
#define SCOUTFS_NET_LISTEN_KEY 255
/* value is struct scoutfs_inode */
struct scoutfs_inode_key {
@@ -243,6 +233,7 @@ struct scoutfs_symlink_key {
#define SCOUTFS_UUID_BYTES 16
/*
* The ring fields describe the statically allocated ring log. The
* head and tail indexes are logical 4k blocks offsets inside the ring.
@@ -261,7 +252,7 @@ struct scoutfs_super_block {
__le64 ring_tail_block;
__le64 ring_gen;
__le64 next_seg_seq;
struct scoutfs_treap_root alloc_treap_root;
struct scoutfs_ring_descriptor alloc_ring;
struct scoutfs_manifest manifest;
} __packed;
@@ -348,4 +339,42 @@ enum {
#define SCOUTFS_MAX_KEY_SIZE \
offsetof(struct scoutfs_link_backref_key, name[SCOUTFS_NAME_LEN + 1])
/*
* messages over the wire.
*/
/* XXX ipv6 */
struct scoutfs_inet_addr {
__le32 addr;
__le16 port;
} __packed;
/*
* This header precedes and describes all network messages sent over
* sockets. The id is set by the request and sent in the reply. The
* type is strictly redundant in the reply because the id will find the
* send but we include it in both packets to make it easier to observe
* replies without having the id from their previous request.
*/
struct scoutfs_net_header {
__le64 id;
__le16 data_len;
__u8 type;
__u8 status;
__u8 data[0];
};
enum {
/* sends and receives a struct scoutfs_timeval */
SCOUTFS_NET_TRADE_TIME = 0,
SCOUTFS_NET_UNKNOWN,
};
enum {
SCOUTFS_NET_STATUS_REQUEST = 0,
SCOUTFS_NET_STATUS_SUCCESS,
SCOUTFS_NET_STATUS_ERROR,
SCOUTFS_NET_STATUS_UNKNOWN,
};
#endif

View File

@@ -47,35 +47,23 @@ static int write_block(int fd, u64 blkno, struct scoutfs_super_block *super,
}
/*
* Figure out how many blocks the ring will need. The ring has to hold:
*
* - manifest entries for every segment with largest keys
* - allocator regions for bits to reference every segment
* - empty space at the end of blocks so nodes don't cross blocks
* - double that to account for repeatedly duplicating entries
* - double that so we can migrate everything before wrapping
* Figure out how many blocks a given ring will need given a max number
* of entries up to a given max size. We figure out how many blocks it
* could take to store these maximal entries given unused tail space and
* block header overheads. Then we (wastefully) multiply by three to
* ensure that the ring won't consume itself as it wraps. The caller
* aligns the ring size to a segment size depending on where it starts.
*/
static u64 calc_ring_blocks(u64 segs)
static u64 calc_ring_blocks(u64 max_nr, u64 max_size)
{
u64 alloc_blocks;
u64 ment_blocks;
u64 block_bytes;
u64 node_bytes;
u64 regions;
node_bytes = sizeof(struct scoutfs_treap_node) +
sizeof(struct scoutfs_manifest_entry) +
(2 * SCOUTFS_MAX_KEY_SIZE);
block_bytes = SCOUTFS_BLOCK_SIZE - (node_bytes - 1);
ment_blocks = DIV_ROUND_UP(segs * node_bytes, block_bytes);
max_size += sizeof(struct scoutfs_ring_entry);
node_bytes = sizeof(struct scoutfs_treap_node) +
sizeof(struct scoutfs_alloc_region);
regions = DIV_ROUND_UP(segs, SCOUTFS_ALLOC_REGION_BITS);
block_bytes = SCOUTFS_BLOCK_SIZE - (node_bytes - 1);
alloc_blocks = DIV_ROUND_UP(regions * node_bytes, block_bytes);
block_bytes = SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_ring_block) -
(max_size - 1);
return ALIGN((ment_blocks + alloc_blocks) * 4, SCOUTFS_SEGMENT_BLOCKS);
return DIV_ROUND_UP(max_nr * max_size, block_bytes) * 3;
}
/*
@@ -92,11 +80,13 @@ static int write_new_fs(char *path, int fd)
struct scoutfs_inode *inode;
struct scoutfs_segment_block *sblk;
struct scoutfs_manifest_entry *ment;
struct scoutfs_treap_node *node;
struct scoutfs_ring_descriptor *rdesc;
struct scoutfs_ring_block *rblk;
struct scoutfs_ring_entry *rent;
struct scoutfs_segment_item *item;
struct timeval tv;
char uuid_str[37];
void *ring;
u64 blkno;
u64 limit;
u64 size;
u64 ring_blocks;
@@ -108,9 +98,9 @@ static int write_new_fs(char *path, int fd)
gettimeofday(&tv, NULL);
super = calloc(1, SCOUTFS_BLOCK_SIZE);
ring = calloc(1, SCOUTFS_BLOCK_SIZE);
rblk = calloc(1, SCOUTFS_BLOCK_SIZE);
sblk = calloc(1, SCOUTFS_SEGMENT_SIZE);
if (!super || !ring || !sblk) {
if (!super || !rblk || !sblk) {
ret = -errno;
fprintf(stderr, "failed to allocate block mem: %s (%d)\n",
strerror(errno), errno);
@@ -133,9 +123,12 @@ static int write_new_fs(char *path, int fd)
}
total_segs = size / SCOUTFS_SEGMENT_SIZE;
ring_blocks = calc_ring_blocks(total_segs);
/* first initialize the super so we can use it to build structures */
/* segments and manifest entries all use single key */
root_ikey.type = SCOUTFS_INODE_KEY;
root_ikey.ino = cpu_to_be64(SCOUTFS_ROOT_INO);
/* partially initialize the super so we can use it to init others */
memset(super, 0, SCOUTFS_BLOCK_SIZE);
pseudo_random_bytes(&super->hdr.fsid, sizeof(super->hdr.fsid));
super->hdr.seq = cpu_to_le64(1);
@@ -143,15 +136,72 @@ static int write_new_fs(char *path, int fd)
uuid_generate(super->uuid);
super->next_ino = cpu_to_le64(SCOUTFS_ROOT_INO + 1);
super->total_segs = cpu_to_le64(total_segs);
super->ring_blkno = cpu_to_le64(SCOUTFS_SUPER_BLKNO + 2);
super->ring_blocks = cpu_to_le64(ring_blocks);
super->ring_tail_block = cpu_to_le64(1);
super->ring_gen = cpu_to_le64(1);
super->next_seg_seq = cpu_to_le64(2);
first_segno = DIV_ROUND_UP(le64_to_cpu(super->ring_blkno) +
le64_to_cpu(super->ring_blocks),
SCOUTFS_SEGMENT_BLOCKS);
/* start writing rings after the super */
blkno = SCOUTFS_SUPER_BLKNO + SCOUTFS_SUPER_NR;
/* allocator ring is empty, allocations start from super fields */
ring_blocks = calc_ring_blocks(DIV_ROUND_UP(total_segs,
SCOUTFS_ALLOC_REGION_BITS),
sizeof(struct scoutfs_alloc_region));
ring_blocks = round_up(blkno + ring_blocks, SCOUTFS_SEGMENT_BLOCKS) -
blkno;
rdesc = &super->alloc_ring;
rdesc->blkno = cpu_to_le64(blkno);
rdesc->total_blocks = cpu_to_le64(ring_blocks);
rdesc->first_block = cpu_to_le64(0);
rdesc->first_seq = cpu_to_le64(0);
rdesc->nr_blocks = cpu_to_le64(0);
blkno += ring_blocks;
/* manifest ring has a block with an entry for the segment */
ring_blocks = calc_ring_blocks(total_segs,
sizeof(struct scoutfs_manifest_entry) +
(2 * SCOUTFS_MAX_KEY_SIZE));
ring_blocks = round_up(ring_blocks, SCOUTFS_SEGMENT_BLOCKS);
/* first usable segno follows manifest ring */
first_segno = (blkno + ring_blocks) / SCOUTFS_SEGMENT_BLOCKS;
super->manifest.level_counts[1] = cpu_to_le64(1);
rdesc = &super->manifest.ring;
rdesc->blkno = cpu_to_le64(blkno);
rdesc->total_blocks = cpu_to_le64(ring_blocks);
rdesc->first_seq = cpu_to_le64(1);
rdesc->nr_blocks = cpu_to_le64(1);
memset(rblk, 0, SCOUTFS_BLOCK_SIZE);
rblk->pad = 0;
rblk->fsid = super->hdr.fsid;
rblk->seq = cpu_to_le64(1);
rblk->block = 0;
rblk->nr_entries = cpu_to_le32(1);
rent = rblk->entries;
rent->flags = 0;
rent->data_len = cpu_to_le16(sizeof(struct scoutfs_manifest_entry) +
(2 * sizeof(struct scoutfs_inode_key)));
ment = (void *)rent->data;
ment->segno = cpu_to_le64(first_segno);
ment->seq = cpu_to_le64(1);
ment->first_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key));
ment->last_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key));
ment->level = 1;
ikey = (void *)ment->keys;
ikey[0] = root_ikey;
ikey[1] = root_ikey;
rblk->crc = cpu_to_le32(crc_ring_block(rblk));
ret = write_raw_block(fd, blkno, rblk);
if (ret)
goto out;
blkno += ring_blocks;
/* alloc from uninit, don't need regions yet */
super->alloc_uninit = cpu_to_le64(first_segno + 1);
@@ -162,9 +212,6 @@ static int write_new_fs(char *path, int fd)
sblk->seq = cpu_to_le64(1);
sblk->nr_items = cpu_to_le32(1);
root_ikey.type = SCOUTFS_INODE_KEY;
root_ikey.ino = cpu_to_be64(SCOUTFS_ROOT_INO);
item = &sblk->items[0];
ikey = (void *)&sblk->items[1];
inode = (void *)(ikey + 1);
@@ -194,35 +241,6 @@ static int write_new_fs(char *path, int fd)
goto out;
}
/* a single manifest entry points to the single segment */
node = ring;
node->off = cpu_to_le64((char *)node - (char *)ring);
node->gen = cpu_to_le64(1);
node->bytes = cpu_to_le16(sizeof(struct scoutfs_manifest_entry) +
(2 * sizeof(struct scoutfs_inode_key)));
pseudo_random_bytes(&node->prio, sizeof(node->prio));
ment = (void *)node->data;
ment->segno = sblk->segno;
ment->seq = cpu_to_le64(1);
ment->first_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key));
ment->last_key_len = cpu_to_le16(sizeof(struct scoutfs_inode_key));
ment->level = 1;
ikey = (void *)ment->keys;
ikey[0] = root_ikey;
ikey[1] = root_ikey;
node->crc = crc_node(node);
super->manifest.root.ref.off = node->off;
super->manifest.root.ref.gen = node->gen;
super->manifest.root.ref.aug_bits = SCOUTFS_TREAP_AUG_LESSER;
super->manifest.level_counts[1] = cpu_to_le64(1);
ret = write_raw_block(fd, le64_to_cpu(super->ring_blkno), ring);
if (ret)
goto out;
/* write the two super blocks */
for (i = 0; i < SCOUTFS_SUPER_NR; i++) {
super->hdr.seq = cpu_to_le64(i + 1);
@@ -242,19 +260,17 @@ static int write_new_fs(char *path, int fd)
uuid_unparse(super->uuid, uuid_str);
printf("Created scoutfs filesystem:\n"
" total segments: %llu\n"
" ring blocks: %llu\n"
" fsid: %llx\n"
" uuid: %s\n",
total_segs, ring_blocks, le64_to_cpu(super->hdr.fsid),
le64_to_cpu(super->hdr.fsid),
uuid_str);
ret = 0;
out:
if (super)
free(super);
if (ring)
free(ring);
if (rblk)
free(rblk);
if (sblk)
free(sblk);
return ret;

View File

@@ -13,6 +13,7 @@
#include "sparse.h"
#include "util.h"
#include "format.h"
#include "bitmap.h"
#include "cmd.h"
#include "crc.h"
@@ -251,81 +252,69 @@ static void print_segment_block(struct scoutfs_segment_block *sblk)
le32_to_cpu(sblk->nr_items));
}
static int print_segment(int fd, struct scoutfs_treap_node *tnode)
static int print_segments(int fd, unsigned long *seg_map, u64 total)
{
struct scoutfs_manifest_entry *ment = (void *)tnode->data;
u64 segno = le64_to_cpu(ment->segno);
struct scoutfs_segment_block *sblk;
int i;
u64 s;
u64 i;
sblk = read_segment(fd, segno);
if (!sblk)
return -ENOMEM;
for (s = 0; (s = find_next_set_bit(seg_map, s, total)) < total; s++) {
sblk = read_segment(fd, s);
if (!sblk)
return -ENOMEM;
printf("segment segno %llu\n", segno);
print_segment_block(sblk);
printf("segment segno %llu\n", s);
print_segment_block(sblk);
for (i = 0; i < le32_to_cpu(sblk->nr_items); i++)
print_item(sblk, i);
for (i = 0; i < le32_to_cpu(sblk->nr_items); i++)
print_item(sblk, i);
free(sblk);
free(sblk);
}
return 0;
}
static void print_treap_ref(struct scoutfs_treap_ref *ref)
static void print_ring_descriptor(struct scoutfs_ring_descriptor *rdesc,
char *which)
{
printf(" off %llu gen %llu aug_bits %x",
le64_to_cpu(ref->off), le64_to_cpu(ref->gen),
ref->aug_bits);
printf(" %s ring:\n blkno %llu total_blocks %llu first_block %llu "
"first_seq %llu nr_blocks %llu\n",
which, le64_to_cpu(rdesc->blkno),
le64_to_cpu(rdesc->total_blocks),
le64_to_cpu(rdesc->first_block),
le64_to_cpu(rdesc->first_seq),
le64_to_cpu(rdesc->nr_blocks));
}
static void print_treap_node(struct scoutfs_treap_node *tnode)
static int print_manifest_entry(int fd, struct scoutfs_ring_entry *rent,
void *arg)
{
char valid_str[40];
__le32 crc;
struct scoutfs_manifest_entry *ment = (void *)rent->data;
unsigned long *seg_map = arg;
crc = crc_node(tnode);
if (crc != tnode->crc)
sprintf(valid_str, "(!= %08x) ", le32_to_cpu(crc));
else
valid_str[0] = '\0';
printf(" node: crc %08x %soff %llu gen %llu bytes %u prio %016llx\n"
" l:",
le32_to_cpu(tnode->crc), valid_str, le64_to_cpu(tnode->off),
le64_to_cpu(tnode->gen), le16_to_cpu(tnode->bytes),
le64_to_cpu(tnode->prio));
print_treap_ref(&tnode->left);
printf(" r:");
print_treap_ref(&tnode->right);
printf("\n");
}
static int print_manifest_entry(int fd, struct scoutfs_treap_node *tnode)
{
struct scoutfs_manifest_entry *ment = (void *)tnode->data;
print_treap_node(tnode);
printf(" ment: segno %llu seq %llu first_len %u last_len %u level %u\n",
printf(" segno %llu seq %llu first_len %u last_len %u level %u\n",
le64_to_cpu(ment->segno),
le64_to_cpu(ment->seq),
le16_to_cpu(ment->first_key_len),
le16_to_cpu(ment->last_key_len),
ment->level);
if (rent->flags & SCOUTFS_RING_ENTRY_FLAG_DELETION)
clear_bit(seg_map, le64_to_cpu(ment->segno));
else
set_bit(seg_map, le64_to_cpu(ment->segno));
return 0;
}
static int print_alloc_region(int fd, struct scoutfs_treap_node *tnode)
static int print_alloc_region(int fd, struct scoutfs_ring_entry *rent,
void *arg)
{
struct scoutfs_alloc_region *reg = (void *)tnode->data;
struct scoutfs_alloc_region *reg = (void *)rent->data;
int i;
print_treap_node(tnode);
printf(" reg: index %llu bits", le64_to_cpu(reg->index));
printf(" index %llu bits", le64_to_cpu(reg->index));
for (i = 0; i < array_size(reg->bits); i++)
printf(" %016llx", le64_to_cpu(reg->bits[i]));
printf("\n");
@@ -333,43 +322,68 @@ static int print_alloc_region(int fd, struct scoutfs_treap_node *tnode)
return 0;
}
typedef int (*tnode_func)(int fd, struct scoutfs_treap_node *tnode);
typedef int (*rent_func)(int fd, struct scoutfs_ring_entry *rent, void *arg);
static int walk_treap(int fd, struct scoutfs_super_block *super,
struct scoutfs_treap_ref *ref, tnode_func func)
static int print_ring(int fd, struct scoutfs_super_block *super,
char *which, struct scoutfs_ring_descriptor *rdesc,
rent_func func, void *arg)
{
struct scoutfs_treap_node *tnode;
struct scoutfs_ring_block *rblk;
struct scoutfs_ring_entry *rent;
u64 block;
u64 blkno;
void *blk;
u64 off;
int ret;
u64 i;
u32 e;
if (!ref->gen)
return 0;
block = le64_to_cpu(rdesc->first_block);
for (i = 0; i < le64_to_cpu(rdesc->nr_blocks); i++) {
blkno = le64_to_cpu(rdesc->blkno) + block;
off = le64_to_cpu(ref->off);
blkno = le64_to_cpu(super->ring_blkno) + (off >> SCOUTFS_BLOCK_SHIFT);
rblk = read_block(fd, blkno);
if (!rblk)
return -ENOMEM;
blk = read_block(fd, blkno);
if (!blk)
return -ENOMEM;
printf("%s ring blkno %llu\n"
" crc %08x fsid %llx seq %llu block %llu "
"nr_entries %u\n",
which, blkno, le32_to_cpu(rblk->crc),
le64_to_cpu(rblk->fsid),
le64_to_cpu(rblk->seq),
le64_to_cpu(rblk->block),
le32_to_cpu(rblk->nr_entries));
tnode = blk + (off & SCOUTFS_BLOCK_MASK);
rent = rblk->entries;
for (e = 0; e < le32_to_cpu(rblk->nr_entries); e++) {
ret = func(fd, tnode);
if (ret == 0)
ret = walk_treap(fd, super, &tnode->left, func) ?:
walk_treap(fd, super, &tnode->right, func);
printf(" entry [%u] off %lu data_len %u flags %x\n",
e, (char *)rent - (char *)rblk->entries,
le16_to_cpu(rent->data_len), rent->flags);
free(blk);
ret = func(fd, rent, arg);
if (ret) {
free(rblk);
return ret;
}
return ret;
rent = (void *)&rent->data[le16_to_cpu(rent->data_len)];
}
block++;
if (block == le64_to_cpu(rdesc->total_blocks))
block = 0;
free(rblk);
}
return 0;
}
static int print_super_blocks(int fd)
{
struct scoutfs_super_block *super;
struct scoutfs_super_block recent = { .hdr.seq = 0 };
unsigned long *seg_map;
char uuid_str[37];
__le64 *counts;
int ret = 0;
@@ -402,14 +416,11 @@ static int print_super_blocks(int fd)
le64_to_cpu(super->total_segs),
le64_to_cpu(super->next_seg_seq),
le64_to_cpu(super->free_segs));
printf(" alloc root:");
print_treap_ref(&super->alloc_treap_root.ref);
printf("\n");
printf(" manifest root:");
print_treap_ref(&super->manifest.root.ref);
printf("\n");
printf(" level_counts:");
print_ring_descriptor(&super->alloc_ring, "alloc");
print_ring_descriptor(&super->manifest.ring, "manifest");
printf(" level_counts:");
counts = super->manifest.level_counts;
for (j = 0; j < SCOUTFS_MANIFEST_MAX_LEVEL; j++) {
if (le64_to_cpu(counts[j]))
@@ -425,21 +436,29 @@ static int print_super_blocks(int fd)
super = &recent;
printf("manifest treap:\n");
ret = walk_treap(fd, super, &super->manifest.root.ref,
print_manifest_entry);
seg_map = alloc_bits(le64_to_cpu(super->total_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);
return ret;
}
printf("alloc treap:\n");
err = walk_treap(fd, super, &super->alloc_treap_root.ref,
print_alloc_region);
ret = print_ring(fd, super, "alloc", &super->alloc_ring,
print_alloc_region, NULL);
err = print_ring(fd, super, "manifest", &super->manifest.ring,
print_manifest_entry, seg_map);
if (err && !ret)
ret = err;
err = walk_treap(fd, super, &super->manifest.root.ref,
print_segment);
err = print_segments(fd, seg_map, le64_to_cpu(super->total_segs));
if (err && !ret)
ret = err;
free(seg_map);
return ret;
}