From 631bfbc1e826e74bdc1f53fd2c8a8f3cebc7a75a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 17 Jul 2024 16:24:48 -0500 Subject: [PATCH] gc: Made lfsr_fs_gc a bit smarter when flags change Now we consider if it's still possible for the current traversal to make progress. If it can, we continue with the relevant masked flags, otherwise we restart. This should prevent us from traversing the filesystem for no reason. I also reverted the ckedmeta/ckeddata flags, these ended up just adding code cost. We're not in the stack hot-path anyways... Code changes: code stack before: 36244 2680 after: 36228 (-0.0%) 2680 (+0.0%) --- lfs.c | 88 ++++++++++++++++++++++++++++++++--------------------------- lfs.h | 2 -- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/lfs.c b/lfs.c index 025f6a8d..e4ee991a 100644 --- a/lfs.c +++ b/lfs.c @@ -5924,14 +5924,6 @@ static inline bool lfsr_f_hasorphans(uint32_t flags) { return flags & LFS_F_ORPHANS; } -static inline bool lfsr_f_hasckedmeta(uint32_t flags) { - return flags & LFS_F_CKEDMETA; -} - -static inline bool lfsr_f_hasckeddata(uint32_t flags) { - return flags & LFS_F_CKEDDATA; -} - // on-demand flags // needed in lfsr_fs_isinconsistent @@ -13040,14 +13032,6 @@ int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) { LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_islookahead(flags)); LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_isckdata(flags)); - // do we really need a full traversal? - if (!(lfsr_t_islookahead(flags) - || lfsr_t_iscompact(flags) - || lfsr_t_isckmeta(flags) - || lfsr_t_isckdata(flags))) { - flags |= LFS_T_MTREEONLY; - } - // fix pending grms if requested if (lfsr_t_ismkconsistent(flags) && lfsr_grm_count(lfs) > 0) { @@ -13069,42 +13053,54 @@ int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) { } } - // every time we call lfsr_fs_gc with ckmeta/ckdata, assume we want - // a new traversal - lfs->flags &= ~(LFS_F_CKEDMETA | LFS_F_CKEDDATA); - // do we have any pending work? - 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_f_hasckedmeta(lfs->flags)) - || (lfsr_t_isckdata(flags) - && !lfsr_f_hasckeddata(lfs->flags)))) { + uint32_t pending = flags & ( + ((lfsr_f_hasorphans(lfs->flags)) ? LFS_GC_MKCONSISTENT : 0) + | ((lfsr_fs_canlookahead(lfs)) ? LFS_GC_LOOKAHEAD : 0) + | ((lfsr_i_isuncompacted(lfs->flags)) ? LFS_GC_COMPACT : 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)) { - lfs->gc = LFSR_TRAVERSAL(flags); + lfs->gc = LFSR_TRAVERSAL(pending); lfsr_omdir_open(lfs, &lfs->gc.o.o); // existing traversal? } else { - // note that we mask flags (except mtreeonly)! if you change flags - // mid-traversal, the result is equivalent to the worst-case set - // of flags + // mask flags, we can't trust existing traversals to make + // progress if flags change lfs->gc.o.o.flags &= ~( LFS_GC_MKCONSISTENT | LFS_GC_LOOKAHEAD | LFS_GC_COMPACT | LFS_GC_CKMETA | LFS_GC_CKDATA - ) | flags; + ) | pending; + + // 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_COMPACT + | LFS_GC_CKMETA + | LFS_GC_CKDATA))) { + lfs->gc.o.o.flags |= LFS_T_MTREEONLY; } // progress gc @@ -13114,13 +13110,25 @@ int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) { return err; } + // end of traversal? if (err == LFS_ERR_NOENT) { lfsr_omdir_close(lfs, &lfs->gc.o.o); - // consider our filesystem checked if we complete at least - // one traversal - lfs->flags |= ((lfsr_t_isckmeta(flags)) ? LFS_F_CKEDMETA : 0) - | ((lfsr_t_isckdata(flags)) ? LFS_F_CKEDDATA : 0); + // clear any pending flags we make progress on + pending &= ~( + ((!lfsr_f_hasorphans(lfs->flags)) + ? LFS_GC_MKCONSISTENT + : 0) + | ((!lfsr_fs_canlookahead(lfs)) + ? LFS_GC_LOOKAHEAD + : 0) + | ((!lfsr_i_isuncompacted(lfs->flags)) + ? LFS_GC_COMPACT + : 0) + // consider our filesystem checked if we complete at + // least one traversal + | LFS_GC_CKMETA + | LFS_GC_CKDATA); } // decrement steps diff --git a/lfs.h b/lfs.h index 8a30cadf..ed5ed342 100644 --- a/lfs.h +++ b/lfs.h @@ -140,8 +140,6 @@ enum lfs_fsinfo_flags { // internally used flags LFS_F_ORPHANS = 0x8000, // Filesystem may have untracked orphans - LFS_F_CKEDMETA = 0x2000, // Filesystem metadata checked during gc - LFS_F_CKEDDATA = 0x4000, // Filesystem data checked during gc }; // File types