Restart gc on flag change, better dedup mkconsistent/ckmeta/etc
This simplifies lfsr_fs_gc a bit, and allows lfsr_fs_mkconsistent/
ckmeta/etc to call lfsr_fs_gc directly (it would be a bit strange for
these function to finish up unrelated gc traversals).
Unfortunately, this does risk gc getting stuck constantly restarting if
there is contention between two lfsr_fs_gc calls with different flags,
but you could argue this would be a system design mistake...
The deduplication of traversal state leads to some pretty nice code
savings:
code stack
before: 36316 2680
after: 36068 (-0.7%) 2680 (+0.0%)
This commit is contained in:
@@ -12928,97 +12928,32 @@ failed:;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lfsr_fs_fixorphans(lfs_t *lfs) {
|
||||
// LFS_T_MKCONSISTENT really just removes orphans
|
||||
lfsr_traversal_t t = LFSR_TRAVERSAL(
|
||||
LFS_T_MTREEONLY | LFS_T_MKCONSISTENT);
|
||||
while (true) {
|
||||
int err = lfsr_mtree_gc(lfs, &t,
|
||||
NULL, NULL);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// prepare the filesystem for mutation
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// fix orphaned files
|
||||
//
|
||||
// this must happen after fixgrm, since removing orphaned files risks
|
||||
// outdating the grm
|
||||
//
|
||||
if (lfsr_f_hasorphans(lfs->flags)) {
|
||||
LFS_DEBUG("Fixing orphans...");
|
||||
|
||||
int err = lfsr_fs_fixorphans(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
// leave this up to lfsr_fs_gc
|
||||
return lfsr_fs_gc(lfs, -1, LFS_GC_MTREEONLY | LFS_GC_MKCONSISTENT);
|
||||
}
|
||||
|
||||
// check the filesystem for metadata errors
|
||||
int lfsr_fs_ckmeta(lfs_t *lfs) {
|
||||
// we leave this up to lfsr_mtree_gc
|
||||
lfsr_traversal_t t = LFSR_TRAVERSAL(LFS_T_CKMETA);
|
||||
while (true) {
|
||||
int err = lfsr_mtree_gc(lfs, &t,
|
||||
NULL, NULL);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
// we want a full traversal, so make sure no gc is currently running
|
||||
if (lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
|
||||
lfsr_omdir_close(lfs, &lfs->gc.o.o);
|
||||
}
|
||||
|
||||
return 0;
|
||||
// leave this up to lfsr_fs_gc
|
||||
return lfsr_fs_gc(lfs, -1, LFS_GC_CKMETA);
|
||||
}
|
||||
|
||||
// check the filesystem for metadata + data errors
|
||||
int lfsr_fs_ckdata(lfs_t *lfs) {
|
||||
// we leave this up to lfsr_mtree_gc
|
||||
lfsr_traversal_t t = LFSR_TRAVERSAL(LFS_T_CKMETA | LFS_T_CKDATA);
|
||||
while (true) {
|
||||
int err = lfsr_mtree_gc(lfs, &t,
|
||||
NULL, NULL);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
// we want a full traversal, so make sure no gc is currently running
|
||||
if (lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
|
||||
lfsr_omdir_close(lfs, &lfs->gc.o.o);
|
||||
}
|
||||
|
||||
return 0;
|
||||
// leave this up to lfsr_fs_gc
|
||||
return lfsr_fs_gc(lfs, -1, LFS_GC_CKMETA | LFS_GC_CKDATA);
|
||||
}
|
||||
|
||||
// perform any pending janitorial work
|
||||
@@ -13035,6 +12970,14 @@ 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) {
|
||||
@@ -13072,33 +13015,21 @@ int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) {
|
||||
// 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));
|
||||
// flags mismatch? restart traversal
|
||||
if (lfsr_omdir_isopen(lfs, &lfs->gc.o.o)
|
||||
&& (flags != (lfs->gc.o.o.flags & (
|
||||
LFS_T_MTREEONLY
|
||||
| LFS_T_MKCONSISTENT
|
||||
| LFS_T_LOOKAHEAD
|
||||
| LFS_T_COMPACT
|
||||
| LFS_T_CKMETA
|
||||
| LFS_T_CKDATA)))) {
|
||||
lfsr_omdir_close(lfs, &lfs->gc.o.o);
|
||||
}
|
||||
|
||||
// start a new traversal?
|
||||
if (!lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
|
||||
lfs->gc = LFSR_TRAVERSAL(flags);
|
||||
lfsr_omdir_open(lfs, &lfs->gc.o.o);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user