From 5d756fe6982b4e66a00acce1aa855c6e37985639 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 6 Jan 2025 15:59:51 -0600 Subject: [PATCH] gc: Tweaked lfsr_gc API to be more stateful Before: int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags); After: int lfsr_gc(lfs_t *lfs); int lfsr_gc_setflags(lfs_t *lfs, uint32_t flags); int lfsr_gc_setsteps(lfs_t *lfs, lfs_soff_t steps); --- The interesting thing about the lfsr_gc API is that the caller will often be very different from whoever configures the system. One example being an OS calling lfsr_gc in a background loop, while leaving configuration up to the user. The idea here, is instead of forcing the OS to come up with its own stateful system to pass flags to lfsr_gc, we just embed this state in littlefs directly. The whole point of lfsr_gc is that it's a stateful system anyways. Unfortunately this state does require a bit more logic to maintain, which adds code/ctx cost: code stack ctx before: 37812 2608 752 after: 37916 (+0.3%) 2608 (+0.0%) 768 (+2.1%) --- lfs.c | 347 ++++++++++++----------- lfs.h | 79 ++++-- runners/bench_runner.h | 4 + runners/test_runner.h | 4 + tests/test_attrs.toml | 12 +- tests/test_ck.toml | 16 +- tests/test_gc.toml | 611 +++++++++++++++++++++++++---------------- 7 files changed, 644 insertions(+), 429 deletions(-) diff --git a/lfs.c b/lfs.c index 2e2c9eb1..fc5e09d9 100644 --- a/lfs.c +++ b/lfs.c @@ -8733,7 +8733,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } // we may have touched any number of mdirs, so assume uncompacted - // until lfsr_fs_gc can prove otherwise + // until lfsr_gc can prove otherwise lfs->flags |= LFS_I_UNCOMPACTED; // update any gstate changes @@ -13155,6 +13155,15 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, // // wear-leveling. // LFS_ASSERT(lfs->cfg->block_cycles != 0); + // unknown gc flags? + LFS_ASSERT((lfs->cfg->gc_flags & ~( + LFS_GC_MTREEONLY + | LFS_GC_MKCONSISTENT + | LFS_GC_LOOKAHEAD + | LFS_GC_COMPACT + | LFS_GC_CKMETA + | LFS_GC_CKDATA)) == 0); + // check that gc_compact_thresh makes sense // // metadata can't be compacted below block_size/2, and metadata can't @@ -13176,7 +13185,7 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, // assume we may contain orphans until proven otherwise | LFS_I_UNTIDY // default to assuming we need compaction somewhere, worst case - // this just makes lfsr_fs_gc read more than is strictly needed + // this just makes lfsr_gc read more than is strictly needed | LFS_I_UNCOMPACTED; // copy block_count so we can mutate it @@ -13352,6 +13361,20 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, lfs_memset(lfs->grm_p, 0, LFSR_GRM_DSIZE); lfs_memset(lfs->grm_d, 0, LFSR_GRM_DSIZE); + // setup gc state, this can be mutated which is why we need a copy + if (lfs->cfg->gc_flags) { + lfs->gc.flags = lfs->cfg->gc_flags; + } else { + lfs->gc.flags = LFS_GC_MKCONSISTENT + | LFS_GC_LOOKAHEAD + | LFS_GC_COMPACT; + } + if (lfs->cfg->gc_steps) { + lfs->gc.steps = lfs->cfg->gc_steps; + } else { + lfs->gc.steps = 1; + } + return 0; failed:; @@ -13897,6 +13920,9 @@ static int lfsr_mountinited(lfs_t *lfs) { return 0; } +// needed in lfsr_mount +static int lfsr_gc_(lfs_t *lfs, uint32_t flags, lfs_soff_t steps); + int lfsr_mount(lfs_t *lfs, uint32_t flags, const struct lfs_config *cfg) { // unknown flags? @@ -13951,14 +13977,15 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags, | LFS_M_COMPACT | LFS_M_CKMETA | LFS_M_CKDATA)) { - err = lfsr_fs_gc(lfs, -1, + err = lfsr_gc_(lfs, flags & ( LFS_M_MTREEONLY | LFS_M_MKCONSISTENT | LFS_M_LOOKAHEAD | LFS_M_COMPACT | LFS_M_CKMETA - | LFS_M_CKDATA)); + | LFS_M_CKDATA), + -1); if (err) { goto failed; } @@ -13990,8 +14017,9 @@ failed:; int lfsr_unmount(lfs_t *lfs) { // all files/dirs should be closed before lfsr_unmount LFS_ASSERT(lfs->omdirs == NULL - || (lfs->omdirs == &lfs->gc.o.o - && lfs->gc.o.o.next == NULL)); + // special case for our gc traversal handle + || (lfs->omdirs == &lfs->gc.t.o.o + && lfs->gc.t.o.o.next == NULL)); return lfs_deinit(lfs); } @@ -14125,12 +14153,13 @@ int lfsr_format(lfs_t *lfs, uint32_t flags, | LFS_F_COMPACT | LFS_F_CKMETA | LFS_F_CKDATA)) { - err = lfsr_fs_gc(lfs, -1, + err = lfsr_gc_(lfs, flags & ( LFS_F_MTREEONLY | LFS_F_COMPACT | LFS_F_CKMETA - | LFS_F_CKDATA)); + | LFS_F_CKDATA), + -1); if (err) { goto failed; } @@ -14209,6 +14238,18 @@ lfs_ssize_t lfsr_fs_size(lfs_t *lfs) { // consistency stuff static int lfsr_fs_fixgrm(lfs_t *lfs) { + 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])); + } + while (lfsr_grm_count(lfs) > 0) { LFS_ASSERT(lfs->grm.mids[0] != -1); @@ -14316,18 +14357,6 @@ int lfsr_fs_mkconsistent(lfs_t *lfs) { // fix pending grms if (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])); - } - int err = lfsr_fs_fixgrm(lfs); if (err) { return err; @@ -14376,134 +14405,8 @@ int lfsr_fs_ckdata(lfs_t *lfs) { return lfsr_fs_ck(lfs, LFS_T_CKMETA | LFS_T_CKDATA); } -// perform any pending janitorial work -int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) { - // unknown flags? - LFS_ASSERT((flags & ~( - LFS_GC_MTREEONLY - | LFS_GC_MKCONSISTENT - | LFS_GC_LOOKAHEAD - | LFS_GC_COMPACT - | LFS_GC_CKMETA - | LFS_GC_CKDATA)) == 0); - // these flags require a writable filesystem - LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_ismkconsistent(flags)); - LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_islookahead(flags)); - LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_iscompact(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)); - - // 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])); - } - - int err = lfsr_fs_fixgrm(lfs); - if (err) { - return err; - } - } - - // do we have any pending work? - uint32_t pending = flags & ( - (lfs->flags & ( - LFS_I_UNTIDY - | LFS_I_UNCOMPACTED)) - | ((lfsr_fs_canlookahead(lfs)) ? LFS_GC_LOOKAHEAD : 0) - | LFS_GC_CKMETA - | LFS_GC_CKDATA); - - while (pending && (lfs_off_t)steps > 0) { - // checkpoint the allocator to maximize any lookahead scans - lfs_alloc_ckpoint(lfs); - - // start a new traversal? - if (!lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) { - lfsr_traversal_init(&lfs->gc, pending); - lfsr_omdir_open(lfs, &lfs->gc.o.o); - } - - // mask flags, we can't trust existing traversals to make - // progress if flags change - lfs->gc.o.o.flags &= ( - pending | ~( - LFS_GC_MKCONSISTENT - | LFS_GC_LOOKAHEAD - | LFS_GC_COMPACT - | LFS_GC_CKMETA - | LFS_GC_CKDATA)); - - // don't bother with lookahead if we've mutated - if (lfsr_t_isdirty(lfs->gc.o.o.flags) - || lfsr_t_ismutated(lfs->gc.o.o.flags)) { - lfs->gc.o.o.flags &= ~LFS_GC_LOOKAHEAD; - } - - // will this traversal still make progress? no? start over - if (!(lfs->gc.o.o.flags & ( - LFS_GC_MKCONSISTENT - | LFS_GC_LOOKAHEAD - | LFS_GC_COMPACT - | LFS_GC_CKMETA - | LFS_GC_CKDATA))) { - lfsr_omdir_close(lfs, &lfs->gc.o.o); - continue; - } - - // do we really need a full traversal? - if (!(lfs->gc.o.o.flags & ( - LFS_GC_LOOKAHEAD - | LFS_GC_CKMETA - | LFS_GC_CKDATA))) { - lfs->gc.o.o.flags |= LFS_T_MTREEONLY; - } - - // progress gc - int err = lfsr_mtree_gc(lfs, &lfs->gc, - NULL, NULL); - if (err && err != LFS_ERR_NOENT) { - return err; - } - - // end of traversal? - if (err == LFS_ERR_NOENT) { - lfsr_omdir_close(lfs, &lfs->gc.o.o); - - // clear any pending flags we make progress on - pending &= ( - (lfs->flags & ( - LFS_I_UNTIDY - | LFS_I_UNCOMPACTED)) - | ((lfsr_fs_canlookahead(lfs)) ? LFS_GC_LOOKAHEAD : 0) - // only consider our filesystem checked if we - // weren't mutated - | ((lfsr_t_isdirty(lfs->gc.o.o.flags) - || lfsr_t_ismutated(lfs->gc.o.o.flags)) - ? LFS_GC_CKMETA | LFS_GC_CKDATA - : 0)); - } - - // decrement steps - if (steps > 0) { - steps -= 1; - } - } - - return 0; -} - +// attempt to grow the filesystem int lfsr_fs_grow(lfs_t *lfs, lfs_size_t block_count_) { // filesystem must be writeable LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags)); @@ -14564,7 +14467,6 @@ failed:; } - /// High-level filesystem traversal /// // needed in lfsr_traversal_open @@ -14619,18 +14521,6 @@ int lfsr_traversal_read(lfs_t *lfs, lfsr_traversal_t *t, // operation introduced new grms if (lfsr_t_ismkconsistent(t->o.o.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])); - } - // swap dirty/mutated flags while mutating t->o.o.flags = lfsr_t_swapdirty(t->o.o.flags); @@ -14746,6 +14636,143 @@ int lfsr_traversal_rewind(lfs_t *lfs, lfsr_traversal_t *t) { +/// Incremental gc operations /// + +int lfsr_gc_setflags(lfs_t *lfs, uint32_t flags) { + // unknown gc flags? + LFS_ASSERT((flags & ~( + LFS_GC_MTREEONLY + | LFS_GC_MKCONSISTENT + | LFS_GC_LOOKAHEAD + | LFS_GC_COMPACT + | LFS_GC_CKMETA + | LFS_GC_CKDATA)) == 0); + + // clobber any existing traversals + if (lfsr_omdir_isopen(lfs, &lfs->gc.t.o.o)) { + lfsr_omdir_close(lfs, &lfs->gc.t.o.o); + } + + lfs->gc.flags = flags; + return 0; +} + +int lfsr_gc_setsteps(lfs_t *lfs, lfs_soff_t steps) { + lfs->gc.steps = steps; + return 0; +} + +// perform any pending janitorial work +static int lfsr_gc_(lfs_t *lfs, uint32_t flags, lfs_soff_t steps) { + // unknown gc flags? + // + // we should have check these earlier, but it doesn't hurt to + // double check + LFS_ASSERT((flags & ~( + LFS_GC_MTREEONLY + | LFS_GC_MKCONSISTENT + | LFS_GC_LOOKAHEAD + | LFS_GC_COMPACT + | LFS_GC_CKMETA + | LFS_GC_CKDATA)) == 0); + // these flags require a writable filesystem + LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_ismkconsistent(flags)); + LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_islookahead(flags)); + LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_iscompact(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)); + + // fix pending grms if requested + if (lfsr_t_ismkconsistent(flags) + && lfsr_grm_count(lfs) > 0) { + int err = lfsr_fs_fixgrm(lfs); + if (err) { + return err; + } + } + + // do we have any pending work? + uint32_t pending = flags & ( + (lfs->flags & ( + LFS_I_UNTIDY + | LFS_I_UNCOMPACTED)) + | ((lfsr_fs_canlookahead(lfs)) ? LFS_GC_LOOKAHEAD : 0) + | LFS_GC_CKMETA + | LFS_GC_CKDATA); + + while (pending && (lfs_off_t)steps > 0) { + // checkpoint the allocator to maximize any lookahead scans + lfs_alloc_ckpoint(lfs); + + // start a new traversal? + if (!lfsr_omdir_isopen(lfs, &lfs->gc.t.o.o)) { + lfsr_traversal_init(&lfs->gc.t, pending); + lfsr_omdir_open(lfs, &lfs->gc.t.o.o); + } + + // don't bother with lookahead if we've mutated + if (lfsr_t_isdirty(lfs->gc.t.o.o.flags) + || lfsr_t_ismutated(lfs->gc.t.o.o.flags)) { + lfs->gc.t.o.o.flags &= ~LFS_GC_LOOKAHEAD; + } + + // will this traversal still make progress? no? start over + if (!(lfs->gc.t.o.o.flags & ( + LFS_GC_MKCONSISTENT + | LFS_GC_LOOKAHEAD + | LFS_GC_COMPACT + | LFS_GC_CKMETA + | LFS_GC_CKDATA))) { + lfsr_omdir_close(lfs, &lfs->gc.t.o.o); + continue; + } + + // do we really need a full traversal? + if (!(lfs->gc.t.o.o.flags & ( + LFS_GC_LOOKAHEAD + | LFS_GC_CKMETA + | LFS_GC_CKDATA))) { + lfs->gc.t.o.o.flags |= LFS_T_MTREEONLY; + } + + // progress gc + int err = lfsr_mtree_gc(lfs, &lfs->gc.t, + NULL, NULL); + if (err && err != LFS_ERR_NOENT) { + return err; + } + + // end of traversal? + if (err == LFS_ERR_NOENT) { + lfsr_omdir_close(lfs, &lfs->gc.t.o.o); + + // clear any pending flags we make progress on + pending &= ( + (lfs->flags & ( + LFS_I_UNTIDY + | LFS_I_UNCOMPACTED)) + | ((lfsr_fs_canlookahead(lfs)) ? LFS_GC_LOOKAHEAD : 0) + // only consider our filesystem checked if we + // weren't mutated + | ((lfsr_t_isdirty(lfs->gc.t.o.o.flags) + || lfsr_t_ismutated(lfs->gc.t.o.o.flags)) + ? LFS_GC_CKMETA | LFS_GC_CKDATA + : 0)); + } + + // decrement steps + if (steps > 0) { + steps -= 1; + } + } + + return 0; +} + +int lfsr_gc(lfs_t *lfs) { + return lfsr_gc_(lfs, lfs->gc.flags, lfs->gc.steps); +} diff --git a/lfs.h b/lfs.h index 6afdae24..f36c4ef3 100644 --- a/lfs.h +++ b/lfs.h @@ -352,6 +352,24 @@ struct lfs_config { // can track 8 blocks. lfs_size_t lookahead_size; + // Flags indicating what gc work to do during lfsr_gc calls. + // + // Defaults to LFS_GC_MKCONSISTENT + LFS_GC_LOOKAHEAD + + // LFS_GC_COMPACT when zero. + uint32_t gc_flags; + + // Number of gc steps to perform in each call to lfsr_gc, with each + // step being ~1 block of work. + // + // More steps per call will make more progress if interleaved with + // other filesystem operations, 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. + // + // Defaults to steps=1 when zero. + lfs_soff_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 @@ -862,7 +880,11 @@ typedef struct lfs { uint8_t grm_d[LFSR_GRM_DSIZE]; // TODO allow compile time opt-out to reclaim RAM - lfsr_traversal_t gc; + struct { + uint32_t flags; + lfs_soff_t steps; + lfsr_traversal_t t; + } gc; } lfs_t; @@ -1229,6 +1251,42 @@ int lfsr_traversal_read(lfs_t *lfs, lfsr_traversal_t *t, int lfsr_traversal_rewind(lfs_t *lfs, lfsr_traversal_t *t); +/// Incremental gc operations /// + +#ifndef LFS_READONLY +// Perform any janitorial work that may be pending. +// +// The exact janitorial work depends on the configured flags and steps. +// +// 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_gc(lfs_t *lfs); +#endif + +#ifndef LFS_READONLY +// Sets the gc flags. +// +// Returns a negative error code on failure. +int lfsr_gc_setflags(lfs_t *lfs, uint32_t flags); +#endif + +#ifndef LFS_READONLY +// Sets the number of gc steps per lfsr_gc call, with each step being +// ~1 block of work. +// +// More steps per call will make more progress if interleaved with +// other filesystem operations, 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. +// +// Returns a negative error code on failure. +int lfsr_gc_setsteps(lfs_t *lfs, lfs_soff_t steps); +#endif + + /// Filesystem-level filesystem operations // Find on-disk info about the filesystem @@ -1283,25 +1341,6 @@ int lfsr_fs_ckmeta(lfs_t *lfs); int lfsr_fs_ckdata(lfs_t *lfs); #endif -#ifndef LFS_READONLY -// Perform any janitorial work that may be pending. -// -// 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, lfs_soff_t steps, uint32_t flags); -#endif - #ifndef LFS_READONLY // Change the number of blocks used by the filesystem // diff --git a/runners/bench_runner.h b/runners/bench_runner.h index b34864a2..3b925b56 100644 --- a/runners/bench_runner.h +++ b/runners/bench_runner.h @@ -114,6 +114,8 @@ 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_FLAGS, 0 ) \ + BENCH_DEFINE(GC_STEPS, 0 ) \ BENCH_DEFINE(GC_COMPACT_THRESH, 0 ) \ BENCH_DEFINE(INLINE_SIZE, BLOCK_SIZE/4 ) \ BENCH_DEFINE(SHRUB_SIZE, INLINE_SIZE ) \ @@ -143,6 +145,8 @@ 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_flags = GC_FLAGS, \ + .gc_steps = GC_STEPS, \ .gc_compact_thresh = GC_COMPACT_THRESH, \ .inline_size = INLINE_SIZE, \ .shrub_size = SHRUB_SIZE, \ diff --git a/runners/test_runner.h b/runners/test_runner.h index 4835d2ea..97c5eef7 100644 --- a/runners/test_runner.h +++ b/runners/test_runner.h @@ -105,6 +105,8 @@ 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_FLAGS, 0 ) \ + TEST_DEFINE(GC_STEPS, 0 ) \ TEST_DEFINE(GC_COMPACT_THRESH, 0 ) \ TEST_DEFINE(INLINE_SIZE, BLOCK_SIZE/4 ) \ TEST_DEFINE(SHRUB_SIZE, INLINE_SIZE ) \ @@ -134,6 +136,8 @@ 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_flags = GC_FLAGS, \ + .gc_steps = GC_STEPS, \ .gc_compact_thresh = GC_COMPACT_THRESH, \ .inline_size = INLINE_SIZE, \ .shrub_size = SHRUB_SIZE, \ diff --git a/tests/test_attrs.toml b/tests/test_attrs.toml index c0d51e48..382988b2 100644 --- a/tests/test_attrs.toml +++ b/tests/test_attrs.toml @@ -490,6 +490,8 @@ defines.FILETYPE = [0, 1, 2] defines.M = 40 defines.SIZE = 4 defines.COMPACT = [false, true] +defines.GC_FLAGS = 'LFS_GC_COMPACT' +defines.GC_STEPS = -1 defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' code = ''' lfs_t lfs; @@ -527,7 +529,7 @@ code = ''' // try compacting? if (COMPACT) { - lfsr_fs_gc(&lfs, -1, LFS_GC_COMPACT) => 0; + lfsr_gc(&lfs) => 0; } for (int remount = 0; remount < 2; remount++) { @@ -567,6 +569,8 @@ defines.N = 64 defines.M = 4 defines.SIZE = 4 defines.COMPACT = [false, true] +defines.GC_FLAGS = 'LFS_GC_COMPACT' +defines.GC_STEPS = -1 defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' code = ''' lfs_t lfs; @@ -605,7 +609,7 @@ code = ''' // try compacting? if (COMPACT) { - lfsr_fs_gc(&lfs, -1, LFS_GC_COMPACT) => 0; + lfsr_gc(&lfs) => 0; } for (int remount = 0; remount < 2; remount++) { @@ -4067,6 +4071,8 @@ defines.N = 64 defines.M = 4 defines.SIZE = 4 defines.COMPACT = [false, true] +defines.GC_FLAGS = 'LFS_GC_COMPACT' +defines.GC_STEPS = -1 defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' code = ''' lfs_t lfs; @@ -4105,7 +4111,7 @@ code = ''' // try compacting? if (COMPACT) { - lfsr_fs_gc(&lfs, -1, LFS_GC_COMPACT) => 0; + lfsr_gc(&lfs) => 0; } for (int remount = 0; remount < 2; remount++) { diff --git a/tests/test_ck.toml b/tests/test_ck.toml index c319f439..b1ed4d2c 100644 --- a/tests/test_ck.toml +++ b/tests/test_ck.toml @@ -8,10 +8,12 @@ after = ['test_traversal', 'test_gc', 'test_mount'] # test we can detect at least fully clobbered blocks [cases.test_ck_ckmeta_easy] # METHOD=0 => lfsr_fs_ckmeta -# METHOD=1 => lfsr_fs_gc +# METHOD=1 => lfsr_gc # METHOD=2 => lfsr_traversal_read # METHOD=3 => lfsr_mount defines.METHOD = [0, 1, 2, 3] +defines.GC_FLAGS = 'LFS_GC_CKMETA' +defines.GC_STEPS = -1 defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', @@ -94,9 +96,9 @@ code = ''' if (METHOD == 0) { lfsr_fs_ckmeta(&lfs) => LFS_ERR_CORRUPT; - // find clobbered blocks with lfsr_fs_gc + // find clobbered blocks with lfsr_gc } else if (METHOD == 1) { - lfsr_fs_gc(&lfs, -1, LFS_GC_CKMETA) => LFS_ERR_CORRUPT; + lfsr_gc(&lfs) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_traversal_read } else if (METHOD == 2) { @@ -136,10 +138,12 @@ done:; [cases.test_ck_ckdata_easy] # METHOD=0 => lfsr_fs_ckdata -# METHOD=1 => lfsr_fs_gc +# METHOD=1 => lfsr_gc # METHOD=2 => lfsr_traversal_read # METHOD=3 => lfsr_mount defines.METHOD = [0, 1, 2, 3] +defines.GC_FLAGS = 'LFS_GC_CKDATA' +defines.GC_STEPS = -1 defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', @@ -223,9 +227,9 @@ code = ''' if (METHOD == 0) { lfsr_fs_ckdata(&lfs) => LFS_ERR_CORRUPT; - // find clobbered blocks with lfsr_fs_gc + // find clobbered blocks with lfsr_gc } else if (METHOD == 1) { - lfsr_fs_gc(&lfs, -1, LFS_GC_CKDATA) => LFS_ERR_CORRUPT; + lfsr_gc(&lfs) => LFS_ERR_CORRUPT; // find clobbered blocks with lfsr_traversal_read } else if (METHOD == 2) { diff --git a/tests/test_gc.toml b/tests/test_gc.toml index b5147b48..0353dd16 100644 --- a/tests/test_gc.toml +++ b/tests/test_gc.toml @@ -1,14 +1,19 @@ # Test GC things -# most of the GC logic is tested in test_traversal, we just test a few -# GC-specific things here +# most of the GC logic is tested in test_traversal, we just test +# GC-API specific things here after = ['test_traversal'] # test that lookahead can make progress in isolation [cases.test_gc_lookahead_progress] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_LOOKAHEAD + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -39,17 +44,14 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_CANLOOKAHEAD); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // 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; + lfsr_gc(&lfs) => 0; lfsr_fs_stat(&lfs, &fsinfo) => 0; if (!(fsinfo.flags & LFS_I_CANLOOKAHEAD)) { @@ -67,11 +69,143 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -# test that lookahead dirtying still works with the GC API -[cases.test_gc_lookahead_mutation] -defines.GC_STEPS = 1 +# test that we can change flags after mount +[cases.test_gc_setflags] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.SIZE = [ + 'FILE_BUFFER_SIZE/2', + '2*FILE_BUFFER_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '8*BLOCK_SIZE', +] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; + + uint32_t prng = 42; + + // create a file + lfsr_file_t file; + lfsr_file_open(&lfs, &file, "spider", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + uint8_t wbuf[SIZE]; + for (lfs_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); + } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // expect dirty initial state or else our test doesn't work + struct lfs_fsinfo fsinfo; + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags & LFS_I_CANLOOKAHEAD); + assert(lfs.omdirs != &lfs.gc.t.o.o); + + // change flags + lfsr_gc_setflags(&lfs, GC_FLAGS | LFS_GC_LOOKAHEAD) => 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); + + lfsr_gc(&lfs) => 0; + + lfsr_fs_stat(&lfs, &fsinfo) => 0; + if (!(fsinfo.flags & LFS_I_CANLOOKAHEAD)) { + break; + } + } + + // check the file contents + lfsr_file_open(&lfs, &file, "spider", LFS_O_RDONLY) => 0; + uint8_t rbuf[SIZE]; + lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test that we can change steps after mount +[cases.test_gc_setsteps] +defines.CKMETA = [false, true] +defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_LOOKAHEAD + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = 1 +defines.SIZE = [ + 'FILE_BUFFER_SIZE/2', + '2*FILE_BUFFER_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '8*BLOCK_SIZE', +] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; + + uint32_t prng = 42; + + // create a file + lfsr_file_t file; + lfsr_file_open(&lfs, &file, "spider", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + uint8_t wbuf[SIZE]; + for (lfs_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); + } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // expect dirty initial state or else our test doesn't work + struct lfs_fsinfo fsinfo; + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags & LFS_I_CANLOOKAHEAD); + assert(lfs.omdirs != &lfs.gc.t.o.o); + + // change steps + lfsr_gc_setsteps(&lfs, -1) => 0; + + // run GC + lfsr_gc(&lfs) => 0; + + // 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]; + lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test that lookahead dirtying still works with the GC API +[cases.test_gc_lookahead_mutation] +defines.CKMETA = [false, true] +defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_LOOKAHEAD + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -104,14 +238,11 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_CANLOOKAHEAD); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one step - lfsr_fs_gc(&lfs, GC_STEPS, - LFS_GC_LOOKAHEAD - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // mutate the filesystem lfsr_file_open(&lfs, &file, "spider", @@ -123,11 +254,8 @@ code = ''' lfsr_file_close(&lfs, &file) => 0; // run GC until our traversal is done - while (lfs.omdirs == &lfs.gc.o.o) { - lfsr_fs_gc(&lfs, GC_STEPS, - LFS_GC_LOOKAHEAD - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -146,9 +274,12 @@ code = ''' # test that adding flags doesn't break lookahead [cases.test_gc_lookahead_add_flags] -defines.GC_STEPS = 1 defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -181,20 +312,17 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_CANLOOKAHEAD); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one step - lfsr_fs_gc(&lfs, GC_STEPS, - ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // change flags and run GC until our traversal is done - while (lfs.omdirs == &lfs.gc.o.o) { - lfsr_fs_gc(&lfs, GC_STEPS, - LFS_GC_LOOKAHEAD - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc_setflags(&lfs, GC_FLAGS | LFS_GC_LOOKAHEAD) => 0; + + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -213,9 +341,13 @@ code = ''' # test that removing flags invalidates lookahead [cases.test_gc_lookahead_remove_flags] -defines.GC_STEPS = 1 defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_LOOKAHEAD + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -248,20 +380,17 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_CANLOOKAHEAD); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one step - lfsr_fs_gc(&lfs, GC_STEPS, - LFS_GC_LOOKAHEAD - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // change flags and run GC until our traversal is done - while (lfs.omdirs == &lfs.gc.o.o) { - lfsr_fs_gc(&lfs, GC_STEPS, - ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc_setflags(&lfs, GC_FLAGS & ~LFS_GC_LOOKAHEAD) => 0; + + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -281,10 +410,18 @@ code = ''' # test that compact can make progress in isolation [cases.test_gc_compact_progress] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.LOOKAHEAD = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_COMPACT + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] +# set compact thresh to minimum +defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -293,8 +430,6 @@ defines.SIZE = [ '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] -# set compact thresh to minimum -defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; @@ -322,18 +457,14 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_UNCOMPACTED); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // 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_COMPACT - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; lfsr_fs_stat(&lfs, &fsinfo) => 0; if (!(fsinfo.flags & LFS_I_UNCOMPACTED)) { @@ -366,10 +497,17 @@ code = ''' # test that compact dirtying still works with the GC API [cases.test_gc_compact_mutation] -defines.GC_STEPS = 1 defines.LOOKAHEAD = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_COMPACT + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +# set compact thresh to minimum +defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -378,8 +516,6 @@ defines.SIZE = [ '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] -# set compact thresh to minimum -defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' # we need something to keep the traversal running if = 'CKMETA || CKDATA' code = ''' @@ -409,27 +545,19 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_UNCOMPACTED); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one traversal + one step while (true) { - 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_gc(&lfs) => 0; // internal traversal done? - if (lfs.omdirs != &lfs.gc.o.o) { + if (lfs.omdirs != &lfs.gc.t.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; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // mutate the filesystem lfsr_file_rewind(&lfs, &file) => 0; @@ -440,12 +568,8 @@ code = ''' lfsr_file_sync(&lfs, &file) => 0; // run GC until our traversal is done (twice for compact) - while (lfs.omdirs == &lfs.gc.o.o) { - 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; + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -474,10 +598,16 @@ code = ''' # test that adding flags doesn't break compact [cases.test_gc_compact_add_flags] -defines.GC_STEPS = 1 defines.LOOKAHEAD = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +# set compact thresh to minimum +defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -486,8 +616,6 @@ defines.SIZE = [ '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] -# set compact thresh to minimum -defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' # we need something to keep the traversal running if = 'CKMETA || CKDATA' code = ''' @@ -517,33 +645,25 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_UNCOMPACTED); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one traversal + one step while (true) { - lfsr_fs_gc(&lfs, GC_STEPS, - ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; // internal traversal done? - if (lfs.omdirs != &lfs.gc.o.o) { + if (lfs.omdirs != &lfs.gc.t.o.o) { break; } } - lfsr_fs_gc(&lfs, GC_STEPS, - ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // change flags and run GC until our traversal is done (twice for compact) - while (lfs.omdirs == &lfs.gc.o.o) { - 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_gc_setflags(&lfs, GC_FLAGS | LFS_GC_COMPACT) => 0; + + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -572,10 +692,17 @@ code = ''' # test that removing flags invalidates compact [cases.test_gc_compact_remove_flags] -defines.GC_STEPS = 1 defines.LOOKAHEAD = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_COMPACT + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +# set compact thresh to minimum +defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -584,8 +711,6 @@ defines.SIZE = [ '2*BLOCK_SIZE', '8*BLOCK_SIZE', ] -# set compact thresh to minimum -defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' # we need something to keep the traversal running if = 'CKMETA || CKDATA' code = ''' @@ -615,34 +740,25 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_UNCOMPACTED); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one traversal + one step while (true) { - 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_gc(&lfs) => 0; // internal traversal done? - if (lfs.omdirs != &lfs.gc.o.o) { + if (lfs.omdirs != &lfs.gc.t.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; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // change flags and run GC until our traversal is done (twice for compact) - while (lfs.omdirs == &lfs.gc.o.o) { - lfsr_fs_gc(&lfs, GC_STEPS, - ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc_setflags(&lfs, GC_FLAGS & ~LFS_GC_COMPACT) => 0; + + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -672,11 +788,18 @@ code = ''' # test that mkconsistent can make progress in isolation [cases.test_gc_mkconsistent_progress] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_MKCONSISTENT + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.SIZE = 'FILE_BUFFER_SIZE/2' # <=2 => grm-able # >2 => requires orphans @@ -731,19 +854,14 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_INCONSISTENT); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // 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; + lfsr_gc(&lfs) => 0; lfsr_fs_stat(&lfs, &fsinfo) => 0; if (!(fsinfo.flags & LFS_I_INCONSISTENT)) { @@ -835,7 +953,7 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_INCONSISTENT); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // call lfsr_fs_mkconsistent lfsr_fs_mkconsistent(&lfs) => 0; @@ -873,11 +991,17 @@ code = ''' # test that mkconsistent dirtying still works with the GC API [cases.test_gc_mkconsistent_mutation] -defines.GC_STEPS = 1 defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_MKCONSISTENT + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' defines.SIZE = 'FILE_BUFFER_SIZE/2' # <=2 => grm-able # >2 => requires orphans @@ -925,14 +1049,9 @@ code = ''' } // run GC one step - assert(lfs.omdirs != &lfs.gc.o.o); - 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; - assert(lfs.omdirs == &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // create the rest of the orphans after GC has started for (lfs_size_t i = 0; i < ORPHANS; i++) { @@ -951,13 +1070,8 @@ code = ''' assert(fsinfo.flags & LFS_I_INCONSISTENT); // run GC until our traversal is done - while (lfs.omdirs == &lfs.gc.o.o) { - 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; + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -993,11 +1107,16 @@ code = ''' # test that adding flags doesn't break mkconsistent [cases.test_gc_mkconsistent_add_flags] -defines.GC_STEPS = 1 defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' defines.SIZE = 'FILE_BUFFER_SIZE/2' # <=2 => grm-able # >2 => requires orphans @@ -1055,24 +1174,17 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_INCONSISTENT); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one step - lfsr_fs_gc(&lfs, GC_STEPS, - ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // change flags and run GC until our traversal is done - while (lfs.omdirs == &lfs.gc.o.o) { - 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; + lfsr_gc_setflags(&lfs, GC_FLAGS | LFS_GC_MKCONSISTENT) => 0; + + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -1108,11 +1220,17 @@ code = ''' # test that removing flags invalidates mkconsistent [cases.test_gc_mkconsistent_remove_flags] -defines.GC_STEPS = 1 defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + LFS_GC_MKCONSISTENT + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' defines.SIZE = 'FILE_BUFFER_SIZE/2' # <=2 => grm-able # >2 => requires orphans @@ -1169,24 +1287,17 @@ code = ''' struct lfs_fsinfo fsinfo; lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags & LFS_I_INCONSISTENT); - assert(lfs.omdirs != &lfs.gc.o.o); + assert(lfs.omdirs != &lfs.gc.t.o.o); // run GC one step - 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; - assert(lfs.omdirs == &lfs.gc.o.o); + lfsr_gc(&lfs) => 0; + assert(lfs.omdirs == &lfs.gc.t.o.o); // change flags and run GC until our traversal is done - while (lfs.omdirs == &lfs.gc.o.o) { - lfsr_fs_gc(&lfs, GC_STEPS, - ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc_setflags(&lfs, GC_FLAGS & ~LFS_GC_MKCONSISTENT) => 0; + + while (lfs.omdirs == &lfs.gc.t.o.o) { + lfsr_gc(&lfs) => 0; } // we should _not_ make progress @@ -1225,6 +1336,7 @@ code = ''' # # these are tested more thoroughly in test_ck [cases.test_gc_ckmeta] +defines.GC_FLAGS = 'LFS_GC_CKMETA' defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ @@ -1304,12 +1416,12 @@ code = ''' } clobbered:; - // running lfsr_fs_gc should eventually find the clobbered block + // running lfsr_gc should eventually find the clobbered block 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); + int err = lfsr_gc(&lfs); assert(!err || err == LFS_ERR_CORRUPT); // found it if (err == LFS_ERR_CORRUPT) { @@ -1323,6 +1435,7 @@ done:; ''' [cases.test_gc_ckdata] +defines.GC_FLAGS = 'LFS_GC_CKDATA' defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ @@ -1403,14 +1516,14 @@ code = ''' } clobbered:; - // running lfsr_fs_gc should eventually find the clobbered block + // running lfsr_gc should eventually find the clobbered block // // note LFS_GC_CKDATA implies 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_CKDATA); + int err = lfsr_gc(&lfs); assert(!err || err == LFS_ERR_CORRUPT); // found it if (err == LFS_ERR_CORRUPT) { @@ -1603,13 +1716,20 @@ 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.N = 100 defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.SIZE = [ @@ -1649,12 +1769,7 @@ code = ''' lfsr_file_close(&lfs, &file) => 0; // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } // check the file contents @@ -1669,13 +1784,20 @@ 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.N = 100 defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.SIZE = [ @@ -1715,16 +1837,11 @@ code = ''' lfsr_file_close(&lfs, &file) => 0; // choose a new subset of flags every cycle - uint32_t flags = ( - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0) - ) & TEST_PRNG(&prng); + uint32_t flags = GC_FLAGS & TEST_PRNG(&prng); + lfsr_gc_setflags(&lfs, flags) => 0; // gc! - lfsr_fs_gc(&lfs, GC_STEPS, flags) => 0; + lfsr_gc(&lfs) => 0; } // check the file contents @@ -1743,12 +1860,19 @@ code = ''' # [cases.test_gc_spam_dir_many] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256] @@ -1766,12 +1890,7 @@ code = ''' assert(!err || (TEST_PLS && err == LFS_ERR_EXIST)); // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } for (int remount = 0; remount < 2; remount++) { @@ -1838,12 +1957,19 @@ code = ''' ''' [cases.test_gc_spam_dir_fuzz] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256] @@ -1944,12 +2070,7 @@ code = ''' } // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } for (int remount = 0; remount < 2; remount++) { @@ -2004,12 +2125,19 @@ code = ''' ''' [cases.test_gc_spam_file_many] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.N = [1, 2, 4, 8, 16, 32, 64] @@ -2047,12 +2175,7 @@ code = ''' lfsr_file_close(&lfs, &file) => 0; // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } for (int remount = 0; remount < 2; remount++) { @@ -2093,12 +2216,19 @@ code = ''' ''' [cases.test_gc_spam_file_fuzz] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.N = [1, 2, 4, 8, 16, 32, 64] @@ -2246,12 +2376,7 @@ code = ''' } // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } for (int remount = 0; remount < 2; remount++) { @@ -2321,12 +2446,19 @@ code = ''' ''' [cases.test_gc_spam_fwrite_fuzz] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.OPS = 20 @@ -2410,12 +2542,7 @@ code = ''' } // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } lfsr_file_close(&lfs, &file) => 0; @@ -2469,12 +2596,19 @@ code = ''' ''' [cases.test_gc_spam_uz_fuzz] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.N = [1, 2, 4, 8, 16, 32, 64] @@ -2740,12 +2874,7 @@ code = ''' } // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } // check that disk matches our simulation @@ -2825,12 +2954,19 @@ code = ''' ''' [cases.test_gc_spam_uzd_fuzz] -defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] +defines.GC_FLAGS = ''' + ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_GC_COMPACT : 0) + | ((CKMETA) ? LFS_GC_CKMETA : 0) + | ((CKDATA) ? LFS_GC_CKDATA : 0) +''' +defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] # set compact thresh to minimum defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' defines.N = [1, 2, 4, 8, 16, 32, 64] @@ -3158,12 +3294,7 @@ code = ''' } // gc! - lfsr_fs_gc(&lfs, GC_STEPS, - ((MKCONSISTENT) ? LFS_GC_MKCONSISTENT : 0) - | ((LOOKAHEAD) ? LFS_GC_LOOKAHEAD : 0) - | ((COMPACT) ? LFS_GC_COMPACT : 0) - | ((CKMETA) ? LFS_GC_CKMETA : 0) - | ((CKDATA) ? LFS_GC_CKDATA : 0)) => 0; + lfsr_gc(&lfs) => 0; } // check that disk matches our simulation