mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-01 12:20:02 +00:00
trv: Added LFS3_t_NOSPC, avoid ENOSPC errors in traversals
This relaxes error encountered during lfs3_mtree_gc to _not_ propagate,
but instead just log a warning and prevent the relevant work from being
checked off during EOT.
The idea is this allows other work to make progress in low-space
conditions.
I originally meant to limit this to gbmap repopulations, to match the
behavior of lfs3_alloc_repopgbmap, but I think extending the idea to all
filesystem mutating operations makes sense (LFS3_T_MKCONSISTENT +
LFS3_T_REPOPGBMAP + LFS3_T_COMPACTMETA).
---
To avoid incorrectly marking traversal work as completed, we need to
track if we hit any ENOSPC errors, thus the new LFS3_t_NOSPC flag:
LFS3_t_NOSPC 0x00800000 Optional gc work ran out of space
Not the happiest just throwing flags at problems, but I can't think of a
better solution at the moment.
This doesn't differentiate between ENOSPC errors during the different
types of work, but in theory if we're hitting ENOSPC errors whatever
work returns the error is a toss-up anyways.
---
Adds a bit of code:
code stack ctx
before: 37208 2352 688
after: 37248 (+0.1%) 2352 (+0.0%) 688 (+0.0%)
code stack ctx
gbmap before: 40120 2368 856
gbmap after: 40204 (+0.2%) 2368 (+0.0%) 856 (+0.0%)
This commit is contained in:
61
lfs3.c
61
lfs3.c
@ -7449,7 +7449,7 @@ static inline void lfs3_t_settstate(uint32_t *flags, uint8_t tstate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t lfs3_t_btype(uint32_t flags) {
|
static inline uint8_t lfs3_t_btype(uint32_t flags) {
|
||||||
return (flags >> 20) & 0x0f;
|
return (flags >> 20) & 0x7;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t lfs3_t_btypeflags(uint8_t btype) {
|
static inline uint32_t lfs3_t_btypeflags(uint8_t btype) {
|
||||||
@ -7472,6 +7472,10 @@ static inline bool lfs3_t_isckpointed(uint32_t flags) {
|
|||||||
return flags & LFS3_t_CKPOINTED;
|
return flags & LFS3_t_CKPOINTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool lfs3_t_isnospc(uint32_t flags) {
|
||||||
|
return flags & LFS3_t_NOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
// mount flags
|
// mount flags
|
||||||
static inline bool lfs3_m_isrdonly(uint32_t flags) {
|
static inline bool lfs3_m_isrdonly(uint32_t flags) {
|
||||||
(void)flags;
|
(void)flags;
|
||||||
@ -10668,10 +10672,19 @@ 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/bad info and (2) try to best use any available
|
||||||
// erased-state
|
// erased-state
|
||||||
int err = lfs3_alloc_zerogbmap(lfs3, &mgc->gbmap_);
|
int err = lfs3_alloc_zerogbmap(lfs3, &mgc->gbmap_);
|
||||||
if (err) {
|
if (err && err != LFS3_ERR_NOSPC) {
|
||||||
return 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
|
// keep our own ckpointed flag clear
|
||||||
mgc->t.b.h.flags &= ~LFS3_t_CKPOINTED;
|
mgc->t.b.h.flags &= ~LFS3_t_CKPOINTED;
|
||||||
}
|
}
|
||||||
@ -10708,10 +10721,19 @@ dropped:;
|
|||||||
&& !lfs3_t_isckpointed(mgc->t.b.h.flags)) {
|
&& !lfs3_t_isckpointed(mgc->t.b.h.flags)) {
|
||||||
int err = lfs3_gbmap_markbptr(lfs3, &mgc->gbmap_, tag, bptr_,
|
int err = lfs3_gbmap_markbptr(lfs3, &mgc->gbmap_, tag, bptr_,
|
||||||
LFS3_TAG_BMINUSE);
|
LFS3_TAG_BMINUSE);
|
||||||
if (err) {
|
if (err && err != LFS3_ERR_NOSPC) {
|
||||||
return 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
|
// keep our own ckpointed flag clear
|
||||||
mgc->t.b.h.flags &= ~LFS3_t_CKPOINTED;
|
mgc->t.b.h.flags &= ~LFS3_t_CKPOINTED;
|
||||||
}
|
}
|
||||||
@ -10724,9 +10746,19 @@ dropped:;
|
|||||||
lfs3_mdir_t *mdir = (lfs3_mdir_t*)bptr_->d.u.buffer;
|
lfs3_mdir_t *mdir = (lfs3_mdir_t*)bptr_->d.u.buffer;
|
||||||
uint32_t dirty = mgc->t.b.h.flags;
|
uint32_t dirty = mgc->t.b.h.flags;
|
||||||
int err = lfs3_mdir_mkconsistent(lfs3, mdir);
|
int err = lfs3_mdir_mkconsistent(lfs3, mdir);
|
||||||
if (err) {
|
if (err && err != LFS3_ERR_NOSPC) {
|
||||||
return 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
|
// reset dirty flag
|
||||||
mgc->t.b.h.flags &= ~LFS3_t_DIRTY | dirty;
|
mgc->t.b.h.flags &= ~LFS3_t_DIRTY | dirty;
|
||||||
// make sure we clear any zombie flags
|
// make sure we clear any zombie flags
|
||||||
@ -10763,9 +10795,19 @@ dropped:;
|
|||||||
// compact the mdir
|
// compact the mdir
|
||||||
uint32_t dirty = mgc->t.b.h.flags;
|
uint32_t dirty = mgc->t.b.h.flags;
|
||||||
int err = lfs3_mdir_compact(lfs3, mdir);
|
int err = lfs3_mdir_compact(lfs3, mdir);
|
||||||
if (err) {
|
if (err && err != LFS3_ERR_NOSPC) {
|
||||||
return 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
|
// reset dirty flag
|
||||||
mgc->t.b.h.flags &= ~LFS3_t_DIRTY | dirty;
|
mgc->t.b.h.flags &= ~LFS3_t_DIRTY | dirty;
|
||||||
}
|
}
|
||||||
@ -10790,21 +10832,24 @@ eot:;
|
|||||||
&& lfs3_f_isgbmap(lfs3->flags)
|
&& lfs3_f_isgbmap(lfs3->flags)
|
||||||
&& lfs3_t_isrepopgbmap(lfs3->flags)
|
&& lfs3_t_isrepopgbmap(lfs3->flags)
|
||||||
&& !lfs3_t_ismtreeonly(mgc->t.b.h.flags)
|
&& !lfs3_t_ismtreeonly(mgc->t.b.h.flags)
|
||||||
&& !lfs3_t_isckpointed(mgc->t.b.h.flags)) {
|
&& !lfs3_t_isckpointed(mgc->t.b.h.flags)
|
||||||
|
&& !lfs3_t_isnospc(mgc->t.b.h.flags)) {
|
||||||
lfs3_alloc_adoptgbmap(lfs3, &mgc->gbmap_, lfs3->lookahead.ckpoint);
|
lfs3_alloc_adoptgbmap(lfs3, &mgc->gbmap_, lfs3->lookahead.ckpoint);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// was mkconsistent successful?
|
// was mkconsistent successful?
|
||||||
if (lfs3_t_ismkconsistent(mgc->t.b.h.flags)
|
if (lfs3_t_ismkconsistent(mgc->t.b.h.flags)
|
||||||
&& !lfs3_t_isdirty(mgc->t.b.h.flags)) {
|
&& !lfs3_t_isdirty(mgc->t.b.h.flags)
|
||||||
|
&& !lfs3_t_isnospc(mgc->t.b.h.flags)) {
|
||||||
lfs3->flags &= ~LFS3_I_MKCONSISTENT;
|
lfs3->flags &= ~LFS3_I_MKCONSISTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// was compaction successful? note we may need multiple passes if
|
// was compaction successful? note we may need multiple passes if
|
||||||
// we want to be sure everything is compacted
|
// we want to be sure everything is compacted
|
||||||
if (lfs3_t_compactmeta(mgc->t.b.h.flags)
|
if (lfs3_t_compactmeta(mgc->t.b.h.flags)
|
||||||
&& !lfs3_t_ismutated(mgc->t.b.h.flags)) {
|
&& !lfs3_t_ismutated(mgc->t.b.h.flags)
|
||||||
|
&& !lfs3_t_isnospc(mgc->t.b.h.flags)) {
|
||||||
lfs3->flags &= ~LFS3_I_COMPACTMETA;
|
lfs3->flags &= ~LFS3_I_COMPACTMETA;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
3
lfs3.h
3
lfs3.h
@ -342,12 +342,13 @@ enum lfs3_btype {
|
|||||||
// internally used flags, don't use these
|
// internally used flags, don't use these
|
||||||
#define LFS3_t_TYPE 0xf0000000 // The traversal's type
|
#define LFS3_t_TYPE 0xf0000000 // The traversal's type
|
||||||
#define LFS3_t_TSTATE 0x000f0000 // The current traversal state
|
#define LFS3_t_TSTATE 0x000f0000 // The current traversal state
|
||||||
#define LFS3_t_BTYPE 0x00f00000 // The current block type
|
#define LFS3_t_BTYPE 0x00700000 // The current block type
|
||||||
#define LFS3_t_ZOMBIE 0x08000000 // File has been removed
|
#define LFS3_t_ZOMBIE 0x08000000 // File has been removed
|
||||||
#define LFS3_t_DIRTY 0x04000000 // Filesystem modified outside traversal
|
#define LFS3_t_DIRTY 0x04000000 // Filesystem modified outside traversal
|
||||||
#define LFS3_t_MUTATED 0x02000000 // Filesystem modified during traversal
|
#define LFS3_t_MUTATED 0x02000000 // Filesystem modified during traversal
|
||||||
#define LFS3_t_CKPOINTED \
|
#define LFS3_t_CKPOINTED \
|
||||||
0x01000000 // Filesystem ckpointed during traversal
|
0x01000000 // Filesystem ckpointed during traversal
|
||||||
|
#define LFS3_t_NOSPC 0x00800000 // Optional gc work ran out of space
|
||||||
|
|
||||||
// GC flags
|
// GC flags
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
|
|||||||
@ -165,7 +165,7 @@ FLAGS = [
|
|||||||
('^_GBMAP', 0x00080000, "Tstate = gbmap" ),
|
('^_GBMAP', 0x00080000, "Tstate = gbmap" ),
|
||||||
('^_GBMAP_P', 0x00090000, "Tstate = gbmap_p" ),
|
('^_GBMAP_P', 0x00090000, "Tstate = gbmap_p" ),
|
||||||
('^_DONE', 0x000a0000, "Tstate = done" ),
|
('^_DONE', 0x000a0000, "Tstate = done" ),
|
||||||
('t_BTYPE', 0x00f00000, "The current block type" ),
|
('t_BTYPE', 0x00700000, "The current block type" ),
|
||||||
('^_MDIR', 0x00100000, "Btype = mdir" ),
|
('^_MDIR', 0x00100000, "Btype = mdir" ),
|
||||||
('^_BTREE', 0x00200000, "Btype = btree" ),
|
('^_BTREE', 0x00200000, "Btype = btree" ),
|
||||||
('^_DATA', 0x00300000, "Btype = data" ),
|
('^_DATA', 0x00300000, "Btype = data" ),
|
||||||
@ -173,6 +173,7 @@ FLAGS = [
|
|||||||
('t_DIRTY', 0x04000000, "Filesystem modified outside traversal" ),
|
('t_DIRTY', 0x04000000, "Filesystem modified outside traversal" ),
|
||||||
('t_MUTATED', 0x02000000, "Filesystem modified during traversal" ),
|
('t_MUTATED', 0x02000000, "Filesystem modified during traversal" ),
|
||||||
('t_CKPOINTED', 0x01000000, "Filesystem ckpointed during traversal" ),
|
('t_CKPOINTED', 0x01000000, "Filesystem ckpointed during traversal" ),
|
||||||
|
('t_NOSPC', 0x00800000, "Optional gc work ran out of space" ),
|
||||||
|
|
||||||
# Block allocator flags
|
# Block allocator flags
|
||||||
('alloc_ERASE', 0x00000001, "Please erase the block" ),
|
('alloc_ERASE', 0x00000001, "Please erase the block" ),
|
||||||
|
|||||||
Reference in New Issue
Block a user