Reworked lfsr_bshrub_t, renamed file.o -> file.b

This moves all of the shrub tracking logic from lfsr_obshrub_t into
lfsr_bshrub_t, completely drops the lfsr_obshrub_t type, and changes all
lfsr_bshrub_* functions to take lfsr_bshrub_t instead of the mdir+shrub
pair.

This makes the lfsr_bshrub_* functions <-> lfsr_bshrub_t relationship
more consistent with other APIs, such as lfsr_btree_t:

  - lfsr_bshrub_lookupnext(lfs, &file->o.o.mdir, &file->o.bshrub, ...)
  + lfsr_bshrub_lookupnext(lfs, &file->b, ...)

I think the reason why this design wasn't obvious before is because, at
least conceptually, having the lfsr_mdir_t live inside the lfsr_bshrub_t
is a bit weird. It's only thanks to lfsr_file_t invasively using the
internal lfsr_mdir_t that we can avoid duplicate lfsr_mdir_t objects.

This also reorganizes the structs in lfs.h a bit, and renames the
related file.o -> file.b fields (much needed because lfs->gc.t.o.o.mdir.
rbyd.blocks was starting to get _real_ confusing).

---

Unfortunately, reducing the number of arguments to lfsr_bshrub_*
functions did not save nearly as much code as I thought it would. It
even ended up with a net _increase_ of code, apparently due to needing
to recalculate the bshrub->shrub offset more often:

           code          stack          ctx
  before: 36476           2608          640
  after:  36484 (+0.0%)   2608 (+0.0%)  640 (+0.0%)

