t: Implemented rudimentary lfsr_traversal_t and related functions

This adds the lfsr_traversal_t object, which encapsulates a traversal
over all blocks in the filesystem.

This replaces the earlier lfs_fs_traverse function, but is sort of
"inside-out" in that instead of taking a callback, an lfsr_traversal_t
object can be read from to return lfs_tinfo structs that describe the
blocks in our system:

  lfsr_traversal_open(&lfs, &t) => 0;
  lfsr_traversal_read(&lfs, &t, &tinfo) => 0;
  tinfo.btype => LFS_BTYPE_MDIR;
  tinfo.block => 0x0;
  lfsr_traversal_read(&lfs, &t, &tinfo) => 0;
  tinfo.btype => LFS_BTYPE_MDIR;
  tinfo.block => 0x1;
  lfsr_traversal_read(&lfs, &t, &tinfo) => 0;
  tinfo.btype => LFS_BTYPE_DATA;
  tinfo.block => 0x42;
  lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT;
  lfsr_traversal_close(&lfs, &t) => 0;

This is more flexible, allowing for aborted traversals, yielding,
rewinding, etc, but also more complicated to implement, since it
requires all traversal state to be stored explicitly.

Fortunately, since we needed to reimplement filesystem traversals
anyways, I was able to build this into the new system from the start
using a small state machine to drive the traversal internally. So all
that was really needed was a bit of window dressing, adding
LFS_TYPE_TRAVERSAL to track open traversals, logic to handle
invalidating traversals on file close, mutation, etc...

Which, uh, that last one is not implemented yet. Interactions with other
filesystem operations gets messy, so I figured I'd go ahead and commit
what is currently working.

Ugh, and tests. The biggest downside of adding lfsr_traversal_t is how
many more corner-cases it adds to the system...

lfsr_traversal_t is going to be a work-in-progress for a bit...

---

lfsr_traversal_t also adds a really interesting path towards more access
to advanced low-level operations, such as checking metadata/data
checksums, incrementally progressing the garbage collector, even
repairing bad metadata/data blocks eventually.

Currently implemented is LFS_T_CKMETADATA and LFS_T_CKDATA to check
metadata and data checksums respectively. This is the first feature that
actually allows you to validate data checksums.

Code changes so far:

           code          stack
  before: 33886           2560
  after:  34226 (+1.0%)   2560 (+0.0%)
