Changed gc_steps into a runtime parameter, better dedup mount gc

So instead of configuring gc_steps at mount time (or eventually compile
time), lfsr_fs_gc now takes a steps parameter that controls how much gc
work to attempt:

  int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags);

This API was needed internally to better deduplicate on-mount gc, and I
figured it might also be useful for users to be able to easily change
gc_steps per lfsr_fs_gc call.

I realize this could also be accomplished with the theoretical
lfsr_fs_gccfg, but it's a bit easier to not need a struct every call.

Most likely, depending on project/system, users will always call
lfsr_fs_gc with either 1 (minimal work) or -1 (maximal work), or, worst
case, can define a system-wide GC_STEPS somewhere.

---

Deduplicating on-mount gc work better saved some code, though it's worth
noting this could have been done internally and not exposed to users:

           code          stack
  before: 36476           2680 (+0.0%)
  after:  36316 (-0.4%)   2680 (+0.0%)
This commit is contained in:
Christopher Haster
2024-07-17 01:56:12 -05:00
parent 54ecc94702
commit eced943685
5 changed files with 163 additions and 222 deletions
+81 -124
View File
@@ -12623,13 +12623,13 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags,
int err = lfs_init(lfs,
// strip out the one-time traversal flags
flags
& ~LFS_M_MTREEONLY
& ~LFS_M_MKCONSISTENT
& ~LFS_M_LOOKAHEAD
& ~LFS_M_COMPACT
& ~LFS_M_CKMETA
& ~LFS_M_CKDATA,
flags & ~(
LFS_M_MTREEONLY
| LFS_M_MKCONSISTENT
| LFS_M_LOOKAHEAD
| LFS_M_COMPACT
| LFS_M_CKMETA
| LFS_M_CKDATA),
cfg);
if (err) {
return err;
@@ -12655,73 +12655,17 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags,
lfsr_mtree_weight_(&lfs->mtree) >> lfs->mdir_bits,
1 << lfs->mdir_bits);
// fix pending grms if requested
if (lfsr_t_ismkconsistent(flags)
&& lfsr_grm_count(lfs) > 0) {
if (lfsr_grm_count(lfs) == 2) {
LFS_DEBUG("Fixing grm %"PRId32".%"PRId32" %"PRId32".%"PRId32,
lfsr_mid_bid(lfs, lfs->grm.mids[0]) >> lfs->mdir_bits,
lfsr_mid_rid(lfs, lfs->grm.mids[0]),
lfsr_mid_bid(lfs, lfs->grm.mids[1]) >> lfs->mdir_bits,
lfsr_mid_rid(lfs, lfs->grm.mids[1]));
} else if (lfsr_grm_count(lfs) == 1) {
LFS_DEBUG("Fixing grm %"PRId32".%"PRId32,
lfsr_mid_bid(lfs, lfs->grm.mids[0]) >> lfs->mdir_bits,
lfsr_mid_rid(lfs, lfs->grm.mids[0]));
}
err = lfsr_fs_fixgrm(lfs);
if (err) {
goto failed;
}
}
// run gc until all requested mount work is done
bool mutated = true;
while ((lfsr_t_ismkconsistent(flags)
&& lfsr_f_hasorphans(lfs->flags))
|| (lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& mutated)
|| (lfsr_t_isckdata(flags)
&& mutated)) {
// checkpoint the allocator to maximize any lookahead scans
lfs_alloc_ckpoint(lfs);
// do we really need a full traversal?
uint32_t flags_ = flags;
if (!((lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& mutated)
|| (lfsr_t_isckdata(flags)
&& mutated))) {
flags_ |= LFS_GC_MTREEONLY;
}
lfsr_traversal_t t = LFSR_TRAVERSAL(flags_);
lfsr_omdir_open(lfs, &t.o.o);
while (true) {
err = lfsr_mtree_gc(lfs, &t,
NULL, NULL);
if (err) {
lfsr_omdir_close(lfs, &t.o.o);
if (err == LFS_ERR_NOENT) {
break;
}
goto failed;
}
}
// mutated? we need another pass for ckmeta/ckdata
mutated = lfsr_f_ismutated(t.o.o.flags);
// run gc if requested
err = lfsr_fs_gc(lfs, -1,
flags & (
LFS_M_MTREEONLY
| LFS_M_MKCONSISTENT
| LFS_M_LOOKAHEAD
| LFS_M_COMPACT
| LFS_M_CKMETA
| LFS_M_CKDATA));
if (err) {
goto failed;
}
return 0;
@@ -13078,10 +13022,7 @@ int lfsr_fs_ckdata(lfs_t *lfs) {
}
// perform any pending janitorial work
int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
// some flags don't make sense when only traversing the mtree
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_islookahead(flags));
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_isckdata(flags));
int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) {
// unknown flags?
LFS_ASSERT((flags
& ~LFS_GC_MTREEONLY
@@ -13090,6 +13031,9 @@ int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
& ~LFS_GC_COMPACT
& ~LFS_GC_CKMETA
& ~LFS_GC_CKDATA) == 0);
// some flags don't make sense when only traversing the mtree
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_islookahead(flags));
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_isckdata(flags));
// fix pending grms if requested
if (lfsr_t_ismkconsistent(flags)
@@ -13112,57 +13056,70 @@ int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
}
}
// do we need to do anything?
if (!((lfsr_t_ismkconsistent(flags)
&& lfsr_f_hasorphans(lfs->flags))
|| (lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| lfsr_t_isckmeta(flags)
|| lfsr_t_isckdata(flags))) {
return 0;
}
// do we have any pending work?
bool cked = false;
while ((lfs_off_t)steps > 0
&& ((lfsr_t_ismkconsistent(flags)
&& lfsr_f_hasorphans(lfs->flags))
|| (lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& !cked)
|| (lfsr_t_isckdata(flags)
&& !cked))) {
// checkpoint the allocator to maximize any lookahead scans
lfs_alloc_ckpoint(lfs);
// checkpoint the allocator to maximize any lookahead scans
lfs_alloc_ckpoint(lfs);
// existing traversal?
if (lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
// note that we mask flags (except mtreeonly)! if you change flags
// mid-traversal, the result is equivalent to the worst-case set
// of flags
lfs->gc.o.o.flags &= (
~LFS_GC_MKCONSISTENT
& ~LFS_GC_LOOKAHEAD
& ~LFS_GC_COMPACT
& ~LFS_GC_CKMETA
& ~LFS_GC_CKDATA
) | flags;
// start a new traversal
} else {
lfs->gc = LFSR_TRAVERSAL(
flags
// do we really need a full traversal?
| ((!((lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& !cked)
|| (lfsr_t_isckdata(flags)
&& !cked)))
? LFS_T_MTREEONLY
: 0));
lfsr_omdir_open(lfs, &lfs->gc.o.o);
}
// do we really need a full traversal?
if (!((lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| lfsr_t_isckmeta(flags)
|| lfsr_t_isckdata(flags))) {
flags |= LFS_GC_MTREEONLY;
}
// existing traversal?
if (lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
// note that we mask flags (except mtreeonly)! if you change flags
// mid-traversal, the result is equivalent to the worst-case set
// of flags
lfs->gc.o.o.flags &= (
~LFS_GC_MKCONSISTENT
& ~LFS_GC_LOOKAHEAD
& ~LFS_GC_COMPACT
& ~LFS_GC_CKMETA
& ~LFS_GC_CKDATA
) | flags;
// start a new traversal
} else {
lfs->gc = LFSR_TRAVERSAL(flags);
lfsr_omdir_open(lfs, &lfs->gc.o.o);
}
for (uint32_t i = 0;
i < (lfs->cfg->gc_steps ? (uint32_t)lfs->cfg->gc_steps : 1);
i++) {
// progress gc
int err = lfsr_mtree_gc(lfs, &lfs->gc,
NULL, NULL);
if (err) {
if (err && err != LFS_ERR_NOENT) {
return err;
}
if (err == LFS_ERR_NOENT) {
lfsr_omdir_close(lfs, &lfs->gc.o.o);
return (err == LFS_ERR_NOENT) ? 0 : err;
// consider our filesystem checked if we completed a traversal
// with no mutation
cked = !lfsr_f_ismutated(lfs->gc.o.o.flags);
}
// decrement steps
if (steps > 0) {
steps -= 1;
}
}
+9 -14
View File
@@ -310,17 +310,6 @@ struct lfs_config {
// can track 8 blocks.
lfs_size_t lookahead_size;
// How many gc steps to perform on each lfsr_fs_gc call.
//
// Each gc step progresses janitorial work by ~1 block (this is equivalent
// to lfsr_traversal_read). More steps per call may make more progress if
// interleaving with other work.
//
// 0 defaults to 1 step, and -1 will perform a full traversal every call,
// though multiple traversals may still be needed to complete all
// janitorial work.
int32_t gc_steps;
// Threshold for metadata compaction during gc in bytes. Metadata logs
// that exceed this threshold will be compacted during gc operations.
// Defaults to ~88% block_size when zero, though this default may change
@@ -1183,14 +1172,20 @@ int lfsr_fs_ckdata(lfs_t *lfs);
#ifndef LFS_READONLY
// Perform any janitorial work that may be pending.
//
// The exact janitorial work depends on the provided flags. Note multiple
// calls may be required to complete all janitorial work.
// The exact janitorial work depends on the provided flags.
//
// The steps parameter controls how many gc steps to progress before
// returning, with each gc step being ~1 block of work. More steps per call
// will make more progress if interleaved with other filesystem writes, but
// may also introduce more latency. steps=1 will do the minimum amount of
// work to make progress, and steps=-1 will not return until all pending
// janitorial work has been completed.
//
// Calling this function is not required, but may allow the offloading of
// expensive janitorial work to a less time-critical code path.
//
// Returns a negative error code on failure.
int lfsr_fs_gc(lfs_t *lfs, uint32_t flags);
int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags);
#endif
#ifndef LFS_READONLY
-2
View File
@@ -120,7 +120,6 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size);
BENCH_DEFINE(PCACHE_SIZE, LFS_MAX(16, PROG_SIZE) ) \
BENCH_DEFINE(FILE_BUFFER_SIZE, 16 ) \
BENCH_DEFINE(LOOKAHEAD_SIZE, 16 ) \
BENCH_DEFINE(GC_STEPS, 0 ) \
BENCH_DEFINE(GC_COMPACT_THRESH, 0 ) \
BENCH_DEFINE(INLINE_SIZE, BLOCK_SIZE/4 ) \
BENCH_DEFINE(SHRUB_SIZE, INLINE_SIZE ) \
@@ -150,7 +149,6 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size);
.pcache_size = PCACHE_SIZE, \
.file_buffer_size = FILE_BUFFER_SIZE, \
.lookahead_size = LOOKAHEAD_SIZE, \
.gc_steps = GC_STEPS, \
.gc_compact_thresh = GC_COMPACT_THRESH, \
.inline_size = INLINE_SIZE, \
.shrub_size = SHRUB_SIZE, \
-2
View File
@@ -105,7 +105,6 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size);
TEST_DEFINE(PCACHE_SIZE, LFS_MAX(16, PROG_SIZE) ) \
TEST_DEFINE(FILE_BUFFER_SIZE, 16 ) \
TEST_DEFINE(LOOKAHEAD_SIZE, 16 ) \
TEST_DEFINE(GC_STEPS, 0 ) \
TEST_DEFINE(GC_COMPACT_THRESH, 0 ) \
TEST_DEFINE(INLINE_SIZE, BLOCK_SIZE/4 ) \
TEST_DEFINE(SHRUB_SIZE, INLINE_SIZE ) \
@@ -135,7 +134,6 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size);
.pcache_size = PCACHE_SIZE, \
.file_buffer_size = FILE_BUFFER_SIZE, \
.lookahead_size = LOOKAHEAD_SIZE, \
.gc_steps = GC_STEPS, \
.gc_compact_thresh = GC_COMPACT_THRESH, \
.inline_size = INLINE_SIZE, \
.shrub_size = SHRUB_SIZE, \
+73 -80
View File
@@ -41,23 +41,22 @@ code = '''
assert(fsinfo.flags & LFS_I_CANLOOKAHEAD);
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC until our traversal is done
while (true) {
lfsr_fs_gc(&lfs,
// run GC until we make progress
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
LFS_ASSERT(i < 2*BLOCK_COUNT);
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_LOOKAHEAD
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
// internal traversal done?
if (lfs.omdirs != &lfs.gc.o.o) {
lfsr_fs_stat(&lfs, &fsinfo) => 0;
if (!(fsinfo.flags & LFS_I_CANLOOKAHEAD)) {
break;
}
}
// we should have made progress
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(!(fsinfo.flags & LFS_I_CANLOOKAHEAD));
// check the file contents
lfsr_file_open(&lfs, &file, "spider", LFS_O_RDONLY) => 0;
uint8_t rbuf[SIZE];
@@ -106,7 +105,7 @@ code = '''
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC one step
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_LOOKAHEAD
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
@@ -123,7 +122,7 @@ code = '''
// run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_LOOKAHEAD
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
@@ -183,14 +182,14 @@ code = '''
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC one step
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
assert(lfs.omdirs == &lfs.gc.o.o);
// change flags and run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_LOOKAHEAD
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
@@ -250,7 +249,7 @@ code = '''
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC one step
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_LOOKAHEAD
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
@@ -258,7 +257,7 @@ code = '''
// change flags and run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
}
@@ -323,29 +322,26 @@ code = '''
assert(fsinfo.flags & LFS_I_UNCOMPACTED);
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC until our traversal is done (twice for compact)
for (int i = 0; i < 2; i++) {
while (true) {
lfsr_fs_gc(&lfs,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
// run GC until we make progress
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
LFS_ASSERT(i < 2*BLOCK_COUNT);
// internal traversal done?
if (lfs.omdirs != &lfs.gc.o.o) {
break;
}
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
if (!(fsinfo.flags & LFS_I_UNCOMPACTED)) {
break;
}
}
// mdir should have been compacted
assert((file.o.o.mdir.rbyd.eoff & 0x7fffffff) <= GC_COMPACT_THRESH);
// we should have made progress
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(!(fsinfo.flags & LFS_I_UNCOMPACTED));
// check we can still read the file
for (int remount = 0; remount < 2; remount++) {
// remount?
@@ -413,7 +409,7 @@ code = '''
// run GC one traversal + one step
while (true) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -424,7 +420,7 @@ code = '''
break;
}
}
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -441,7 +437,7 @@ code = '''
// run GC until our traversal is done (twice for compact)
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -521,7 +517,7 @@ code = '''
// run GC one traversal + one step
while (true) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
@@ -531,7 +527,7 @@ code = '''
break;
}
}
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
@@ -539,7 +535,7 @@ code = '''
// change flags and run GC until our traversal is done (twice for compact)
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -619,7 +615,7 @@ code = '''
// run GC one traversal + one step
while (true) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -630,7 +626,7 @@ code = '''
break;
}
}
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_COMPACT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -639,7 +635,7 @@ code = '''
// change flags and run GC until our traversal is done (twice for compact)
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
@@ -733,25 +729,24 @@ code = '''
assert(fsinfo.flags & LFS_I_INCONSISTENT);
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC until our traversal is done
while (true) {
lfsr_fs_gc(&lfs,
// run GC until we make progress
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
LFS_ASSERT(i < 2*BLOCK_COUNT);
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_MKCONSISTENT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
| ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0;
// internal traversal done?
if (lfs.omdirs != &lfs.gc.o.o) {
lfsr_fs_stat(&lfs, &fsinfo) => 0;
if (!(fsinfo.flags & LFS_I_INCONSISTENT)) {
break;
}
}
// we should have made progress
lfsr_fs_stat(&lfs, &fsinfo) => 0;
assert(!(fsinfo.flags & LFS_I_INCONSISTENT));
// check we can still read the files
for (int remount = 0; remount < 2; remount++) {
// remount?
@@ -925,7 +920,7 @@ code = '''
// run GC one step
assert(lfs.omdirs != &lfs.gc.o.o);
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_MKCONSISTENT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -951,7 +946,7 @@ code = '''
// run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_MKCONSISTENT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -1057,7 +1052,7 @@ code = '''
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC one step
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -1066,7 +1061,7 @@ code = '''
// change flags and run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_MKCONSISTENT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -1171,7 +1166,7 @@ code = '''
assert(lfs.omdirs != &lfs.gc.o.o);
// run GC one step
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
LFS_GC_MKCONSISTENT
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -1181,7 +1176,7 @@ code = '''
// change flags and run GC until our traversal is done
while (lfs.omdirs == &lfs.gc.o.o) {
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
| ((CKMETA) ? LFS_GC_CKMETA : 0)
@@ -1302,17 +1297,16 @@ code = '''
clobbered:;
// running lfsr_fs_gc should eventually find the clobbered block
while (true) {
int err = lfsr_fs_gc(&lfs, LFS_GC_CKMETA);
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
LFS_ASSERT(i < 2*BLOCK_COUNT);
int err = lfsr_fs_gc(&lfs, GC_STEPS, LFS_GC_CKMETA);
assert(!err || err == LFS_ERR_CORRUPT);
// found it
if (err == LFS_ERR_CORRUPT) {
break;
}
// we should find the clobbered block before finishing the
// traversal
assert(lfs.omdirs == &lfs.gc.o.o);
}
lfsr_unmount(&lfs) => 0;
@@ -1404,17 +1398,16 @@ code = '''
// running lfsr_fs_gc should eventually find the clobbered block
//
// note LFS_GC_CKDATA implies LFS_GC_CKMETA
while (true) {
int err = lfsr_fs_gc(&lfs, LFS_GC_CKDATA);
for (lfs_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
LFS_ASSERT(i < 2*BLOCK_COUNT);
int err = lfsr_fs_gc(&lfs, GC_STEPS, LFS_GC_CKDATA);
assert(!err || err == LFS_ERR_CORRUPT);
// found it
if (err == LFS_ERR_CORRUPT) {
break;
}
// we should find the clobbered block before finishing the
// traversal
assert(lfs.omdirs == &lfs.gc.o.o);
}
lfsr_unmount(&lfs) => 0;
@@ -1603,7 +1596,7 @@ done:;
# pseudo-fuzz test that dirtying still works with the GC API
[cases.test_gc_mutation]
defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000]
defines.STEPS = 100
defines.N = 100
defines.MKCONSISTENT = [false, true]
defines.LOOKAHEAD = [false, true]
defines.COMPACT = [false, true]
@@ -1637,7 +1630,7 @@ code = '''
lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE;
lfsr_file_close(&lfs, &file) => 0;
for (uint32_t i = 0; i < STEPS; i++) {
for (uint32_t i = 0; i < N; i++) {
// rewrite the file every gc cycle
lfsr_file_open(&lfs, &file, "spider",
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
@@ -1648,7 +1641,7 @@ code = '''
lfsr_file_close(&lfs, &file) => 0;
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -1669,7 +1662,7 @@ code = '''
# pseudo-fuzz test that adding/removing flags doesn't break anything
[cases.test_gc_changing_flags]
defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000]
defines.STEPS = 100
defines.N = 100
defines.MKCONSISTENT = [false, true]
defines.LOOKAHEAD = [false, true]
defines.COMPACT = [false, true]
@@ -1703,7 +1696,7 @@ code = '''
lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE;
lfsr_file_close(&lfs, &file) => 0;
for (uint32_t i = 0; i < STEPS; i++) {
for (uint32_t i = 0; i < N; i++) {
// rewrite the file every gc cycle
lfsr_file_open(&lfs, &file, "spider",
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
@@ -1723,7 +1716,7 @@ code = '''
) & TEST_PRNG(&prng);
// gc!
lfsr_fs_gc(&lfs, flags) => 0;
lfsr_fs_gc(&lfs, GC_STEPS, flags) => 0;
}
// check the file contents
@@ -1765,7 +1758,7 @@ code = '''
assert(!err || (TEST_PLS && err == LFS_ERR_EXIST));
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -1943,7 +1936,7 @@ code = '''
}
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -2046,7 +2039,7 @@ code = '''
lfsr_file_close(&lfs, &file) => 0;
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -2245,7 +2238,7 @@ code = '''
}
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -2409,7 +2402,7 @@ code = '''
}
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -2739,7 +2732,7 @@ code = '''
}
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)
@@ -3157,7 +3150,7 @@ code = '''
}
// gc!
lfsr_fs_gc(&lfs,
lfsr_fs_gc(&lfs, GC_STEPS,
((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0)
| ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0)
| ((COMPACT) ? LFS_GC_COMPACT : 0)