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:
@@ -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,74 +12655,18 @@ 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);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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,31 +13056,22 @@ int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
|
||||
}
|
||||
}
|
||||
|
||||
// do we need to do anything?
|
||||
if (!((lfsr_t_ismkconsistent(flags)
|
||||
// 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)
|
||||
|| lfsr_t_isckdata(flags))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|| (lfsr_t_isckmeta(flags)
|
||||
&& !cked)
|
||||
|| (lfsr_t_isckdata(flags)
|
||||
&& !cked))) {
|
||||
// checkpoint the allocator to maximize any lookahead scans
|
||||
lfs_alloc_ckpoint(lfs);
|
||||
|
||||
// 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
|
||||
@@ -13151,18 +13086,40 @@ int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
|
||||
) | flags;
|
||||
// start a new traversal
|
||||
} else {
|
||||
lfs->gc = LFSR_TRAVERSAL(flags);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, \
|
||||
|
||||
@@ -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, \
|
||||
|
||||
+68
-75
@@ -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,
|
||||
// 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;
|
||||
|
||||
// internal traversal done?
|
||||
if (lfs.omdirs != &lfs.gc.o.o) {
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user