preerase: Implemented the gc side of preerase
Allocating pre-erased blocks gets quite complicated due to our
restricted flash model, but at least the actual pre-erasing is
relatively straightforward:
- We keep track of known preerased state in lfs3->gbmap.preeraser.
- If LFS3_GC_PREERASE is provided during gc work, we increment the
preeraser's known window by scanning the gbmap.
- Any BMFREE ranges we find, we erase a block at a time, and store the
resulting ecksum in a BMERASED range in the gbmap.
- We keep track of how many blocks we erased, and stop early if this
exceeds cfg.gc_preerase_count. This just lets users tune how many
blocks to preerase in case something (?) prevents preerased blocks
from being used.
Some notes:
- We don't really do anything with ranges in lfs3_alloc_preerase. In
theory we could bulk in erase to minimize the number of commits to the
gbmap, but we expect erase to dominate, so this probably isn't worth
it.
And if erase doesn't dominate, why would you bother pre-erasing
blocks?
- Preerasing isn't really a traversal operation, and is managed by a
sort of secondary state machine in lfs3_fs_gc_.
This also means lfs3_trv_read with LFS3_T_PREERASE does nothing, but I
guess that is ok? It's tempting to try to make lfs3_trv_read also
preerase, but it's unclear what block it should return -- it's
probably the wrong API.
- Introducing ecksums actually went quite a bit smoother than I
expected. Though it helps ecksums are the only optional payload, no
type punning or anything.
Ecksums do muddy the gbmap's design a bit, unfortunately. The main
issue being that we can only merge BMERASED ranges with equal ecksums.
This makes BMERASED ranges less compressable than the others, and may
be one reason to limit cfg.gc_preerase_count.
However:
1. This is where I think it's useful to emphasize that the gbmap's
responsibility is to track _free_ blocks, in-use blocks are
secondary.
When allocating, we're going to stop at the first BMFREE/BMERASED,
but may need to skip over an unbounded number of BMINUSE/BMBAD
blocks. So the compressability of BMFREE/BMERASED ranges should
have less of an impact on block allocation.
2. In practice, most flash uses consistent erase values, so the
resulting ecksums will probably be compressable. The exceptions are
noop-erases (SD/eMMC, RAM, NVRAM, etc), and encryption with block
address permutation?
Though noop-erases are a pretty big exception.
Code changes:
code stack ctx
before: 35116 2136 660
after: 35116 (+0.0%) 2136 (+0.0%) 660 (+0.0%)
code stack ctx
gbmap+np before: 38040 2136 776
gbmap+np after: 38188 (+0.4%) 2144 (+0.4%) 776 (+0.0%)
code stack ctx
gbmap+yp before: 38040 2136 776
gbmap+yp after: 38608 (+1.5%) 2144 (+0.4%) 796 (+2.6%)
This commit is contained in:
@@ -1915,10 +1915,9 @@ enum lfs3_from {
|
||||
LFS3_FROM_LEB128 = 5,
|
||||
LFS3_FROM_LLEB128 = 6,
|
||||
LFS3_FROM_NAME = 7,
|
||||
LFS3_FROM_BRANCH = 8,
|
||||
|
||||
LFS3_FROM_ECKSUM = 8,
|
||||
LFS3_FROM_BRANCH = 9,
|
||||
|
||||
LFS3_FROM_ECKSUM = 9,
|
||||
LFS3_FROM_BPTR = 10,
|
||||
LFS3_FROM_BTREE = 11,
|
||||
LFS3_FROM_SHRUB = 12,
|
||||
@@ -2474,13 +2473,50 @@ static int lfs3_bptr_ck(lfs3_t *lfs3, const lfs3_bptr_t *bptr) {
|
||||
|
||||
/// Erased-state checksum stuff ///
|
||||
|
||||
// erased-state checksum
|
||||
#ifndef LFS3_RDONLY
|
||||
typedef struct lfs3_ecksum {
|
||||
// cksize=-1 indicates no ecksum
|
||||
lfs3_ssize_t cksize;
|
||||
uint32_t cksum;
|
||||
} lfs3_ecksum_t;
|
||||
static int lfs3_ecksum_eck(lfs3_t *lfs3, lfs3_ecksum_t *ecksum,
|
||||
lfs3_block_t block, lfs3_off_t off) {
|
||||
// keep track of prog size
|
||||
ecksum->cksize = lfs3->cfg->prog_size;
|
||||
// checksum erased state
|
||||
ecksum->cksum = 0;
|
||||
return lfs3_bd_cksum(lfs3,
|
||||
block, off, 0,
|
||||
lfs3->cfg->prog_size,
|
||||
&ecksum->cksum);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS3_RDONLY
|
||||
static int lfs3_ecksum_ck(lfs3_t *lfs3, const lfs3_ecksum_t *ecksum,
|
||||
lfs3_block_t block, lfs3_off_t off) {
|
||||
uint32_t cksum_ = 0;
|
||||
int err = lfs3_bd_cksum(lfs3,
|
||||
block, off, 0,
|
||||
ecksum->cksize,
|
||||
&cksum_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return (cksum_ != ecksum->cksum) ? LFS3_ERR_CORRUPT : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS3_RDONLY
|
||||
static inline int lfs3_ecksum_cmp(
|
||||
const lfs3_ecksum_t *a,
|
||||
const lfs3_ecksum_t *b) {
|
||||
// accept NULL as cksize=-1
|
||||
if (((a) ? a->cksize : -1) != ((b) ? b->cksize : -1)) {
|
||||
return ((a) ? a->cksize : -1) - ((b) ? b->cksize : -1);
|
||||
// only cmp cksum if cksize!=-1
|
||||
} else if (((a) ? a->cksize : -1) != -1) {
|
||||
return a->cksum - b->cksum;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// erased-state checksum on-disk encoding
|
||||
@@ -2623,17 +2659,8 @@ static int lfs3_rbyd_ckecksum(lfs3_t *lfs3, const lfs3_rbyd_t *rbyd,
|
||||
|
||||
// check that erased-state matches our checksum, if this fails
|
||||
// most likely a write was interrupted
|
||||
uint32_t ecksum_ = 0;
|
||||
err = lfs3_bd_cksum(lfs3,
|
||||
rbyd->blocks[0], lfs3_rbyd_eoff(rbyd), 0,
|
||||
ecksum->cksize,
|
||||
&ecksum_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// found erased-state?
|
||||
return (ecksum_ == ecksum->cksum) ? 0 : LFS3_ERR_CORRUPT;
|
||||
return lfs3_ecksum_ck(lfs3, ecksum,
|
||||
rbyd->blocks[0], lfs3_rbyd_eoff(rbyd));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3323,16 +3350,15 @@ static int lfs3_rbyd_appendrattr_(lfs3_t *lfs3, lfs3_rbyd_t *rbyd,
|
||||
lfs3_data_t datas[2];
|
||||
uint8_t buf[LFS3_LEB128_DSIZE];
|
||||
} name;
|
||||
|
||||
struct {
|
||||
lfs3_data_t data;
|
||||
uint8_t buf[LFS3_ECKSUM_DSIZE];
|
||||
} ecksum;
|
||||
struct {
|
||||
lfs3_data_t data;
|
||||
uint8_t buf[LFS3_BRANCH_DSIZE];
|
||||
} branch;
|
||||
|
||||
struct {
|
||||
lfs3_data_t data;
|
||||
uint8_t buf[LFS3_ECKSUM_DSIZE];
|
||||
} ecksum;
|
||||
struct {
|
||||
lfs3_data_t data;
|
||||
uint8_t buf[LFS3_BPTR_DSIZE];
|
||||
@@ -3418,16 +3444,6 @@ static int lfs3_rbyd_appendrattr_(lfs3_t *lfs3, lfs3_rbyd_t *rbyd,
|
||||
datas = ctx.u.name.datas;
|
||||
data_count = 2;
|
||||
|
||||
// ecksum?
|
||||
} else if (from == LFS3_FROM_ECKSUM) {
|
||||
ctx.u.ecksum.data = lfs3_data_fromecksum(
|
||||
&(const lfs3_ecksum_t){
|
||||
.cksize = args[0],
|
||||
.cksum = args[1]},
|
||||
ctx.u.ecksum.buf);
|
||||
datas = &ctx.u.ecksum.data;
|
||||
data_count = 1;
|
||||
|
||||
// branch?
|
||||
} else if (from == LFS3_FROM_BRANCH) {
|
||||
ctx.u.branch.data = lfs3_data_frombranch(
|
||||
@@ -3439,6 +3455,14 @@ static int lfs3_rbyd_appendrattr_(lfs3_t *lfs3, lfs3_rbyd_t *rbyd,
|
||||
datas = &ctx.u.branch.data;
|
||||
data_count = 1;
|
||||
|
||||
// ecksum?
|
||||
} else if (from == LFS3_FROM_ECKSUM) {
|
||||
ctx.u.ecksum.data = lfs3_data_fromecksum(
|
||||
(const lfs3_ecksum_t*)args[0],
|
||||
ctx.u.ecksum.buf);
|
||||
datas = &ctx.u.ecksum.data;
|
||||
data_count = 1;
|
||||
|
||||
// bptr?
|
||||
} else if (from == LFS3_FROM_BPTR) {
|
||||
ctx.u.bptr.data = lfs3_data_frombptr(
|
||||
@@ -4351,11 +4375,9 @@ static int lfs3_rbyd_appendcksum_(lfs3_t *lfs3, lfs3_rbyd_t *rbyd,
|
||||
perturb = ((e >> 7) == lfs3_parity(cksum));
|
||||
|
||||
// calculate the erased-state checksum
|
||||
uint32_t ecksum = 0;
|
||||
err = lfs3_bd_cksum(lfs3,
|
||||
rbyd->blocks[0], off_, lfs3->cfg->prog_size,
|
||||
lfs3->cfg->prog_size,
|
||||
&ecksum);
|
||||
lfs3_ecksum_t ecksum;
|
||||
err = lfs3_ecksum_eck(lfs3, &ecksum,
|
||||
rbyd->blocks[0], off_);
|
||||
if (err && err != LFS3_ERR_CORRUPT) {
|
||||
return err;
|
||||
}
|
||||
@@ -4363,8 +4385,7 @@ static int lfs3_rbyd_appendcksum_(lfs3_t *lfs3, lfs3_rbyd_t *rbyd,
|
||||
err = lfs3_rbyd_appendrattr_(lfs3, rbyd,
|
||||
LFS3_TAG_ECKSUM, 0,
|
||||
LFS3_FROM_ECKSUM, 0, LFS3_RATTRS(
|
||||
LFS3_RATTR_ARG(lfs3->cfg->prog_size),
|
||||
LFS3_RATTR_ARG(ecksum)));
|
||||
LFS3_RATTR_ARG(&ecksum)));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -7226,6 +7247,17 @@ static inline bool lfs3_t_islookahead(uint32_t flags) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool lfs3_t_ispreerase(uint32_t flags) {
|
||||
(void)flags;
|
||||
#if !defined(LFS3_RDONLY) \
|
||||
&& defined(LFS3_GBMAP) \
|
||||
&& !defined(LFS3_NO_PREERASE)
|
||||
return flags & LFS3_T_PREERASE;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool lfs3_t_compact(uint32_t flags) {
|
||||
(void)flags;
|
||||
#ifndef LFS3_RDONLY
|
||||
@@ -10481,7 +10513,14 @@ eot:;
|
||||
static void lfs3_gbmap_init(lfs3_gbmap_t *gbmap) {
|
||||
gbmap->window = 0;
|
||||
gbmap->known = 0;
|
||||
#ifndef LFS3_RDONLY
|
||||
gbmap->free = 0;
|
||||
#endif
|
||||
#if !defined(LFS3_RDONLY) && !defined(LFS3_NO_PREERASE)
|
||||
gbmap->ecksum.cksize = -1;
|
||||
gbmap->preeraser.known = 0;
|
||||
gbmap->preeraser.count = 0;
|
||||
#endif
|
||||
lfs3_btree_init(&gbmap->b);
|
||||
lfs3_btree_init(&gbmap->b_p);
|
||||
}
|
||||
@@ -10554,9 +10593,26 @@ static int lfs3_data_readgbmap(lfs3_t *lfs3, lfs3_data_t *data,
|
||||
#ifdef LFS3_GBMAP
|
||||
static lfs3_stag_t lfs3_gbmap_lookupnext(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
lfs3_bid_t bid,
|
||||
lfs3_bid_t *bid_, lfs3_bid_t *weight_) {
|
||||
return lfs3_btree_lookupnext(lfs3, gbmap, bid,
|
||||
bid_, weight_, NULL);
|
||||
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_ecksum_t *ecksum_) {
|
||||
lfs3_data_t data;
|
||||
lfs3_stag_t tag = lfs3_btree_lookupnext(lfs3, gbmap, bid,
|
||||
bid_, weight_, &data);
|
||||
if (tag < 0) {
|
||||
return tag;
|
||||
}
|
||||
|
||||
if (ecksum_) {
|
||||
if (tag == LFS3_TAG_BMERASED && lfs3_data_size(&data) > 0) {
|
||||
int err = lfs3_data_readecksum(lfs3, &data,
|
||||
ecksum_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
ecksum_->cksize = -1;
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10574,19 +10630,21 @@ static int lfs3_gbmap_commit(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
// the purpose of weight is really just to provide a shortcut for bulk
|
||||
// clearing ranges in lfs3_alloc_lookgbmap
|
||||
static int lfs3_gbmap_mark_(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
lfs3_block_t block, lfs3_block_t weight, lfs3_tag_t tag) {
|
||||
lfs3_block_t block, lfs3_block_t weight,
|
||||
lfs3_tag_t tag, const lfs3_ecksum_t *ecksum) {
|
||||
// lookup gbmap range
|
||||
lfs3_bid_t bid__;
|
||||
lfs3_bid_t weight__;
|
||||
lfs3_ecksum_t ecksum__;
|
||||
lfs3_stag_t tag__ = lfs3_gbmap_lookupnext(lfs3, gbmap, block,
|
||||
&bid__, &weight__);
|
||||
&bid__, &weight__, &ecksum__);
|
||||
if (tag__ < 0) {
|
||||
LFS3_ASSERT(tag__ != LFS3_ERR_NOENT);
|
||||
return tag__;
|
||||
}
|
||||
|
||||
// wait, already set to expected type? guess we're done
|
||||
if (tag__ == tag) {
|
||||
if (tag__ == tag && lfs3_ecksum_cmp(&ecksum__, ecksum) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10607,15 +10665,16 @@ static int lfs3_gbmap_mark_(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
&& block < lfs3->block_count-1) {
|
||||
lfs3_bid_t r_bid;
|
||||
lfs3_bid_t r_weight;
|
||||
lfs3_ecksum_t r_ecksum;
|
||||
lfs3_stag_t r_tag = lfs3_gbmap_lookupnext(lfs3, gbmap, block+1,
|
||||
&r_bid, &r_weight);
|
||||
&r_bid, &r_weight, &r_ecksum);
|
||||
if (r_tag < 0) {
|
||||
LFS3_ASSERT(r_tag != LFS3_ERR_NOENT);
|
||||
return r_tag;
|
||||
}
|
||||
LFS3_ASSERT(r_weight == r_bid - block);
|
||||
|
||||
if (r_tag == tag) {
|
||||
if (r_tag == tag && lfs3_ecksum_cmp(&r_ecksum, ecksum) == 0) {
|
||||
// delete to prepare merge
|
||||
int err = lfs3_gbmap_commit(lfs3, &gbmap_, r_bid, LFS3_RATTRS(
|
||||
LFS3_RATTR(2, LFS3_tag_RM, -2),
|
||||
@@ -10638,15 +10697,16 @@ static int lfs3_gbmap_mark_(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
&& block-(weight-1) > 0) {
|
||||
lfs3_bid_t l_bid;
|
||||
lfs3_bid_t l_weight;
|
||||
lfs3_ecksum_t l_ecksum;
|
||||
lfs3_stag_t l_tag = lfs3_gbmap_lookupnext(lfs3, gbmap, block-weight,
|
||||
&l_bid, &l_weight);
|
||||
&l_bid, &l_weight, &l_ecksum);
|
||||
if (l_tag < 0) {
|
||||
LFS3_ASSERT(l_tag != LFS3_ERR_NOENT);
|
||||
return l_tag;
|
||||
}
|
||||
LFS3_ASSERT(l_bid == block-weight);
|
||||
|
||||
if (l_tag == tag) {
|
||||
if (l_tag == tag && lfs3_ecksum_cmp(&l_ecksum, ecksum) == 0) {
|
||||
// delete to prepare merge
|
||||
int err = lfs3_gbmap_commit(lfs3, &gbmap_, l_bid, LFS3_RATTRS(
|
||||
LFS3_RATTR(2, LFS3_tag_RM, -2),
|
||||
@@ -10676,12 +10736,18 @@ static int lfs3_gbmap_mark_(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
? LFS3_RATTR(2, LFS3_tag_GROW, -2)
|
||||
: LFS3_RATTR(2, LFS3_tag_RM, -2),
|
||||
LFS3_RATTR_WEIGHT(-((bid__+1) - (block-(weight-1)))),
|
||||
LFS3_RATTR(2, tag, -2),
|
||||
(ecksum && ecksum->cksize != -1)
|
||||
? LFS3_RATTR(3, tag, -2, LFS3_FROM_ECKSUM)
|
||||
: LFS3_RATTR(3, tag, -2),
|
||||
LFS3_RATTR_WEIGHT(+weight_),
|
||||
LFS3_RATTR_ARG(ecksum),
|
||||
(bid__ > block)
|
||||
? LFS3_RATTR(2, tag__, -2)
|
||||
: LFS3_RATTR(2, LFS3_TAG_NULL, 0),
|
||||
? ((ecksum__.cksize != -1)
|
||||
? LFS3_RATTR(3, tag__, -2, LFS3_FROM_ECKSUM)
|
||||
: LFS3_RATTR(3, tag__, -2))
|
||||
: LFS3_RATTR(3, LFS3_TAG_NULL, 0),
|
||||
LFS3_RATTR_WEIGHT(+(bid__ - block)),
|
||||
LFS3_RATTR_ARG(&ecksum__),
|
||||
LFS3_RATTR_NULL));
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -10695,8 +10761,8 @@ static int lfs3_gbmap_mark_(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
|
||||
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP)
|
||||
static int lfs3_gbmap_mark(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
lfs3_block_t block, lfs3_tag_t tag) {
|
||||
return lfs3_gbmap_mark_(lfs3, gbmap, block, 1, tag);
|
||||
lfs3_block_t block, lfs3_tag_t tag, const lfs3_ecksum_t *ecksum) {
|
||||
return lfs3_gbmap_mark_(lfs3, gbmap, block, 1, tag, ecksum);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10725,7 +10791,7 @@ static int lfs3_gbmap_markbptr(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||
}
|
||||
|
||||
for (lfs3_size_t i = 0; i < block_count; i++) {
|
||||
int err = lfs3_gbmap_mark(lfs3, gbmap, blocks[i], tag_);
|
||||
int err = lfs3_gbmap_mark(lfs3, gbmap, blocks[i], tag_, NULL);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -10743,7 +10809,7 @@ static int lfs3_gbmap_zero(lfs3_t *lfs3, lfs3_btree_t *gbmap) {
|
||||
while (true) {
|
||||
lfs3_block_t weight__;
|
||||
lfs3_stag_t tag__ = lfs3_gbmap_lookupnext(lfs3, gbmap, block__+1,
|
||||
&block__, &weight__);
|
||||
&block__, &weight__, NULL);
|
||||
if (tag__ < 0) {
|
||||
if (tag__ == LFS3_ERR_NOENT) {
|
||||
break;
|
||||
@@ -10753,8 +10819,8 @@ static int lfs3_gbmap_zero(lfs3_t *lfs3, lfs3_btree_t *gbmap) {
|
||||
|
||||
// mark in-use/erased ranges as free
|
||||
if (tag__ == LFS3_TAG_BMINUSE || tag__ == LFS3_TAG_BMERASED) {
|
||||
int err = lfs3_gbmap_mark_(lfs3, gbmap, block__, weight__,
|
||||
LFS3_TAG_BMFREE);
|
||||
int err = lfs3_gbmap_mark_(lfs3, gbmap,
|
||||
block__, weight__, LFS3_TAG_BMFREE, NULL);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -10826,8 +10892,8 @@ static inline int lfs3_alloc_ckpoint(lfs3_t *lfs3) {
|
||||
#endif
|
||||
|
||||
// can we repopulate the lookahead buffer?
|
||||
#ifndef LFS3_RDONLY
|
||||
static inline bool lfs3_alloc_canlookahead(const lfs3_t *lfs3) {
|
||||
#ifndef LFS3_RDONLY
|
||||
// below gc_lookahead_thresh?
|
||||
return lfs3_max(
|
||||
lfs3->lookahead.known,
|
||||
@@ -10844,13 +10910,16 @@ static inline bool lfs3_alloc_canlookahead(const lfs3_t *lfs3) {
|
||||
lfs3_min(
|
||||
8*lfs3->cfg->lookahead_size-1,
|
||||
lfs3->block_count-1));
|
||||
#else
|
||||
// TODO adopt this localized void in flag functions?
|
||||
(void)lfs3;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// can we repopulate the gbmap?
|
||||
#ifndef LFS3_RDONLY
|
||||
static inline bool lfs3_alloc_canlookgbmap(const lfs3_t *lfs3) {
|
||||
#ifdef LFS3_GBMAP
|
||||
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP)
|
||||
// do we even have a gbmap?
|
||||
return lfs3_f_isgbmap(lfs3->flags)
|
||||
// below gc_lookgbmap_thresh?
|
||||
@@ -10866,7 +10935,26 @@ static inline bool lfs3_alloc_canlookgbmap(const lfs3_t *lfs3) {
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// can we pre-erase?
|
||||
static inline bool lfs3_alloc_canpreerase(const lfs3_t *lfs3) {
|
||||
#if !defined(LFS3_RDONLY) \
|
||||
&& defined(LFS3_GBMAP) \
|
||||
&& !defined(LFS3_NO_PREERASE)
|
||||
// do we even have a gbmap?
|
||||
return lfs3_f_isgbmap(lfs3->flags)
|
||||
// have we pre-erased enough blocks?
|
||||
&& lfs3->gbmap.preeraser.count
|
||||
< lfs3->cfg->gc_preerase_count
|
||||
// are there any more blocks in our known window?
|
||||
&& lfs3->gbmap.preeraser.known
|
||||
< lfs3->gbmap.known;
|
||||
#else
|
||||
// TODO adopt this localized void in flag functions?
|
||||
(void)lfs3;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// discard any lookahead/gbmap windows, this is necessary if block_count
|
||||
// changes
|
||||
@@ -11030,7 +11118,7 @@ static lfs3_sblock_t lfs3_alloc_findfree(lfs3_t *lfs3) {
|
||||
lfs3_block_t block;
|
||||
lfs3_stag_t tag = lfs3_gbmap_lookupnext(lfs3, &lfs3->gbmap.b,
|
||||
lfs3->gbmap.window,
|
||||
&block, NULL);
|
||||
&block, NULL, NULL);
|
||||
if (tag < 0) {
|
||||
return tag;
|
||||
}
|
||||
@@ -11172,6 +11260,7 @@ static lfs3_sblock_t lfs3_alloc(lfs3_t *lfs3, uint32_t flags) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// rebuild the gbmap
|
||||
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP)
|
||||
static int lfs3_alloc_lookgbmap(lfs3_t *lfs3) {
|
||||
LFS3_INFO("Repopulating gbmap (gbmap %"PRId32"/%"PRId32")",
|
||||
@@ -11225,6 +11314,66 @@ static int lfs3_alloc_lookgbmap(lfs3_t *lfs3) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// try to pre-erase _one_ block
|
||||
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||
static int lfs3_alloc_preerase(lfs3_t *lfs3) {
|
||||
while (lfs3->gbmap.preeraser.known < lfs3->gbmap.known) {
|
||||
// lookup next known block
|
||||
lfs3_block_t block = (lfs3->gbmap.window + lfs3->gbmap.preeraser.known)
|
||||
% lfs3->cfg->block_count;
|
||||
lfs3_bid_t block__;
|
||||
lfs3_stag_t tag__ = lfs3_gbmap_lookupnext(lfs3, &lfs3->gbmap.b, block,
|
||||
&block__, NULL, NULL);
|
||||
if (tag__ < 0) {
|
||||
LFS3_ASSERT(tag__ != LFS3_ERR_NOENT);
|
||||
return tag__;
|
||||
}
|
||||
|
||||
// not free?
|
||||
if (tag__ != LFS3_TAG_BMFREE) {
|
||||
lfs3_sblock_t d = lfs3_min(
|
||||
block__+1 - block,
|
||||
lfs3->gbmap.known - lfs3->gbmap.preeraser.known);
|
||||
// wait, already erased?
|
||||
if (tag__ == LFS3_TAG_BMERASED) {
|
||||
lfs3->gbmap.preeraser.count += d;
|
||||
}
|
||||
lfs3->gbmap.preeraser.known += d;
|
||||
continue;
|
||||
}
|
||||
|
||||
// erase!
|
||||
int err = lfs3_bd_erase(lfs3, block);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// calculate erased-state checksum
|
||||
lfs3_ecksum_t ecksum;
|
||||
err = lfs3_ecksum_eck(lfs3, &ecksum, block, 0);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// commit into gbmap
|
||||
//
|
||||
// this relies on lfs3_gbmap_commit being atomic
|
||||
err = lfs3_gbmap_mark(lfs3, &lfs3->gbmap.b,
|
||||
block, LFS3_TAG_BMERASED, &ecksum);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// successful pre-erase
|
||||
lfs3->gbmap.preeraser.count += 1;
|
||||
lfs3->gbmap.preeraser.known += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return LFS3_ERR_NOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14870,6 +15019,9 @@ static int lfs3_init(lfs3_t *lfs3, uint32_t flags,
|
||||
LFS3_ASSERT((lfs3->cfg->gc_flags & ~(
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_GC_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA)) == 0);
|
||||
@@ -14898,8 +15050,9 @@ static int lfs3_init(lfs3_t *lfs3, uint32_t flags,
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_I_MKCONSISTENT)
|
||||
// default to lookaheadable
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_I_LOOKAHEAD)
|
||||
// default to assuming we need compaction somewhere, worst case
|
||||
// this just makes lfs3_fs_gc read more than is strictly needed
|
||||
// default to assuming we need compaction somewhere, worst
|
||||
// case this just makes lfs3_fs_gc read more than is
|
||||
// strictly needed
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_I_COMPACT)
|
||||
// default to needing a ckmeta/ckdata scan
|
||||
| LFS3_I_CKMETA
|
||||
@@ -15728,6 +15881,9 @@ int lfs3_mount(lfs3_t *lfs3, uint32_t flags,
|
||||
#ifdef LFS3_YES_LOOKAHEAD
|
||||
flags |= LFS3_M_LOOKAHEAD;
|
||||
#endif
|
||||
#ifdef LFS3_YES_PREERASE
|
||||
flags |= LFS3_M_PREERASE;
|
||||
#endif
|
||||
#ifdef LFS3_YES_COMPACT
|
||||
flags |= LFS3_M_COMPACT;
|
||||
#endif
|
||||
@@ -15752,12 +15908,16 @@ int lfs3_mount(lfs3_t *lfs3, uint32_t flags,
|
||||
| LFS3_IFDEF_CKDATACKSUMS(LFS3_M_CKDATACKSUMS, 0)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_M_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_M_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_M_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_M_COMPACT)
|
||||
| LFS3_M_CKMETA
|
||||
| LFS3_M_CKDATA)) == 0);
|
||||
// these flags require a writable filesystem
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_ismkconsistent(flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_islookahead(flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_ispreerase(flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_compact(flags));
|
||||
|
||||
int err = lfs3_init(lfs3,
|
||||
@@ -15786,12 +15946,18 @@ int lfs3_mount(lfs3_t *lfs3, uint32_t flags,
|
||||
if (flags & (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_GC_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA)) {
|
||||
err = lfs3_fs_ck(lfs3, flags & (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_GC_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA));
|
||||
@@ -16036,6 +16202,9 @@ int lfs3_format(lfs3_t *lfs3, uint32_t flags,
|
||||
#ifdef LFS3_YES_LOOKAHEAD
|
||||
flags |= LFS3_F_LOOKAHEAD;
|
||||
#endif
|
||||
#ifdef LFS3_YES_PREERASE
|
||||
flags |= LFS3_F_PREERASE;
|
||||
#endif
|
||||
#ifdef LFS3_YES_COMPACT
|
||||
flags |= LFS3_F_COMPACT;
|
||||
#endif
|
||||
@@ -16058,6 +16227,9 @@ int lfs3_format(lfs3_t *lfs3, uint32_t flags,
|
||||
| LFS3_IFDEF_CKDATACKSUMS(LFS3_F_CKDATACKSUMS, 0)
|
||||
| LFS3_F_MKCONSISTENT
|
||||
| LFS3_F_LOOKAHEAD
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_F_PREERASE, 0), 0))
|
||||
| LFS3_F_COMPACT
|
||||
| LFS3_F_CKMETA
|
||||
| LFS3_F_CKDATA)) == 0);
|
||||
@@ -16098,12 +16270,18 @@ int lfs3_format(lfs3_t *lfs3, uint32_t flags,
|
||||
if (flags & (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_GC_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA)) {
|
||||
err = lfs3_fs_ck(lfs3, flags & (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_GC_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA));
|
||||
@@ -16150,7 +16328,16 @@ int lfs3_fs_stat(lfs3_t *lfs3, struct lfs3_fsinfo *fsinfo) {
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
(lfs3_grm_count(lfs3) > 0)
|
||||
? LFS3_I_MKCONSISTENT
|
||||
: 0);
|
||||
: 0)
|
||||
// LFS3_I_PREERASE we're just lazy about, since it depends
|
||||
// on both gc_preerase_count and preerase vs free known
|
||||
// windows
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(
|
||||
(lfs3_alloc_canpreerase(lfs3))
|
||||
? LFS3_I_PREERASE
|
||||
: 0, 0), 0));
|
||||
|
||||
// return filesystem config, this may come from disk
|
||||
fsinfo->block_size = lfs3->cfg->block_size;
|
||||
@@ -16354,7 +16541,7 @@ int lfs3_fs_mkconsistent(lfs3_t *lfs3) {
|
||||
static int lfs3_fs_gc_(lfs3_t *lfs3, lfs3_mgc_t *mgc,
|
||||
uint32_t flags, lfs3_soff_t steps) {
|
||||
while ((lfs3_off_t)steps > 0) {
|
||||
// do we have any pending work?
|
||||
// do we have any pending gc work?
|
||||
uint32_t pending = flags & (
|
||||
(lfs3->flags & (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
@@ -16367,73 +16554,95 @@ static int lfs3_fs_gc_(lfs3_t *lfs3, lfs3_mgc_t *mgc,
|
||||
(lfs3_grm_count(lfs3) > 0)
|
||||
? LFS3_GC_MKCONSISTENT
|
||||
: 0));
|
||||
if (!pending) {
|
||||
if (pending) {
|
||||
// prioritize lookahead/gbmap before any work that may need
|
||||
// to allocate
|
||||
#ifndef LFS3_RDONLY
|
||||
if (lfs3_t_islookahead(pending)) {
|
||||
pending &= ~(
|
||||
LFS3_GC_MKCONSISTENT
|
||||
| LFS3_GC_COMPACT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// start a new traversal?
|
||||
if (!lfs3_handle_isopen(lfs3, &mgc->t.h)) {
|
||||
lfs3_mgc_init(mgc, pending);
|
||||
lfs3_handle_open(lfs3, &mgc->t.h);
|
||||
}
|
||||
// mask out any flags that changed
|
||||
//
|
||||
// note that even though our current API prevents flags from
|
||||
// changing mid-traversal, lfs3->flags can be updated by
|
||||
// other operations
|
||||
mgc->t.h.flags &= ~(pending ^ (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA));
|
||||
|
||||
// will this traversal still make progress? no? start over
|
||||
if (!(mgc->t.h.flags
|
||||
& (LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA)
|
||||
// don't bother with lookahead/gbmap if we've
|
||||
// ckpointed
|
||||
& ~LFS3_IFDEF_RDONLY(
|
||||
0,
|
||||
(lfs3_t_isckpointed(mgc->t.h.flags))
|
||||
? LFS3_GC_LOOKAHEAD
|
||||
: 0))) {
|
||||
lfs3_handle_close(lfs3, &mgc->t.h);
|
||||
continue;
|
||||
}
|
||||
|
||||
// do we really need a full traversal?
|
||||
if (!(mgc->t.h.flags & (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA))) {
|
||||
mgc->t.h.flags |= LFS3_T_MTREEONLY;
|
||||
}
|
||||
|
||||
// progress gc
|
||||
lfs3_bptr_t bptr;
|
||||
lfs3_stag_t tag = lfs3_mtree_gc(lfs3, mgc,
|
||||
&bptr);
|
||||
if (tag < 0 && tag != LFS3_ERR_NOENT) {
|
||||
lfs3_handle_close(lfs3, &mgc->t.h);
|
||||
return tag;
|
||||
}
|
||||
|
||||
// end of traversal?
|
||||
if (tag == LFS3_ERR_NOENT) {
|
||||
lfs3_handle_close(lfs3, &mgc->t.h);
|
||||
}
|
||||
|
||||
// if we have no pending gc work, can we preerase blocks?
|
||||
} else if (lfs3_alloc_canpreerase(lfs3)) {
|
||||
#if !defined(LFS3_RDONLY) \
|
||||
&& defined(LFS3_GBMAP) \
|
||||
&& !defined(LFS3_NO_PREERASE)
|
||||
int err = lfs3_alloc_preerase(lfs3);
|
||||
if (err && err != LFS3_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO do this
|
||||
// // if we have nothing else to do, try to commit the gbmap to
|
||||
// // disk so it's recoverable if we lose power
|
||||
// } else if (lfs3_btree_cmp(&lfs3->gbmap.b, &lfs3->gbmap.b_p) != 0) {
|
||||
// // TODO
|
||||
|
||||
// nothing to do at all? guess we're done
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
// prioritize lookahead/gbmap before any work that may need to
|
||||
// allocate
|
||||
#ifndef LFS3_RDONLY
|
||||
if (lfs3_t_islookahead(pending)) {
|
||||
pending &= ~(
|
||||
LFS3_GC_MKCONSISTENT
|
||||
| LFS3_GC_COMPACT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// start a new traversal?
|
||||
if (!lfs3_handle_isopen(lfs3, &mgc->t.h)) {
|
||||
lfs3_mgc_init(mgc, pending);
|
||||
lfs3_handle_open(lfs3, &mgc->t.h);
|
||||
}
|
||||
// mask out any flags that changed
|
||||
//
|
||||
// note that even though our current API prevents flags from
|
||||
// changing mid-traversal, lfs3->flags can be updated by other
|
||||
// operations
|
||||
mgc->t.h.flags &= ~(pending ^ (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA));
|
||||
|
||||
// will this traversal still make progress? no? start over
|
||||
if (!(mgc->t.h.flags
|
||||
& (LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA)
|
||||
// don't bother with lookahead/gbmap if we've ckpointed
|
||||
& ~LFS3_IFDEF_RDONLY(
|
||||
0,
|
||||
(lfs3_t_isckpointed(mgc->t.h.flags))
|
||||
? LFS3_GC_LOOKAHEAD
|
||||
: 0))) {
|
||||
lfs3_handle_close(lfs3, &mgc->t.h);
|
||||
continue;
|
||||
}
|
||||
|
||||
// do we really need a full traversal?
|
||||
if (!(mgc->t.h.flags & (
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA))) {
|
||||
mgc->t.h.flags |= LFS3_T_MTREEONLY;
|
||||
}
|
||||
|
||||
// progress gc
|
||||
lfs3_bptr_t bptr;
|
||||
lfs3_stag_t tag = lfs3_mtree_gc(lfs3, mgc,
|
||||
&bptr);
|
||||
if (tag < 0 && tag != LFS3_ERR_NOENT) {
|
||||
lfs3_handle_close(lfs3, &mgc->t.h);
|
||||
return tag;
|
||||
}
|
||||
// end of traversal?
|
||||
if (tag == LFS3_ERR_NOENT) {
|
||||
lfs3_handle_close(lfs3, &mgc->t.h);
|
||||
}
|
||||
|
||||
// decrement steps
|
||||
if (steps > 0) {
|
||||
@@ -16452,6 +16661,9 @@ int lfs3_fs_ck(lfs3_t *lfs3, uint32_t flags) {
|
||||
LFS3_ASSERT((flags & ~(
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_CK_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_CK_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_CK_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_CK_COMPACT)
|
||||
| LFS3_CK_CKMETA
|
||||
| LFS3_CK_CKDATA)) == 0);
|
||||
@@ -16460,6 +16672,8 @@ int lfs3_fs_ck(lfs3_t *lfs3, uint32_t flags) {
|
||||
|| !lfs3_t_ismkconsistent(flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||
|| !lfs3_t_islookahead(flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||
|| !lfs3_t_ispreerase(flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||
|| !lfs3_t_compact(flags));
|
||||
|
||||
@@ -16481,6 +16695,9 @@ int lfs3_fs_gc(lfs3_t *lfs3) {
|
||||
LFS3_ASSERT((lfs3->cfg->gc_flags & ~(
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_GC_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA)) == 0);
|
||||
@@ -16489,6 +16706,8 @@ int lfs3_fs_gc(lfs3_t *lfs3) {
|
||||
|| !lfs3_t_ismkconsistent(lfs3->cfg->gc_flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||
|| !lfs3_t_islookahead(lfs3->cfg->gc_flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||
|| !lfs3_t_ispreerase(lfs3->cfg->gc_flags));
|
||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||
|| !lfs3_t_compact(lfs3->cfg->gc_flags));
|
||||
|
||||
@@ -16507,6 +16726,9 @@ int lfs3_fs_unck(lfs3_t *lfs3, uint32_t flags) {
|
||||
LFS3_ASSERT((flags & ~(
|
||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_GC_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||
| LFS3_GC_CKMETA
|
||||
| LFS3_GC_CKDATA)) == 0);
|
||||
@@ -16571,7 +16793,7 @@ int lfs3_fs_grow(lfs3_t *lfs3, lfs3_size_t block_count_) {
|
||||
// need a new range
|
||||
lfs3_stag_t tag = lfs3_gbmap_lookupnext(lfs3, &lfs3->gbmap.b,
|
||||
block_count-1,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
if (tag < 0) {
|
||||
LFS3_ASSERT(tag != LFS3_ERR_NOENT);
|
||||
err = tag;
|
||||
@@ -16745,6 +16967,9 @@ int lfs3_trv_open(lfs3_t *lfs3, lfs3_trv_t *trv, uint32_t flags) {
|
||||
| LFS3_T_EXCL
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_T_MKCONSISTENT)
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_T_LOOKAHEAD)
|
||||
| LFS3_IFDEF_RDONLY(0,
|
||||
LFS3_IFDEF_GBMAP(
|
||||
LFS3_IFDEF_PREERASE(LFS3_T_PREERASE, 0), 0))
|
||||
| LFS3_IFDEF_RDONLY(0, LFS3_T_COMPACT)
|
||||
| LFS3_T_CKMETA
|
||||
| LFS3_T_CKDATA)) == 0);
|
||||
@@ -16753,6 +16978,7 @@ int lfs3_trv_open(lfs3_t *lfs3, lfs3_trv_t *trv, uint32_t flags) {
|
||||
// these flags require a writable traversal
|
||||
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_ismkconsistent(flags));
|
||||
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_islookahead(flags));
|
||||
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_ispreerase(flags));
|
||||
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_compact(flags));
|
||||
// some flags don't make sense when only traversing the mtree
|
||||
LFS3_ASSERT(!lfs3_t_ismtreeonly(flags) || !lfs3_t_islookahead(flags));
|
||||
|
||||
Reference in New Issue
Block a user