Changed gc_steps into a runtime parameter, better dedup mount gc

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

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

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

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

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

---

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

           code          stack
  before: 36476           2680 (+0.0%)
  after:  36316 (-0.4%)   2680 (+0.0%)
This commit is contained in:
Christopher Haster
2024-07-17 01:56:12 -05:00
parent 54ecc94702
commit eced943685
5 changed files with 163 additions and 222 deletions
+81 -124
View File
@@ -12623,13 +12623,13 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags,
int err = lfs_init(lfs,
// strip out the one-time traversal flags
flags
& ~LFS_M_MTREEONLY
& ~LFS_M_MKCONSISTENT
& ~LFS_M_LOOKAHEAD
& ~LFS_M_COMPACT
& ~LFS_M_CKMETA
& ~LFS_M_CKDATA,
flags & ~(
LFS_M_MTREEONLY
| LFS_M_MKCONSISTENT
| LFS_M_LOOKAHEAD
| LFS_M_COMPACT
| LFS_M_CKMETA
| LFS_M_CKDATA),
cfg);
if (err) {
return err;
@@ -12655,73 +12655,17 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags,
lfsr_mtree_weight_(&lfs->mtree) >> lfs->mdir_bits,
1 << lfs->mdir_bits);
// fix pending grms if requested
if (lfsr_t_ismkconsistent(flags)
&& lfsr_grm_count(lfs) > 0) {
if (lfsr_grm_count(lfs) == 2) {
LFS_DEBUG("Fixing grm %"PRId32".%"PRId32" %"PRId32".%"PRId32,
lfsr_mid_bid(lfs, lfs->grm.mids[0]) >> lfs->mdir_bits,
lfsr_mid_rid(lfs, lfs->grm.mids[0]),
lfsr_mid_bid(lfs, lfs->grm.mids[1]) >> lfs->mdir_bits,
lfsr_mid_rid(lfs, lfs->grm.mids[1]));
} else if (lfsr_grm_count(lfs) == 1) {
LFS_DEBUG("Fixing grm %"PRId32".%"PRId32,
lfsr_mid_bid(lfs, lfs->grm.mids[0]) >> lfs->mdir_bits,
lfsr_mid_rid(lfs, lfs->grm.mids[0]));
}
err = lfsr_fs_fixgrm(lfs);
if (err) {
goto failed;
}
}
// run gc until all requested mount work is done
bool mutated = true;
while ((lfsr_t_ismkconsistent(flags)
&& lfsr_f_hasorphans(lfs->flags))
|| (lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& mutated)
|| (lfsr_t_isckdata(flags)
&& mutated)) {
// checkpoint the allocator to maximize any lookahead scans
lfs_alloc_ckpoint(lfs);
// do we really need a full traversal?
uint32_t flags_ = flags;
if (!((lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& mutated)
|| (lfsr_t_isckdata(flags)
&& mutated))) {
flags_ |= LFS_GC_MTREEONLY;
}
lfsr_traversal_t t = LFSR_TRAVERSAL(flags_);
lfsr_omdir_open(lfs, &t.o.o);
while (true) {
err = lfsr_mtree_gc(lfs, &t,
NULL, NULL);
if (err) {
lfsr_omdir_close(lfs, &t.o.o);
if (err == LFS_ERR_NOENT) {
break;
}
goto failed;
}
}
// mutated? we need another pass for ckmeta/ckdata
mutated = lfsr_f_ismutated(t.o.o.flags);
// run gc if requested
err = lfsr_fs_gc(lfs, -1,
flags & (
LFS_M_MTREEONLY
| LFS_M_MKCONSISTENT
| LFS_M_LOOKAHEAD
| LFS_M_COMPACT
| LFS_M_CKMETA
| LFS_M_CKDATA));
if (err) {
goto failed;
}
return 0;
@@ -13078,10 +13022,7 @@ int lfsr_fs_ckdata(lfs_t *lfs) {
}
// perform any pending janitorial work
int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
// some flags don't make sense when only traversing the mtree
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_islookahead(flags));
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_isckdata(flags));
int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) {
// unknown flags?
LFS_ASSERT((flags
& ~LFS_GC_MTREEONLY
@@ -13090,6 +13031,9 @@ int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
& ~LFS_GC_COMPACT
& ~LFS_GC_CKMETA
& ~LFS_GC_CKDATA) == 0);
// some flags don't make sense when only traversing the mtree
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_islookahead(flags));
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_isckdata(flags));
// fix pending grms if requested
if (lfsr_t_ismkconsistent(flags)
@@ -13112,57 +13056,70 @@ int lfsr_fs_gc(lfs_t *lfs, uint32_t flags) {
}
}
// do we need to do anything?
if (!((lfsr_t_ismkconsistent(flags)
&& lfsr_f_hasorphans(lfs->flags))
|| (lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| lfsr_t_isckmeta(flags)
|| lfsr_t_isckdata(flags))) {
return 0;
}
// do we have any pending work?
bool cked = false;
while ((lfs_off_t)steps > 0
&& ((lfsr_t_ismkconsistent(flags)
&& lfsr_f_hasorphans(lfs->flags))
|| (lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& !cked)
|| (lfsr_t_isckdata(flags)
&& !cked))) {
// checkpoint the allocator to maximize any lookahead scans
lfs_alloc_ckpoint(lfs);
// checkpoint the allocator to maximize any lookahead scans
lfs_alloc_ckpoint(lfs);
// existing traversal?
if (lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
// note that we mask flags (except mtreeonly)! if you change flags
// mid-traversal, the result is equivalent to the worst-case set
// of flags
lfs->gc.o.o.flags &= (
~LFS_GC_MKCONSISTENT
& ~LFS_GC_LOOKAHEAD
& ~LFS_GC_COMPACT
& ~LFS_GC_CKMETA
& ~LFS_GC_CKDATA
) | flags;
// start a new traversal
} else {
lfs->gc = LFSR_TRAVERSAL(
flags
// do we really need a full traversal?
| ((!((lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| (lfsr_t_isckmeta(flags)
&& !cked)
|| (lfsr_t_isckdata(flags)
&& !cked)))
? LFS_T_MTREEONLY
: 0));
lfsr_omdir_open(lfs, &lfs->gc.o.o);
}
// do we really need a full traversal?
if (!((lfsr_t_islookahead(flags)
&& lfsr_fs_canlookahead(lfs))
|| (lfsr_t_iscompact(flags)
&& lfsr_i_isuncompacted(lfs->flags))
|| lfsr_t_isckmeta(flags)
|| lfsr_t_isckdata(flags))) {
flags |= LFS_GC_MTREEONLY;
}
// existing traversal?
if (lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
// note that we mask flags (except mtreeonly)! if you change flags
// mid-traversal, the result is equivalent to the worst-case set
// of flags
lfs->gc.o.o.flags &= (
~LFS_GC_MKCONSISTENT
& ~LFS_GC_LOOKAHEAD
& ~LFS_GC_COMPACT
& ~LFS_GC_CKMETA
& ~LFS_GC_CKDATA
) | flags;
// start a new traversal
} else {
lfs->gc = LFSR_TRAVERSAL(flags);
lfsr_omdir_open(lfs, &lfs->gc.o.o);
}
for (uint32_t i = 0;
i < (lfs->cfg->gc_steps ? (uint32_t)lfs->cfg->gc_steps : 1);
i++) {
// progress gc
int err = lfsr_mtree_gc(lfs, &lfs->gc,
NULL, NULL);
if (err) {
if (err && err != LFS_ERR_NOENT) {
return err;
}
if (err == LFS_ERR_NOENT) {
lfsr_omdir_close(lfs, &lfs->gc.o.o);
return (err == LFS_ERR_NOENT) ? 0 : err;
// consider our filesystem checked if we completed a traversal
// with no mutation
cked = !lfsr_f_ismutated(lfs->gc.o.o.flags);
}
// decrement steps
if (steps > 0) {
steps -= 1;
}
}