This commit is contained in:
Christopher Haster
2024-06-14 01:53:31 -05:00
parent 74d382b48f
commit 670b9fbf99
6 changed files with 2526 additions and 580 deletions
+437 -313
View File
File diff suppressed because it is too large Load Diff
+135 -20
View File
@@ -120,6 +120,7 @@ enum lfs_type {
// internally used types
LFS_TYPE_BOOKMARK = 4,
LFS_TYPE_TRAVERSAL = 5,
};
// File open flags
@@ -152,6 +153,35 @@ enum lfs_whence_flags {
LFS_SEEK_END = 2, // Seek relative to the end of the file
};
// Block types
enum lfs_btype {
LFS_BTYPE_MDIR = 1,
LFS_BTYPE_BTREE = 2,
LFS_BTYPE_DATA = 3,
// TODO
// LFS_BTYPE_PARITY = 4,
// LFS_BTYPE_BAD = 5,
};
// Traversal flags
enum lfs_traversal_flags {
// traversal open flags
LFS_T_MTREEONLY = 0x0010, // Only traverse the mtree
LFS_T_LOOKAHEAD = 0x0020, // Populate lookahead buffer
LFS_T_COMPACT = 0x0040, // Compact metadata logs
LFS_T_CKMETADATA = 0x0080, // Check metadata checksums
LFS_T_CKDATA = 0x0100, // Check data checksums
// TODO
// LFS_T_REPAIRMETADATA = 0x0100, // Repair metadata blocks
// LFS_T_REPAIRDATA = 0x0200, // Repair data blocks
// flags set in tinfo by lfsr_traversal_read
LFS_T_DIRTY = 0x0001, // Filesystem mutated
// TODO should we have CORRUPTMETADATA vs just error?
LFS_T_CORRUPTMETADATA = 0x0002, // Found corrupted metadata
LFS_T_CORRUPTDATA = 0x0004, // Found corrupted data
};
// Configuration provided during initialization of the littlefs
struct lfs_config {
@@ -340,6 +370,18 @@ struct lfs_fsinfo {
lfs_size_t file_limit;
};
// Traversal info structure
struct lfs_tinfo {
// Traversal flags
uint8_t flags;
// Type of the block
uint8_t btype;
// Block address
lfs_block_t block;
};
//// Custom attribute structure, used to describe custom attributes
//// committed atomically during file writes.
//struct lfs_attr {
@@ -434,6 +476,7 @@ typedef struct lfsr_mdir {
typedef struct lfsr_omdir {
struct lfsr_omdir *next;
uint8_t type;
uint8_t state;
uint16_t flags;
lfsr_mdir_t mdir;
} lfsr_omdir_t;
@@ -464,24 +507,6 @@ typedef struct lfsr_data {
} u;
} lfsr_data_t;
// littlefs directory type
//typedef struct lfs_dir {
// struct lfs_dir *next;
// uint16_t id;
// uint8_t type;
// lfs_mdir_t m;
//
// lfs_off_t pos;
// lfs_block_t head[2];
//} lfs_dir_t;
typedef struct lfsr_dir {
lfsr_omdir_t o;
lfsr_did_t did;
lfs_off_t pos;
} lfsr_dir_t;
// littlefs file type
//typedef struct lfs_file {
@@ -553,6 +578,64 @@ typedef struct lfsr_file {
lfs_size_t eoff;
} lfsr_file_t;
// littlefs directory type
//typedef struct lfs_dir {
// struct lfs_dir *next;
// uint16_t id;
// uint8_t type;
// lfs_mdir_t m;
//
// lfs_off_t pos;
// lfs_block_t head[2];
//} lfs_dir_t;
typedef struct lfsr_dir {
lfsr_omdir_t o;
lfsr_did_t did;
lfs_off_t pos;
} lfsr_dir_t;
// littlefs traversal type
typedef struct lfsr_btraversal {
lfsr_bid_t bid;
lfsr_srid_t rid;
lfsr_rbyd_t branch;
} lfsr_btraversal_t;
typedef struct lfsr_mtraversal {
// core state machine in o.state
lfsr_omdir_t o;
// we really don't want to pay the RAM cost for a full file,
// so only store the relevant bits, is this a hack? yes
const struct lfs_file_config *cfg;
lfsr_bshrub_t bshrub;
union {
// cycle detection state, only valid when traversing the mroot chain
struct {
lfsr_mptr_t mptr;
lfs_block_t step;
uint8_t power;
} mtortoise;
// mtree traversal state, only valid when traversing the mtree
lfsr_btraversal_t mt;
// opened file state, only valid when traversing opened files
const lfsr_omdir_t *o;
} u;
// btree traversal state
lfsr_btraversal_t bt;
} lfsr_mtraversal_t;
typedef struct lfsr_traversal {
// lfsr_mtraversal_t contains most of what we need
lfsr_mtraversal_t mt;
uint8_t btype;
uint8_t count;
lfs_block_t blocks[2];
} lfsr_traversal_t;
//typedef struct lfs_superblock {
// uint32_t version;
// lfs_size_t block_size;
@@ -927,8 +1010,8 @@ int lfsr_dir_close(lfs_t *lfs, lfsr_dir_t *dir);
// Read an entry in the directory
//
// Fills out the info structure, based on the specified file or directory.
// Returns a positive value on success, 0 at the end of directory,
// or a negative error code on failure.
// Returns 0 on success, LFS_ERR_NOENT at the end of directory, or a
// negative error code on failure.
//int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info);
@@ -957,6 +1040,38 @@ lfs_soff_t lfsr_dir_tell(lfs_t *lfs, lfsr_dir_t *dir);
int lfsr_dir_rewind(lfs_t *lfs, lfsr_dir_t *dir);
/// Traversal operations ///
// Open a traversal
//
// Once open, a traversal can be read from to iterate over all blocks in
// the filesystem.
//
// Returns a negative error code on failure.
int lfsr_traversal_open(lfs_t *lfs, lfsr_traversal_t *traversal,
uint32_t flags);
// Close a traversal
//
// Releases any allocated resources.
// Returns a negative error code on failure.
int lfsr_traversal_close(lfs_t *lfs, lfsr_traversal_t *traversal);
// Progress the traversal and read an entry
//
// Fills out the tinfo structure.
//
// Returns 0 on success, LFS_ERR_NOENT at the end of traversal, or a
// negative error code on failure.
int lfsr_traversal_read(lfs_t *lfs, lfsr_traversal_t *traversal,
struct lfs_tinfo *tinfo);
// Reset the traversal
//
// Returns a negative error code on failure.
int lfsr_traversal_rewind(lfs_t *lfs, lfsr_traversal_t *traversal);
/// Filesystem-level filesystem operations
// Find on-disk info about the filesystem
+67 -69
View File
@@ -108,7 +108,7 @@ code = '''
# clobber tests test that our traversal algorithm works
[cases.test_alloc_clobber_dirs]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
defines.REMOUNT = [false, true]
in = 'lfs.c'
code = '''
@@ -166,43 +166,43 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
(CKMETADATA) ? LFS_T_CKMETADATA : 0);
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -271,7 +271,7 @@ defines.SIZE = [
'2*BLOCK_SIZE',
'8*BLOCK_SIZE',
]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
defines.REMOUNT = [false, true]
in = 'lfs.c'
if = '(SIZE*N)/BLOCK_SIZE <= 32'
@@ -334,53 +334,52 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
((VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0)
| LFSR_TRAVERSAL_ALL);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BLOCK) {
} else if (mtinfo.tag == LFSR_TAG_BLOCK) {
printf("traversal: 0x%x block 0x%x\n",
tinfo.tag,
tinfo.u.bptr.data.u.disk.block);
mtinfo.tag,
mtinfo.u.bptr.data.u.disk.block);
// keep track of seen blocks
seen[tinfo.u.bptr.data.u.disk.block / 8]
|= 1 << (tinfo.u.bptr.data.u.disk.block % 8);
seen[mtinfo.u.bptr.data.u.disk.block / 8]
|= 1 << (mtinfo.u.bptr.data.u.disk.block % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -445,7 +444,7 @@ defines.SIZE = [
'2*BLOCK_SIZE',
'8*BLOCK_SIZE',
]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
in = 'lfs.c'
if = '(SIZE*N)/BLOCK_SIZE <= 32'
code = '''
@@ -489,53 +488,52 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
((VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0)
| LFSR_TRAVERSAL_ALL);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BLOCK) {
} else if (mtinfo.tag == LFSR_TAG_BLOCK) {
printf("traversal: 0x%x block 0x%x\n",
tinfo.tag,
tinfo.u.bptr.data.u.disk.block);
mtinfo.tag,
mtinfo.u.bptr.data.u.disk.block);
// keep track of seen blocks
seen[tinfo.u.bptr.data.u.disk.block / 8]
|= 1 << (tinfo.u.bptr.data.u.disk.block % 8);
seen[mtinfo.u.bptr.data.u.disk.block / 8]
|= 1 << (mtinfo.u.bptr.data.u.disk.block % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
+30 -34
View File
@@ -4092,41 +4092,39 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_btraversal_t traversal = LFSR_BTRAVERSAL();
lfsr_btraversal_t bt = LFSR_BTRAVERSAL();
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i <= 2*N);
lfsr_bid_t bid;
lfsr_tinfo_t tinfo;
int err = lfsr_btree_traverse(&lfs, &btree, &traversal,
&bid, &tinfo);
lfsr_btinfo_t btinfo;
int err = lfsr_btree_traverse(&lfs, &btree, &bt, &btinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_BRANCH) {
if (btinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: %d 0x%x btree 0x%x.%x\n",
bid,
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
btinfo.bid,
btinfo.tag,
btinfo.u.rbyd.blocks[0], btinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[btinfo.u.rbyd.blocks[0] / 8]
|= 1 << (btinfo.u.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_DATA) {
} else if (btinfo.tag == LFSR_TAG_DATA) {
printf("traversal: %d 0x%x data %d\n",
bid,
tinfo.tag,
lfsr_data_size(tinfo.u.data));
btinfo.bid,
btinfo.tag,
lfsr_data_size(btinfo.u.data));
} else {
// well this shouldn't happen
printf("traversal: %d 0x%x\n",
bid,
tinfo.tag);
btinfo.bid,
btinfo.tag);
assert(false);
}
}
@@ -4242,41 +4240,39 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_btraversal_t traversal = LFSR_BTRAVERSAL();
lfsr_btraversal_t bt = LFSR_BTRAVERSAL();
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i <= 2*N);
lfsr_bid_t bid;
lfsr_tinfo_t tinfo;
int err = lfsr_btree_traverse(&lfs, &btree, &traversal,
&bid, &tinfo);
lfsr_btinfo_t btinfo;
int err = lfsr_btree_traverse(&lfs, &btree, &bt, &btinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_BRANCH) {
if (btinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: %d 0x%x btree 0x%x.%x\n",
bid,
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
btinfo.bid,
btinfo.tag,
btinfo.u.rbyd.blocks[0], btinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[btinfo.u.rbyd.blocks[0] / 8]
|= 1 << (btinfo.u.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_DATA) {
} else if (btinfo.tag == LFSR_TAG_DATA) {
printf("traversal: %d 0x%x data %d\n",
bid,
tinfo.tag,
lfsr_data_size(tinfo.u.data));
btinfo.bid,
btinfo.tag,
lfsr_data_size(btinfo.u.data));
} else {
// well this shouldn't happen
printf("traversal: %d 0x%x\n",
bid,
tinfo.tag);
btinfo.bid,
btinfo.tag);
assert(false);
}
}
+152 -144
View File
@@ -3340,7 +3340,7 @@ code = '''
# test specific corner cases
[cases.test_mtree_traversal]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
in = 'lfs.c'
code = '''
lfs_t lfs;
@@ -3360,43 +3360,44 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY
| ((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -3438,7 +3439,7 @@ code = '''
'''
[cases.test_mtree_traversal_uninline]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
# this should be set so only one entry can fit in a metadata block
defines.SIZE = 'BLOCK_SIZE / 4'
in = 'lfs.c'
@@ -3474,43 +3475,44 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY
| ((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -3568,7 +3570,7 @@ code = '''
'''
[cases.test_mtree_traversal_uninline_split]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
# this should be set so only one entry can fit in a metadata block
defines.SIZE = 'BLOCK_SIZE / 4'
in = 'lfs.c'
@@ -3610,43 +3612,44 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY
| ((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -3708,7 +3711,7 @@ code = '''
'''
[cases.test_mtree_traversal_split]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
# this should be set so only one entry can fit in a metadata block
defines.SIZE = 'BLOCK_SIZE / 4'
in = 'lfs.c'
@@ -3767,43 +3770,44 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY
| ((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -3877,7 +3881,7 @@ code = '''
'''
[cases.test_mtree_traversal_extend]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
# make it so blocks relocate every two compacts
defines.BLOCK_RECYCLES = 0
in = 'lfs.c'
@@ -3908,43 +3912,44 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY
| ((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -3988,7 +3993,7 @@ code = '''
# larger traversal tests
[cases.test_mtree_traversal_many]
defines.N = [5, 10, 20, 40, 80, 160, 320]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
defines.FORCE_COMPACTION = [false, true]
in = 'lfs.c'
code = '''
@@ -4024,43 +4029,44 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY
| ((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -4118,7 +4124,7 @@ code = '''
[cases.test_mtree_traversal_fuzz]
defines.N = [5, 10, 20, 40, 80, 160]
defines.VALIDATE = [false, true]
defines.CKMETADATA = [false, true]
defines.FORCE_COMPACTION = [false, true]
defines.SEED = 'range(100)'
fuzz = 'SEED'
@@ -4175,43 +4181,44 @@ code = '''
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
memset(seen, 0, (BLOCK_COUNT+7)/8);
lfsr_traversal_t traversal = LFSR_TRAVERSAL(
(VALIDATE) ? LFSR_TRAVERSAL_VALIDATE : 0);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY
| ((CKMETADATA) ? LFS_T_CKMETADATA : 0));
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
// keep track of seen blocks
seen[tinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[1] % 8);
seen[tinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.mdir.rbyd.blocks[0] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[1] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[1] % 8);
seen[mtinfo.u.mdir.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.mdir.rbyd.blocks[0] % 8);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
// keep track of seen blocks
seen[tinfo.u.rbyd.blocks[0] / 8]
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
seen[mtinfo.u.rbyd.blocks[0] / 8]
|= 1 << (mtinfo.u.rbyd.blocks[0] % 8);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
@@ -4297,32 +4304,33 @@ code = '''
LFSR_DATA_MPTR(&LFSR_MPTR_MROOTANCHOR())))) => 0;
// technically, cycle detection only needs to work when we're validating
lfsr_traversal_t traversal = LFSR_TRAVERSAL(LFSR_TRAVERSAL_VALIDATE);
lfsr_mtraversal_t mt = LFSR_MTRAVERSAL(
LFS_T_MTREEONLY | LFS_T_CKMETADATA);
for (lfs_block_t i = 0;; i++) {
// assert that we detect the cycle in a reasonable number of iterations
assert(i < 2*BLOCK_COUNT);
lfsr_tinfo_t tinfo;
int err = lfsr_traversal_read(&lfs, &traversal, &tinfo);
lfsr_mtinfo_t mtinfo;
int err = lfsr_fs_traverse(&lfs, &mt, &mtinfo);
assert(!err || err == LFS_ERR_CORRUPT);
if (err == LFS_ERR_CORRUPT) {
break;
}
if (tinfo.tag == LFSR_TAG_MDIR) {
if (mtinfo.tag == LFSR_TAG_MDIR) {
printf("traversal: 0x%x mdir 0x{%x,%x}\n",
tinfo.tag,
tinfo.u.mdir.rbyd.blocks[0],
tinfo.u.mdir.rbyd.blocks[1]);
mtinfo.tag,
mtinfo.u.mdir.rbyd.blocks[0],
mtinfo.u.mdir.rbyd.blocks[1]);
} else if (tinfo.tag == LFSR_TAG_BRANCH) {
} else if (mtinfo.tag == LFSR_TAG_BRANCH) {
printf("traversal: 0x%x btree 0x%x.%x\n",
tinfo.tag,
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
mtinfo.tag,
mtinfo.u.rbyd.blocks[0], mtinfo.u.rbyd.trunk);
} else {
// this shouldn't happen
printf("traversal: 0x%x\n", tinfo.tag);
printf("traversal: 0x%x\n", mtinfo.tag);
assert(false);
}
}
File diff suppressed because it is too large Load Diff