Strange, but this rework is still worthwhile if only for the code
readability.
This commit is contained in:
Christopher Haster
2025-02-03 03:07:30 -06:00
parent fd62ef9674
commit bc639b03f2
7 changed files with 487 additions and 506 deletions
+339 -351
View File
File diff suppressed because it is too large Load Diff
+60 -63
View File
@@ -584,42 +584,6 @@ struct lfs_file_config {
// uint8_t *buffer;
//} lfs_cache_t;
// TODO do we get ram savings with a lfsr_rorbyd_t substruct? need to measure
typedef struct lfsr_rbyd {
// note this lines up with weight in lfsr_data_t
// sign(weight)=0 => rbyd
lfsr_rid_t weight;
lfs_block_t blocks[2];
// sign(trunk)=0 => normal rbyd
// sign(trunk)=1 => shrub rbyd
lfs_size_t trunk;
// sign(eoff) => perturb bit
// eoff=0, trunk=0 => not yet committed
// eoff=0, trunk>0 => not yet fetched
// eoff>=block_size => rbyd not erased/needs compaction
lfs_size_t eoff;
uint32_t cksum;
} lfsr_rbyd_t;
// a btree is just the root rbyd
typedef lfsr_rbyd_t lfsr_btree_t;
// a shrub is a secondary trunk in an mdir
typedef lfsr_rbyd_t lfsr_shrub_t;
typedef struct lfsr_mdir {
lfsr_smid_t mid;
lfsr_rbyd_t rbyd;
uint32_t gcksumdelta;
} lfsr_mdir_t;
typedef struct lfsr_omdir {
struct lfsr_omdir *next;
uint32_t flags;
lfsr_mdir_t mdir;
} lfsr_omdir_t;
//typedef struct lfs_mdir {
// lfs_block_t pair[2];
// uint32_t rev;
@@ -656,6 +620,62 @@ typedef struct lfsr_data {
} u;
} lfsr_data_t;
// a block pointer
typedef struct lfsr_bptr {
lfsr_data_t data;
#ifndef LFS_CKDATACKSUMS
lfs_size_t cksize;
uint32_t cksum;
#endif
} lfsr_bptr_t;
// littlefs's core metadata log type
typedef struct lfsr_rbyd {
lfsr_rid_t weight;
lfs_block_t blocks[2];
// sign(trunk)=0 => normal rbyd
// sign(trunk)=1 => shrub rbyd
lfs_size_t trunk;
// sign(eoff) => perturb bit
// eoff=0, trunk=0 => not yet committed
// eoff=0, trunk>0 => not yet fetched
// eoff>=block_size => rbyd not erased/needs compaction
lfs_size_t eoff;
uint32_t cksum;
} lfsr_rbyd_t;
// a btree is represented by the root rbyd
typedef lfsr_rbyd_t lfsr_btree_t;
// littlefs's atomic metadata log type
typedef struct lfsr_mdir {
lfsr_smid_t mid;
lfsr_rbyd_t rbyd;
uint32_t gcksumdelta;
} lfsr_mdir_t;
typedef struct lfsr_omdir {
struct lfsr_omdir *next;
uint32_t flags;
lfsr_mdir_t mdir;
} lfsr_omdir_t;
// a shrub is a secondary trunk in an mdir
typedef lfsr_rbyd_t lfsr_shrub_t;
// a bshrub is like a btree but with a shrub as a root
typedef struct lfsr_bshrub {
// bshrubs need to be tracked for commits to work
lfsr_omdir_t o;
// files contain both an active bshrub and staging bshrub, to allow
// staging during mdir compacts
// trunk=0 => no bshrub/btree
// sign(trunk)=1 => bshrub
// sign(trunk)=0 => btree
lfsr_shrub_t shrub;
lfsr_shrub_t shrub_;
} lfsr_bshrub_t;
// littlefs file type
//typedef struct lfs_file {
@@ -678,32 +698,8 @@ typedef struct lfsr_data {
// const struct lfs_file_config *cfg;
//} lfs_file_t;
typedef struct lfsr_bptr {
lfsr_data_t data;
#ifndef LFS_CKDATACKSUMS
lfs_size_t cksize;
uint32_t cksum;
#endif
} lfsr_bptr_t;
// the lfsr_bshrub_t struct represents the on-disk component of a file
//
// weight=0 => no bshrub/btree
// sign(weight)=1 => bshrub
// sign(weight)=0 => btree
typedef lfsr_rbyd_t lfsr_bshrub_t;
typedef struct lfsr_obshrub {
// bshrubs need to be tracked for commits to work
lfsr_omdir_t o;
// files contain both an active bshrub and staging bshrub, to allow
// staging during mdir compacts
lfsr_bshrub_t bshrub;
lfsr_bshrub_t bshrub_;
} lfsr_obshrub_t;
typedef struct lfsr_file {
lfsr_obshrub_t o;
lfsr_bshrub_t b;
const struct lfs_file_config *cfg;
lfs_off_t pos;
@@ -747,8 +743,9 @@ typedef struct lfsr_btraversal {
} lfsr_btraversal_t;
typedef struct lfsr_traversal {
// mdir/btree state, this also includes our traversal state machine
lfsr_obshrub_t o;
// mdir/bshrub/btree state, this also includes our traversal
// state machine
lfsr_bshrub_t b;
// opened file state
lfsr_omdir_t *ot;
union {
+12 -12
View File
@@ -977,7 +977,7 @@ code = '''
lfsr_file_sync(&lfs, &file) => 0;
// delete any bshrub/btree
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
lfsr_mdir_commit(&lfs, &file.b.o.mdir, LFSR_RATS(
LFSR_RAT(
LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_STRUCT, 0,
LFSR_DATA_NULL()))) => 0;
@@ -1094,22 +1094,22 @@ code = '''
lfsr_file_sync(&lfs, &file) => 0;
// create an empty bshrub
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
lfsr_mdir_commit(&lfs, &file.b.o.mdir, LFSR_RATS(
LFSR_RAT_SHRUBCOMMIT(
LFSR_TAG_SHRUBCOMMIT, 0,
&file.o.bshrub, 0, ((lfsr_rat_t[]){
&file.b.shrub, 0, ((lfsr_rat_t[]){
LFSR_RAT(LFSR_TAG_DATA, +1, LFSR_DATA_BUF("?", 1))}),
1))) => 0;
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
lfsr_mdir_commit(&lfs, &file.b.o.mdir, LFSR_RATS(
LFSR_RAT_SHRUBCOMMIT(
LFSR_TAG_SHRUBCOMMIT, 0,
&file.o.bshrub, 0, ((lfsr_rat_t[]){
&file.b.shrub, 0, ((lfsr_rat_t[]){
LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL())}),
1))) => 0;
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
lfsr_mdir_commit(&lfs, &file.b.o.mdir, LFSR_RATS(
LFSR_RAT_SHRUBTRUNK(
LFSR_TAG_SUB | LFSR_TAG_SHRUBTRUNK, 0,
&file.o.bshrub))) => 0;
&file.b.shrub))) => 0;
lfsr_file_close(&lfs, &file) => 0;
@@ -1224,16 +1224,16 @@ code = '''
// create an empty btree
lfs_alloc_ckpoint(&lfs);
lfsr_rbyd_alloc(&lfs, &file.o.bshrub) => 0;
lfsr_rbyd_commit(&lfs, &file.o.bshrub, 0, LFSR_RATS(
lfsr_rbyd_alloc(&lfs, &file.b.shrub) => 0;
lfsr_rbyd_commit(&lfs, &file.b.shrub, 0, LFSR_RATS(
LFSR_RAT(LFSR_TAG_DATA, +1, LFSR_DATA_BUF("?", 1)))) => 0;
lfsr_rbyd_commit(&lfs, &file.o.bshrub, 0, LFSR_RATS(
lfsr_rbyd_commit(&lfs, &file.b.shrub, 0, LFSR_RATS(
LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
uint8_t buf[LFSR_BTREE_DSIZE];
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
lfsr_mdir_commit(&lfs, &file.b.o.mdir, LFSR_RATS(
LFSR_RAT(
LFSR_TAG_SUB | LFSR_TAG_BTREE, 0,
LFSR_DATA_BTREE(&file.o.bshrub, buf)))) => 0;
LFSR_DATA_BTREE(&file.b.shrub, buf)))) => 0;
lfsr_file_close(&lfs, &file) => 0;
+4 -8
View File
@@ -189,8 +189,7 @@ code = '''
lfsr_bid_t bid;
lfsr_tag_t tag;
lfsr_bptr_t bptr;
int err = lfsr_bshrub_traverse(&lfs,
&file.o.o.mdir, &file.o.bshrub, &bt,
int err = lfsr_bshrub_traverse(&lfs, &file.b, &bt,
&bid, &tag, &bptr);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
@@ -330,8 +329,7 @@ code = '''
lfsr_bid_t bid;
lfsr_tag_t tag;
lfsr_bptr_t bptr;
int err = lfsr_bshrub_traverse(&lfs,
&file.o.o.mdir, &file.o.bshrub, &bt,
int err = lfsr_bshrub_traverse(&lfs, &file.b, &bt,
&bid, &tag, &bptr);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
@@ -589,8 +587,7 @@ code = '''
lfsr_bid_t bid;
lfsr_tag_t tag;
lfsr_bptr_t bptr;
int err = lfsr_bshrub_traverse(&lfs,
&file.o.o.mdir, &file.o.bshrub, &bt,
int err = lfsr_bshrub_traverse(&lfs, &file.b, &bt,
&bid, &tag, &bptr);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
@@ -745,8 +742,7 @@ code = '''
lfsr_bid_t bid;
lfsr_tag_t tag;
lfsr_bptr_t bptr;
int err = lfsr_bshrub_traverse(&lfs,
&file.o.o.mdir, &file.o.bshrub, &bt,
int err = lfsr_bshrub_traverse(&lfs, &file.b, &bt,
&bid, &tag, &bptr);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
+17 -17
View File
@@ -45,7 +45,7 @@ code = '''
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.flags & LFS_I_LOOKAHEAD);
assert(lfs.omdirs != &lfs.gc.t.o.o);
assert(lfs.omdirs != &lfs.gc.t.b.o);
// run GC until we make progress
for (lfs_block_t i = 0;; i++) {
@@ -112,11 +112,11 @@ code = '''
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.flags & LFS_I_LOOKAHEAD);
assert(lfs.omdirs != &lfs.gc.t.o.o);
assert(lfs.omdirs != &lfs.gc.t.b.o);
// run GC one step
lfsr_fs_gc(&lfs) => 0;
assert(lfs.omdirs == &lfs.gc.t.o.o);
assert(lfs.omdirs == &lfs.gc.t.b.o);
// mutate the filesystem
lfsr_file_open(&lfs, &file, "spider",
@@ -128,7 +128,7 @@ code = '''
lfsr_file_close(&lfs, &file) => 0;
// run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.t.o.o) {
while (lfs.omdirs == &lfs.gc.t.b.o) {
lfsr_fs_gc(&lfs) => 0;
}
@@ -184,7 +184,7 @@ code = '''
// hack, don't use the internals like this
uint8_t wbuf[SIZE];
while ((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -197,7 +197,7 @@ code = '''
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.flags & LFS_I_COMPACT);
assert(lfs.omdirs != &lfs.gc.t.o.o);
assert(lfs.omdirs != &lfs.gc.t.b.o);
// run GC until we make progress
for (lfs_block_t i = 0;; i++) {
@@ -213,7 +213,7 @@ code = '''
}
// mdir should have been compacted
assert((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// check we can still read the file
for (int remount = 0; remount < 2; remount++) {
@@ -273,7 +273,7 @@ code = '''
// hack, don't use the internals like this
uint8_t wbuf[SIZE];
while ((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -286,19 +286,19 @@ code = '''
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.flags & LFS_I_COMPACT);
assert(lfs.omdirs != &lfs.gc.t.o.o);
assert(lfs.omdirs != &lfs.gc.t.b.o);
// run GC one traversal + one step
while (true) {
lfsr_fs_gc(&lfs) => 0;
// internal traversal done?
if (lfs.omdirs != &lfs.gc.t.o.o) {
if (lfs.omdirs != &lfs.gc.t.b.o) {
break;
}
}
lfsr_fs_gc(&lfs) => 0;
assert(lfs.omdirs == &lfs.gc.t.o.o);
assert(lfs.omdirs == &lfs.gc.t.b.o);
// mutate the filesystem
lfsr_file_rewind(&lfs, &file) => 0;
@@ -309,7 +309,7 @@ code = '''
lfsr_file_sync(&lfs, &file) => 0;
// run GC until our traversal is done (twice for compact)
while (lfs.omdirs == &lfs.gc.t.o.o) {
while (lfs.omdirs == &lfs.gc.t.b.o) {
lfsr_fs_gc(&lfs) => 0;
}
@@ -407,7 +407,7 @@ code = '''
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.flags & LFS_I_MKCONSISTENT);
assert(lfs.omdirs != &lfs.gc.t.o.o);
assert(lfs.omdirs != &lfs.gc.t.b.o);
// run GC until we make progress
for (lfs_block_t i = 0;; i++) {
@@ -507,7 +507,7 @@ code = '''
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.flags & LFS_I_MKCONSISTENT);
#ifdef LFS_GC
assert(lfs.omdirs != &lfs.gc.t.o.o);
assert(lfs.omdirs != &lfs.gc.t.b.o);
#endif
// call lfsr_fs_mkconsistent
@@ -605,9 +605,9 @@ code = '''
}
// run GC one step
assert(lfs.omdirs != &lfs.gc.t.o.o);
assert(lfs.omdirs != &lfs.gc.t.b.o);
lfsr_fs_gc(&lfs) => 0;
assert(lfs.omdirs == &lfs.gc.t.o.o);
assert(lfs.omdirs == &lfs.gc.t.b.o);
// create the rest of the orphans after GC has started
for (lfs_size_t i = 0; i < ORPHANS; i++) {
@@ -626,7 +626,7 @@ code = '''
assert(fsinfo.flags & LFS_I_MKCONSISTENT);
// run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.t.o.o) {
while (lfs.omdirs == &lfs.gc.t.b.o) {
lfsr_fs_gc(&lfs) => 0;
}
+2 -2
View File
@@ -188,7 +188,7 @@ code = '''
// hack, don't use the internals like this
uint8_t wbuf[SIZE];
while ((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -230,7 +230,7 @@ code = '''
// mdir should have been compacted
lfsr_file_open(&lfs, &file, "jellyfish", LFS_O_RDONLY) => 0;
assert((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// check we can still read the file
uint8_t rbuf[SIZE];
+53 -53
View File
@@ -5397,7 +5397,7 @@ code = '''
// hack, don't use the internals like this
uint8_t wbuf[SIZE];
while ((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -5433,7 +5433,7 @@ code = '''
lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT;
// mdir should have been compacted
assert((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// but because we mutated, we're still marked as uncompacted
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5455,7 +5455,7 @@ code = '''
lfsr_traversal_close(&lfs, &t) => 0;
// mdir should have been compacted
assert((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// uncompacted flag should have been cleared
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5649,7 +5649,7 @@ code = '''
// hack, don't use the internals like this
uint8_t wbuf[SIZE];
while ((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -5687,7 +5687,7 @@ code = '''
lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT;
// mdir should have been compacted
assert((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// but because we mutated, we're still marked as uncompacted
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5709,7 +5709,7 @@ code = '''
lfsr_traversal_close(&lfs, &t) => 0;
// mdir should have been compacted
assert((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// uncompacted flag should have been cleared
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5782,10 +5782,10 @@ code = '''
assert(lfs.mtree.weight == 0);
// we need internals to check this
lfs_ssize_t estimate = lfsr_mdir_estimate__(&lfs,
&file1.o.o.mdir, -1, -1,
&file1.b.o.mdir, -1, -1,
NULL);
assert(estimate >= 0);
if ((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) > GC_COMPACT_THRESH
if ((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) > GC_COMPACT_THRESH
&& estimate > BLOCK_SIZE/2) {
break;
}
@@ -5839,8 +5839,8 @@ code = '''
lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT;
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// but because we mutated, we're still marked as uncompacted
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5862,8 +5862,8 @@ code = '''
lfsr_traversal_close(&lfs, &t) => 0;
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// uncompacted flag should have been cleared
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5973,7 +5973,7 @@ code = '''
// write to each file until mdir >gc_compact_thresh full
if (COMPACTSET & 0x1) {
// hack, don't use the internals like this
while ((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file1) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf1[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -5985,7 +5985,7 @@ code = '''
if (COMPACTSET & 0x2) {
// hack, don't use the internals like this
while ((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file2) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf2[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -5997,7 +5997,7 @@ code = '''
if (COMPACTSET & 0x4) {
// hack, don't use the internals like this
while ((file3.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file3.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file3) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf3[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -6053,9 +6053,9 @@ code = '''
if (COMPACTSET) {
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// but because we mutated, we're still marked as uncompacted
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -6078,9 +6078,9 @@ code = '''
lfsr_traversal_close(&lfs, &t) => 0;
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// uncompacted flag should have been cleared
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -6212,10 +6212,10 @@ code = '''
assert(lfs.mtree.weight == orig);
// we need internals to check this
lfs_ssize_t estimate = lfsr_mdir_estimate__(&lfs,
&file2.o.o.mdir, -1, -1,
&file2.b.o.mdir, -1, -1,
NULL);
assert(estimate >= 0);
if ((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) > GC_COMPACT_THRESH
if ((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) > GC_COMPACT_THRESH
&& estimate > BLOCK_SIZE/2) {
break;
}
@@ -6279,10 +6279,10 @@ code = '''
lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT;
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file4.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file4.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// but because we mutated, we're still marked as uncompacted
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -6304,10 +6304,10 @@ code = '''
lfsr_traversal_close(&lfs, &t) => 0;
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file4.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file3.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file4.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// uncompacted flag should have been cleared
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -6467,8 +6467,8 @@ code = '''
// which means there shouldn't be that many files left
assert(lfs.mtree.weight <= (2 << lfs.mdir_bits));
assert(file1.o.o.mdir.rbyd.weight <= 3);
assert(file2.o.o.mdir.rbyd.weight <= 3);
assert(file1.b.o.mdir.rbyd.weight <= 3);
assert(file2.b.o.mdir.rbyd.weight <= 3);
// and we should be marked as consistent
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -6768,8 +6768,8 @@ code = '''
// which means there shouldn't be that many files left
assert(lfs.mtree.weight <= (2 << lfs.mdir_bits));
assert(file1.o.o.mdir.rbyd.weight <= 3);
assert(file2.o.o.mdir.rbyd.weight <= 3);
assert(file1.b.o.mdir.rbyd.weight <= 3);
assert(file2.b.o.mdir.rbyd.weight <= 3);
// and we should be marked as consistent
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -6926,8 +6926,8 @@ code = '''
// which means there shouldn't be that many files left
assert(lfs.mtree.weight <= (2 << lfs.mdir_bits));
assert(file1.o.o.mdir.rbyd.weight <= 3);
assert(file2.o.o.mdir.rbyd.weight <= 3);
assert(file1.b.o.mdir.rbyd.weight <= 3);
assert(file2.b.o.mdir.rbyd.weight <= 3);
// and we should be marked as consistent
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -7095,8 +7095,8 @@ code = '''
// which means there shouldn't be that many files left
assert(lfs.mtree.weight <= (2 << lfs.mdir_bits));
assert(file1.o.o.mdir.rbyd.weight <= 3);
assert(file2.o.o.mdir.rbyd.weight <= 3);
assert(file1.b.o.mdir.rbyd.weight <= 3);
assert(file2.b.o.mdir.rbyd.weight <= 3);
// and we should be marked as consistent
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -7262,8 +7262,8 @@ code = '''
// which means there shouldn't be that many files left
assert(lfs.mtree.weight <= (2 << lfs.mdir_bits));
assert(file1.o.o.mdir.rbyd.weight <= 3);
assert(file2.o.o.mdir.rbyd.weight <= 3);
assert(file1.b.o.mdir.rbyd.weight <= 3);
assert(file2.b.o.mdir.rbyd.weight <= 3);
// and we should be marked as consistent
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -7360,7 +7360,7 @@ code = '''
// write to our mdirs until >gc_compact_thresh full
//
// hack, don't use the internals like this
while ((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file1) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf1[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -7369,7 +7369,7 @@ code = '''
lfsr_file_sync(&lfs, &file1) => 0;
}
while ((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file2) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf2[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -7427,12 +7427,12 @@ code = '''
// which means there shouldn't be that many files left
assert(lfs.mtree.weight <= (2 << lfs.mdir_bits));
assert(file1.o.o.mdir.rbyd.weight <= 3);
assert(file2.o.o.mdir.rbyd.weight <= 3);
assert(file1.b.o.mdir.rbyd.weight <= 3);
assert(file2.b.o.mdir.rbyd.weight <= 3);
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// we should be marked as consistent, but because we mutated, we're
// still marked as uncompacted
@@ -7455,8 +7455,8 @@ code = '''
lfsr_traversal_close(&lfs, &t) => 0;
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// uncompacted flag should have been cleared
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -7534,7 +7534,7 @@ code = '''
// write to our mdirs until >gc_compact_thresh full
//
// hack, don't use the internals like this
while ((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file1) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf1[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -7543,7 +7543,7 @@ code = '''
lfsr_file_sync(&lfs, &file1) => 0;
}
while ((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
while ((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH) {
lfsr_file_rewind(&lfs, &file2) => 0;
for (lfs_size_t j = 0; j < SIZE; j++) {
wbuf2[j] = 'a' + (TEST_PRNG(&prng) % 26);
@@ -7622,8 +7622,8 @@ code = '''
}
// mdirs should have been compacted
assert((file1.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file1.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
assert((file2.b.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// if we introduced actual orphans, we _must_ be marked as inconsistent
lfsr_fs_stat(&lfs, &fsinfo) => 0;