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:
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user