From 9ed9cf0ccd6e674af270ea7a16c87f9fb80552f9 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 8 Jan 2025 16:02:36 -0600 Subject: [PATCH] gc: Added more tests over info flags, dropped gc_flags default Since we dropped lfsr_gc_setflags/setsteps, it was no longer possible to set gc_flags to zero (perfectly valid and useful for system bringup/ testing things). Supporting gc_flags=0 means it's not possible to provide a default, but this is probably ok as users need to opt-in to LFS_GC anyways. Note that at least gc_steps=0 doesn't make sense, so the default there is reasonable. Fixing this also highlighted that gc_flags/steps are no longer mutable, making the comment in lfs_init out-of-date. Dropping these saves a bit of lfs_t size, so that's nice. And then testing also revealed that LFS_GC_CKDATA implying LFS_GC_CKDATA means it should probably clear the LFS_I_CKMETA flag as well. --- And here I thought this was going to be just a simple test-writing exercise! Code changes: code stack ctx default before: 37792 2608 620 default after: 37792 (-0.0%) 2608 (+0.0%) 620 (+0.0%) gc before: 37896 2608 768 gc after: 37848 (-0.1%) 2608 (+0.0%) 760 (-1.0%) --- lfs.c | 24 +- lfs.h | 5 - tests/test_gc.toml | 552 +++++++++++++++++++++++++++++++++++++- tests/test_mount.toml | 12 +- tests/test_traversal.toml | 62 +++-- 5 files changed, 600 insertions(+), 55 deletions(-) diff --git a/lfs.c b/lfs.c index aeba823b..666c5b0c 100644 --- a/lfs.c +++ b/lfs.c @@ -9646,7 +9646,8 @@ eot:; && !lfsr_t_ismtreeonly(t->o.o.flags) && !lfsr_t_isdirty(t->o.o.flags) && !lfsr_t_ismutated(t->o.o.flags)) { - lfs->flags &= ~LFS_I_CKDATA; + // note ckdata implies ckmeta + lfs->flags &= ~LFS_I_CKDATA & ~LFS_I_CKMETA; } return LFS_ERR_NOENT; @@ -13383,22 +13384,6 @@ 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); - #ifdef LFS_GC - // 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; - } - #endif - return 0; failed:; @@ -14542,7 +14527,10 @@ static int lfsr_fs_gc_(lfs_t *lfs, lfsr_traversal_t *t, // perform any pending janitorial work int lfsr_fs_gc(lfs_t *lfs) { return lfsr_fs_gc_(lfs, &lfs->gc.t, - lfs->gc.flags, lfs->gc.steps); + lfs->cfg->gc_flags, + (lfs->cfg->gc_steps) + ? lfs->cfg->gc_steps + : 1); } #endif diff --git a/lfs.h b/lfs.h index f9264e08..6260c528 100644 --- a/lfs.h +++ b/lfs.h @@ -349,9 +349,6 @@ struct lfs_config { #ifdef LFS_GC // 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; #endif @@ -880,8 +877,6 @@ typedef struct lfs { #ifdef LFS_GC struct { - uint32_t flags; - lfs_soff_t steps; lfsr_traversal_t t; } gc; #endif diff --git a/tests/test_gc.toml b/tests/test_gc.toml index fb87d3d6..901d7151 100644 --- a/tests/test_gc.toml +++ b/tests/test_gc.toml @@ -1050,9 +1050,10 @@ done:; [cases.test_gc_ckmeta_unck] # AFTER=0 => after running lfsr_fs_gc once # AFTER=1 => after running lfsr_fs_gc to completion -# AFTER=2 => after lfsr_fs_ckmeta -# AFTER=3 => after remounting with LFS_M_CKMETA -defines.AFTER = [0, 1, 2, 3] +# AFTER=2 => after running lfsr_traversal_t +# AFTER=3 => after lfsr_fs_ckmeta +# AFTER=4 => after remounting with LFS_M_CKMETA +defines.AFTER = [0, 1, 2, 3, 4] defines.GC_FLAGS = 'LFS_GC_CKMETA' defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.N = [1, 2, 4, 8, 16, 32, 64] @@ -1114,8 +1115,22 @@ code = ''' lfsr_fs_gc(&lfs) => 0; } - // run lfsr_fs_ckmeta + // run lfsr_traversal_t } else if (AFTER == 2) { + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, GC_FLAGS) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + + // run lfsr_fs_ckmeta + } else if (AFTER == 3) { lfsr_fs_ckmeta(&lfs) => 0; struct lfs_fsinfo fsinfo; @@ -1123,7 +1138,7 @@ code = ''' assert(!(fsinfo.flags & LFS_I_CKMETA)); // remount with LFS_M_CKMETA - } else if (AFTER == 3) { + } else if (AFTER == 4) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKMETA, CFG) => 0; @@ -1198,9 +1213,10 @@ done:; [cases.test_gc_ckdata_unck] # AFTER=0 => after running lfsr_fs_gc once # AFTER=1 => after running lfsr_fs_gc to completion -# AFTER=2 => after lfsr_fs_ckdata -# AFTER=3 => after remounting with LFS_M_CKDATA -defines.AFTER = [0, 1, 2] +# AFTER=2 => after running lfsr_traversal_t +# AFTER=3 => after lfsr_fs_ckdata +# AFTER=4 => after remounting with LFS_M_CKDATA +defines.AFTER = [0, 1, 2, 3, 4] defines.GC_FLAGS = 'LFS_GC_CKDATA' defines.GC_STEPS = [-1, 1, 2, 10, 100, 1000] defines.N = [1, 2, 4, 8, 16, 32, 64] @@ -1262,8 +1278,22 @@ code = ''' lfsr_fs_gc(&lfs) => 0; } - // run lfsr_fs_ckdata + // run lfsr_traversal_t } else if (AFTER == 2) { + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, GC_FLAGS) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + + // run lfsr_fs_ckdata + } else if (AFTER == 3) { lfsr_fs_ckdata(&lfs) => 0; struct lfs_fsinfo fsinfo; @@ -1271,7 +1301,7 @@ code = ''' assert(!(fsinfo.flags & LFS_I_CKDATA)); // remount with LFS_M_CKDATA - } else if (AFTER == 3) { + } else if (AFTER == 4) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKDATA, CFG) => 0; @@ -1347,6 +1377,508 @@ done:; ''' +# test that gc work clears flags in lfsr_fs_stat +[cases.test_gc_iflags] +# AFTER=0 => after running lfsr_fs_gc +# AFTER=1 => after running lfsr_traversal_t +# AFTER=2 => after explicit operations +# AFTER=3 => after remounting +defines.AFTER = [0, 1, 2, 3] +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 +defines.N = [1, 2, 4, 8, 16, 32, 64] +defines.SIZE = [ + '0', + 'FILE_BUFFER_SIZE/2', + '2*FILE_BUFFER_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '8*BLOCK_SIZE', +] +if = [ + '(SIZE*N)/BLOCK_SIZE <= 32', + 'LFS_IFDEF_GC(true, AFTER != 0)', +] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; + + // create an interesting filesystem + uint32_t prng = 42; + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "squid%03x", i); + + uint8_t wbuf[SIZE]; + for (lfs_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); + } + + lfsr_file_t file; + lfsr_file_open(&lfs, &file, name, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + } + + // remount to reset flags + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; + + // check that flags were reset + struct lfs_fsinfo fsinfo; + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags == ( + LFS_I_MKCONSISTENT + | LFS_I_LOOKAHEAD + | LFS_I_COMPACT + | LFS_I_CKMETA + | LFS_I_CKDATA)); + + // run gc + if (AFTER == 0) { + #ifdef LFS_GC + lfsr_fs_gc(&lfs) => 0; + #else + assert(false); + #endif + + // run lfsr_traversal_t + } else if (AFTER == 1) { + while (true) { + // it may take multiple traversals to do all pending work + lfsr_fs_stat(&lfs, &fsinfo) => 0; + if (!(fsinfo.flags & ( + ((MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_I_COMPACT : 0) + | ((CKMETA) ? LFS_I_CKMETA : 0) + | ((CKDATA) ? LFS_I_CKDATA : 0)))) { + break; + } + + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, GC_FLAGS) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + // run explicit operations + // + // yes, doing these in separate traversals is inefficient, I don't care + } else if (AFTER == 2) { + while (true) { + // it may take multiple traversals to do all pending work + lfsr_fs_stat(&lfs, &fsinfo) => 0; + if (!(fsinfo.flags & ( + ((MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_I_COMPACT : 0) + | ((CKMETA) ? LFS_I_CKMETA : 0) + | ((CKDATA) ? LFS_I_CKDATA : 0)))) { + break; + } + + if (MKCONSISTENT) { + lfsr_fs_mkconsistent(&lfs) => 0; + } + + if (LOOKAHEAD) { + // we need an explicit traversal for this + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, LFS_T_LOOKAHEAD) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + if (COMPACT) { + // we need an explicit traversal for this + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, LFS_T_COMPACT) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + if (CKMETA) { + lfsr_fs_ckmeta(&lfs) => 0; + } + + if (CKDATA) { + lfsr_fs_ckdata(&lfs) => 0; + } + } + + // remount with gc flags + } else if (AFTER == 3) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | GC_FLAGS, CFG) => 0; + + } else { + assert(false); + } + + // did these clear the right flags? + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags == ( + ((!MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((!COMPACT) ? LFS_I_COMPACT : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) + | ((!CKDATA) ? LFS_I_CKDATA : 0))); + + lfsr_unmount(&lfs) => 0; +''' + +# test that gc work clears flags in lfsr_fs_stat after lfsr_fs_unck +[cases.test_gc_iflags_unck] +# AFTER=0 => after running lfsr_fs_gc +# AFTER=1 => after running lfsr_traversal_t +# AFTER=2 => after explicit operations +# AFTER=3 => after remounting +defines.AFTER = [0, 1, 2, 3] +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 +defines.N = [1, 2, 4, 8, 16, 32, 64] +defines.SIZE = [ + '0', + 'FILE_BUFFER_SIZE/2', + '2*FILE_BUFFER_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '8*BLOCK_SIZE', +] +if = [ + '(SIZE*N)/BLOCK_SIZE <= 32', + 'LFS_IFDEF_GC(true, AFTER != 0)', +] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; + + // create an interesting filesystem + uint32_t prng = 42; + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "squid%03x", i); + + uint8_t wbuf[SIZE]; + for (lfs_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); + } + + lfsr_file_t file; + lfsr_file_open(&lfs, &file, name, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + } + + // remount to reset flags + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; + + // check that flags were reset + struct lfs_fsinfo fsinfo; + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags == ( + LFS_I_MKCONSISTENT + | LFS_I_LOOKAHEAD + | LFS_I_COMPACT + | LFS_I_CKMETA + | LFS_I_CKDATA)); + + // run gc + if (AFTER == 0) { + #ifdef LFS_GC + lfsr_fs_gc(&lfs) => 0; + #else + assert(false); + #endif + + // run lfsr_traversal_t + } else if (AFTER == 1) { + while (true) { + // it may take multiple traversals to do all pending work + lfsr_fs_stat(&lfs, &fsinfo) => 0; + if (!(fsinfo.flags & ( + ((MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_I_COMPACT : 0) + | ((CKMETA) ? LFS_I_CKMETA : 0) + | ((CKDATA) ? LFS_I_CKDATA : 0)))) { + break; + } + + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, GC_FLAGS) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + // run explicit operations + // + // yes, doing these in separate traversals is inefficient, I don't care + } else if (AFTER == 2) { + while (true) { + // it may take multiple traversals to do all pending work + lfsr_fs_stat(&lfs, &fsinfo) => 0; + if (!(fsinfo.flags & ( + ((MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_I_COMPACT : 0) + | ((CKMETA) ? LFS_I_CKMETA : 0) + | ((CKDATA) ? LFS_I_CKDATA : 0)))) { + break; + } + + if (MKCONSISTENT) { + lfsr_fs_mkconsistent(&lfs) => 0; + } + + if (LOOKAHEAD) { + // we need an explicit traversal for this + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, LFS_T_LOOKAHEAD) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + if (COMPACT) { + // we need an explicit traversal for this + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, LFS_T_COMPACT) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + if (CKMETA) { + lfsr_fs_ckmeta(&lfs) => 0; + } + + if (CKDATA) { + lfsr_fs_ckdata(&lfs) => 0; + } + } + + // remount with gc flags + } else if (AFTER == 3) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | GC_FLAGS, CFG) => 0; + + } else { + assert(false); + } + + // did these clear the right flags? + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags == ( + ((!MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((!COMPACT) ? LFS_I_COMPACT : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) + | ((!CKDATA) ? LFS_I_CKDATA : 0))); + + // test that we can reset flags with lfsr_fs_unck + lfsr_fs_unck(&lfs, GC_FLAGS) => 0; + + // check that flags were reset + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags == ( + LFS_I_MKCONSISTENT + | LFS_I_LOOKAHEAD + | LFS_I_COMPACT + // note ckdata implies ckmeta, but uncking ckdata does + // _not_ imply uncking ckmeta + | ((!(CKDATA && !CKMETA)) ? LFS_I_CKMETA : 0) + | LFS_I_CKDATA)); + + // run gc + if (AFTER == 0) { + #ifdef LFS_GC + lfsr_fs_gc(&lfs) => 0; + #else + assert(false); + #endif + + // run lfsr_traversal_t + } else if (AFTER == 1) { + while (true) { + // it may take multiple traversals to do all pending work + lfsr_fs_stat(&lfs, &fsinfo) => 0; + if (!(fsinfo.flags & ( + ((MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_I_COMPACT : 0) + | ((CKMETA) ? LFS_I_CKMETA : 0) + | ((CKDATA) ? LFS_I_CKDATA : 0)))) { + break; + } + + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, GC_FLAGS) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + // run explicit operations + // + // yes, doing these in separate traversals is inefficient, I don't care + } else if (AFTER == 2) { + while (true) { + // it may take multiple traversals to do all pending work + lfsr_fs_stat(&lfs, &fsinfo) => 0; + if (!(fsinfo.flags & ( + ((MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((COMPACT) ? LFS_I_COMPACT : 0) + | ((CKMETA) ? LFS_I_CKMETA : 0) + | ((CKDATA) ? LFS_I_CKDATA : 0)))) { + break; + } + + if (MKCONSISTENT) { + lfsr_fs_mkconsistent(&lfs) => 0; + } + + if (LOOKAHEAD) { + // we need an explicit traversal for this + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, LFS_T_LOOKAHEAD) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + if (COMPACT) { + // we need an explicit traversal for this + lfsr_traversal_t t; + lfsr_traversal_open(&lfs, &t, LFS_T_COMPACT) => 0; + while (true) { + struct lfs_tinfo tinfo; + int err = lfsr_traversal_read(&lfs, &t, &tinfo); + assert(err == 0 || err == LFS_ERR_NOENT); + if (err == LFS_ERR_NOENT) { + break; + } + } + lfsr_traversal_close(&lfs, &t) => 0; + } + + if (CKMETA) { + lfsr_fs_ckmeta(&lfs) => 0; + } + + if (CKDATA) { + lfsr_fs_ckdata(&lfs) => 0; + } + } + + // remount with gc flags + } else if (AFTER == 3) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | GC_FLAGS, CFG) => 0; + + } else { + assert(false); + } + + // did these clear the right flags? + lfsr_fs_stat(&lfs, &fsinfo) => 0; + assert(fsinfo.flags == ( + ((!MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) + | ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) + | ((!COMPACT) ? LFS_I_COMPACT : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) + | ((!CKDATA) ? LFS_I_CKDATA : 0))); + + lfsr_unmount(&lfs) => 0; +''' + + # pseudo-fuzz test that dirtying still works with the GC API [cases.test_gc_mutation] defines.N = 100 diff --git a/tests/test_mount.toml b/tests/test_mount.toml index e59bff4b..c7248a42 100644 --- a/tests/test_mount.toml +++ b/tests/test_mount.toml @@ -71,7 +71,8 @@ code = ''' | ((!MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) | ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) | ((!COMPACT) ? LFS_I_COMPACT : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); lfsr_unmount(&lfs) => 0; @@ -144,7 +145,8 @@ code = ''' assert(fsinfo.flags == ( LFS_I_MKCONSISTENT | LFS_I_COMPACT - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); lfsr_unmount(&lfs) => 0; ''' @@ -215,7 +217,8 @@ code = ''' assert(fsinfo.flags == ( LFS_I_MKCONSISTENT | ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // mdir should have been compacted @@ -314,7 +317,8 @@ code = ''' assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) | ((!COMPACT) ? LFS_I_COMPACT : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the files diff --git a/tests/test_traversal.toml b/tests/test_traversal.toml index 3bc11382..d833f688 100644 --- a/tests/test_traversal.toml +++ b/tests/test_traversal.toml @@ -1710,7 +1710,8 @@ code = ''' ((!MKCONSISTENT) ? LFS_I_MKCONSISTENT : 0) | ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) | ((!COMPACT) ? LFS_I_COMPACT : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); lfsr_unmount(&lfs) => 0; @@ -2823,7 +2824,10 @@ code = ''' ((DESYNC) ? LFS_I_MKCONSISTENT : 0) | ((!(LOOKAHEAD && DESYNC)) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!(CKMETA && DESYNC)) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!(CKMETA && DESYNC) && !(CKDATA && DESYNC)) + ? LFS_I_CKMETA + : 0) | ((!(CKDATA && DESYNC)) ? LFS_I_CKDATA : 0))); lfsr_file_close(&lfs, &file2) => 0; @@ -2929,7 +2933,10 @@ code = ''' ((DESYNC) ? LFS_I_MKCONSISTENT : 0) | ((!(LOOKAHEAD && DESYNC)) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!(CKMETA && DESYNC)) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!(CKMETA && DESYNC) && !(CKDATA && DESYNC)) + ? LFS_I_CKMETA + : 0) | ((!(CKDATA && DESYNC)) ? LFS_I_CKDATA : 0))); lfsr_file_close(&lfs, &file2) => 0; @@ -3028,7 +3035,10 @@ code = ''' ((DESYNC) ? LFS_I_MKCONSISTENT : 0) | ((!(LOOKAHEAD && DESYNC)) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!(CKMETA && DESYNC)) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!(CKMETA && DESYNC) && !(CKDATA && DESYNC)) + ? LFS_I_CKMETA + : 0) | ((!(CKDATA && DESYNC)) ? LFS_I_CKDATA : 0))); lfsr_file_close(&lfs, &file2) => 0; @@ -3124,7 +3134,10 @@ code = ''' ((DESYNC) ? LFS_I_MKCONSISTENT : 0) | ((!(LOOKAHEAD && DESYNC)) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!(CKMETA && DESYNC)) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!(CKMETA && DESYNC) && !(CKDATA && DESYNC)) + ? LFS_I_CKMETA + : 0) | ((!(CKDATA && DESYNC)) ? LFS_I_CKDATA : 0))); // check the file contents @@ -5448,7 +5461,8 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the file @@ -5587,7 +5601,8 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the file @@ -5700,7 +5715,8 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the file @@ -5851,7 +5867,8 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -6067,7 +6084,8 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -6290,7 +6308,8 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -6451,7 +6470,8 @@ code = ''' assert(fsinfo.flags == ( ((!LOOKAHEAD || ORPHANS > 0) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!CKMETA || ORPHANS > 0) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | (((!CKMETA && !CKDATA) || ORPHANS > 0) ? LFS_I_CKMETA : 0) | ((!CKDATA || ORPHANS > 0) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -6591,7 +6611,8 @@ code = ''' ((ORPHANS >= 3) ? LFS_I_MKCONSISTENT : 0) | ((!LOOKAHEAD || ORPHANS > 0) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!CKMETA || ORPHANS > 0) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | (((!CKMETA && !CKDATA) || ORPHANS > 0) ? LFS_I_CKMETA : 0) | ((!CKDATA || ORPHANS > 0) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -6750,7 +6771,8 @@ code = ''' assert(fsinfo.flags == ( ((!LOOKAHEAD || ORPHANS > 0) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!CKMETA || ORPHANS > 0) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | (((!CKMETA && !CKDATA) || ORPHANS > 0) ? LFS_I_CKMETA : 0) | ((!CKDATA || ORPHANS > 0) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -6907,7 +6929,8 @@ code = ''' assert(fsinfo.flags == ( ((!LOOKAHEAD || ORPHANS > 0) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!CKMETA || ORPHANS > 0) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | (((!CKMETA && !CKDATA) || ORPHANS > 0) ? LFS_I_CKMETA : 0) | ((!CKDATA || ORPHANS > 0) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -7075,7 +7098,8 @@ code = ''' assert(fsinfo.flags == ( ((!LOOKAHEAD || ORPHANS > 0) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!CKMETA || ORPHANS > 0) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | (((!CKMETA && !CKDATA) || ORPHANS > 0) ? LFS_I_CKMETA : 0) | ((!CKDATA || ORPHANS > 0) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -7241,7 +7265,8 @@ code = ''' assert(fsinfo.flags == ( ((!LOOKAHEAD || ORPHANS > 0) ? LFS_I_LOOKAHEAD : 0) | LFS_I_COMPACT - | ((!CKMETA || ORPHANS > 0) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | (((!CKMETA && !CKDATA) || ORPHANS > 0) ? LFS_I_CKMETA : 0) | ((!CKDATA || ORPHANS > 0) ? LFS_I_CKDATA : 0))); // check we can still read the files @@ -7432,7 +7457,8 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((!LOOKAHEAD) ? LFS_I_LOOKAHEAD : 0) - | ((!CKMETA) ? LFS_I_CKMETA : 0) + // note ckdata implies ckmeta + | ((!CKMETA && !CKDATA) ? LFS_I_CKMETA : 0) | ((!CKDATA) ? LFS_I_CKDATA : 0))); // check we can still read the files