trv: Reverted LFS3_t_NOSPC, forward gbmap repop errors
Note: This affects the blocking lfs3_alloc_repopgbmap as well as
incremental gc/traversal repopulations. Now all repop attempts return
LFS3_ERR_NOSPC when we don't have space for the gbmap, motivation below.
This reverts the previous LFS3_t_NOSPC soft error, in which traversals
were allowed to continue some gc/traversal work when encountering
LFS3_ERR_NOSPC. This results in a simpler implementation and fewer error
cases to worry about.
Observation/motivation:
- The main motivation is noticing that when we're in low-space
conditions, we just start spamming gbmap repops even if they all fail.
That's really not great! We might as well just mark the flash as dead
if we're going to start spamming erases!
At least with an error the user can call rmgbmap to try to make
progress.
- If we're in a low-space condition, something else will probably return
LFS3_ERR_NOSPC anyways. Might as well report this early and simplify
our system.
- It's a simpler model, and littlefs3 is already much more complicated
than littlefs2. Maybe we should lean more towards a simpler system
at the cost of some niche optimizations.
---
This had the side-effect of causing more lfs3_alloc_ckpoints to return
errors during testing, which revealed a bug in our uz/uzd_fuzz tests:
- We weren't flushing after writes to the opened RDWR files, which could
cause delayed errors to occur during the later read checks in the
test.
Fortunately LFS3_O_FLUSH provides a quick and easy fix!
Note we _don't_ adopt this in all uz/uzd_fuzz tests, only those that
error. It's good to test both with and without LFS3_O_FLUSH to test
that read-flushing also works under stress.
Saves a bit of code:
code stack ctx
before: 37260 2352 688
after: 37220 (-0.1%) 2352 (+0.0%) 688 (+0.0%)
code stack ctx
gbmap before: 40220 2368 856
gbmap after: 40184 (-0.1%) 2368 (+0.0%) 856 (+0.0%)
This commit is contained in:
@@ -7461,7 +7461,7 @@ static inline void lfs3_t_settstate(uint32_t *flags, uint8_t tstate) {
|
||||
}
|
||||
|
||||
static inline uint8_t lfs3_t_btype(uint32_t flags) {
|
||||
return (flags >> 20) & 0x7;
|
||||
return (flags >> 20) & 0xf;
|
||||
}
|
||||
|
||||
static inline uint32_t lfs3_t_btypeflags(uint8_t btype) {
|
||||
@@ -7484,10 +7484,6 @@ static inline bool lfs3_t_isckpointed(uint32_t flags) {
|
||||
return flags & LFS3_t_CKPOINTED;
|
||||
}
|
||||
|
||||
static inline bool lfs3_t_isnospc(uint32_t flags) {
|
||||
return flags & LFS3_t_NOSPC;
|
||||
}
|
||||
|
||||
// mount flags
|
||||
static inline bool lfs3_m_isrdonly(uint32_t flags) {
|
||||
(void)flags;
|
||||
@@ -9827,6 +9823,8 @@ static int lfs3_mdir_commit(lfs3_t *lfs3, lfs3_mdir_t *mdir,
|
||||
// checkpoint the allocator
|
||||
int err = lfs3_alloc_ckpoint(lfs3);
|
||||
if (err) {
|
||||
// revert gstate to on-disk state
|
||||
lfs3_fs_revertgdelta(lfs3);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -10684,19 +10682,10 @@ static lfs3_stag_t lfs3_mtree_gc(lfs3_t *lfs3, lfs3_mgc_t *mgc,
|
||||
// erased/bad info and (2) try to best use any available
|
||||
// erased-state
|
||||
int err = lfs3_alloc_zerogbmap(lfs3, &mgc->gbmap_);
|
||||
if (err && err != LFS3_ERR_NOSPC) {
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// not having enough space isn't really an error
|
||||
if (err == LFS3_ERR_NOSPC) {
|
||||
LFS3_WARN("Not enough space for gbmap "
|
||||
"(lookahead %"PRId32"/%"PRId32")",
|
||||
lfs3->lookahead.known,
|
||||
lfs3->block_count);
|
||||
mgc->t.b.h.flags |= LFS3_t_NOSPC;
|
||||
}
|
||||
|
||||
// keep our own ckpointed flag clear
|
||||
mgc->t.b.h.flags &= ~LFS3_t_CKPOINTED;
|
||||
}
|
||||
@@ -10733,19 +10722,10 @@ dropped:;
|
||||
&& !lfs3_t_isckpointed(mgc->t.b.h.flags)) {
|
||||
int err = lfs3_gbmap_markbptr(lfs3, &mgc->gbmap_, tag, bptr_,
|
||||
LFS3_TAG_BMINUSE);
|
||||
if (err && err != LFS3_ERR_NOSPC) {
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// not having enough space isn't really an error
|
||||
if (err == LFS3_ERR_NOSPC) {
|
||||
LFS3_WARN("Not enough space for gbmap "
|
||||
"(lookahead %"PRId32"/%"PRId32")",
|
||||
lfs3->lookahead.known,
|
||||
lfs3->block_count);
|
||||
mgc->t.b.h.flags |= LFS3_t_NOSPC;
|
||||
}
|
||||
|
||||
// keep our own ckpointed flag clear
|
||||
mgc->t.b.h.flags &= ~LFS3_t_CKPOINTED;
|
||||
}
|
||||
@@ -10758,19 +10738,10 @@ dropped:;
|
||||
lfs3_mdir_t *mdir = (lfs3_mdir_t*)bptr_->d.u.buffer;
|
||||
uint32_t dirty = mgc->t.b.h.flags;
|
||||
int err = lfs3_mdir_mkconsistent(lfs3, mdir);
|
||||
if (err && err != LFS3_ERR_NOSPC) {
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// not having enough space isn't really an error
|
||||
if (err == LFS3_ERR_NOSPC) {
|
||||
LFS3_WARN("Not enough space for mkconsistent "
|
||||
"(lookahead %"PRId32"/%"PRId32")",
|
||||
lfs3->lookahead.known,
|
||||
lfs3->block_count);
|
||||
mgc->t.b.h.flags |= LFS3_t_NOSPC;
|
||||
}
|
||||
|
||||
// reset dirty flag
|
||||
mgc->t.b.h.flags &= ~LFS3_t_DIRTY | dirty;
|
||||
// make sure we clear any zombie flags
|
||||
@@ -10807,19 +10778,10 @@ dropped:;
|
||||
// compact the mdir
|
||||
uint32_t dirty = mgc->t.b.h.flags;
|
||||
int err = lfs3_mdir_compact(lfs3, mdir);
|
||||
if (err && err != LFS3_ERR_NOSPC) {
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// not having enough space isn't really an error
|
||||
if (err == LFS3_ERR_NOSPC) {
|
||||
LFS3_WARN("Not enough space for compactmeta "
|
||||
"(lookahead %"PRId32"/%"PRId32")",
|
||||
lfs3->lookahead.known,
|
||||
lfs3->block_count);
|
||||
mgc->t.b.h.flags |= LFS3_t_NOSPC;
|
||||
}
|
||||
|
||||
// reset dirty flag
|
||||
mgc->t.b.h.flags &= ~LFS3_t_DIRTY | dirty;
|
||||
}
|
||||
@@ -10841,8 +10803,7 @@ eot:;
|
||||
&& lfs3_f_isgbmap(lfs3->flags)
|
||||
&& lfs3_t_isrepopgbmap(lfs3->flags)
|
||||
&& !lfs3_t_ismtreeonly(mgc->t.b.h.flags)
|
||||
&& !lfs3_t_isckpointed(mgc->t.b.h.flags)
|
||||
&& !lfs3_t_isnospc(mgc->t.b.h.flags),
|
||||
&& !lfs3_t_isckpointed(mgc->t.b.h.flags),
|
||||
false)) {
|
||||
#ifdef LFS3_GBMAP
|
||||
lfs3_alloc_adoptgbmap(lfs3, &mgc->gbmap_, lfs3->lookahead.ckpoint);
|
||||
@@ -10857,16 +10818,14 @@ eot:;
|
||||
|
||||
// was mkconsistent successful?
|
||||
if (lfs3_t_ismkconsistent(mgc->t.b.h.flags)
|
||||
&& !lfs3_t_isdirty(mgc->t.b.h.flags)
|
||||
&& !lfs3_t_isnospc(mgc->t.b.h.flags)) {
|
||||
&& !lfs3_t_isdirty(mgc->t.b.h.flags)) {
|
||||
lfs3->flags &= ~LFS3_I_MKCONSISTENT;
|
||||
}
|
||||
|
||||
// was compaction successful? note we may need multiple passes if
|
||||
// we want to be sure everything is compacted
|
||||
if (lfs3_t_compactmeta(mgc->t.b.h.flags)
|
||||
&& !lfs3_t_ismutated(mgc->t.b.h.flags)
|
||||
&& !lfs3_t_isnospc(mgc->t.b.h.flags)) {
|
||||
&& !lfs3_t_ismutated(mgc->t.b.h.flags)) {
|
||||
lfs3->flags &= ~LFS3_I_COMPACTMETA;
|
||||
}
|
||||
#endif
|
||||
@@ -11578,7 +11537,7 @@ static int lfs3_alloc_repopgbmap(lfs3_t *lfs3) {
|
||||
// erased-state
|
||||
int err = lfs3_alloc_zerogbmap(lfs3, &gbmap_);
|
||||
if (err) {
|
||||
goto failed;
|
||||
return err;
|
||||
}
|
||||
|
||||
// traverse the filesystem, building up knowledge of what blocks are
|
||||
@@ -11593,15 +11552,14 @@ static int lfs3_alloc_repopgbmap(lfs3_t *lfs3) {
|
||||
if (tag == LFS3_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
err = tag;
|
||||
goto failed;
|
||||
return tag;
|
||||
}
|
||||
|
||||
// track in-use blocks
|
||||
err = lfs3_gbmap_markbptr(lfs3, &gbmap_, tag, &bptr,
|
||||
LFS3_TAG_BMINUSE);
|
||||
if (err) {
|
||||
goto failed;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11614,17 +11572,6 @@ static int lfs3_alloc_repopgbmap(lfs3_t *lfs3) {
|
||||
//
|
||||
lfs3_alloc_adoptgbmap(lfs3, &gbmap_, lfs3->lookahead.ckpoint);
|
||||
return 0;
|
||||
|
||||
failed:;
|
||||
// not having enough space for the gbmap isn't really an error
|
||||
if (err == LFS3_ERR_NOSPC) {
|
||||
LFS3_INFO("Not enough space for gbmap "
|
||||
"(lookahead %"PRId32"/%"PRId32")",
|
||||
lfs3->lookahead.known,
|
||||
lfs3->block_count);
|
||||
return 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user