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_LEB128 = 5,
|
||||||
LFS3_FROM_LLEB128 = 6,
|
LFS3_FROM_LLEB128 = 6,
|
||||||
LFS3_FROM_NAME = 7,
|
LFS3_FROM_NAME = 7,
|
||||||
|
LFS3_FROM_BRANCH = 8,
|
||||||
|
|
||||||
LFS3_FROM_ECKSUM = 8,
|
LFS3_FROM_ECKSUM = 9,
|
||||||
LFS3_FROM_BRANCH = 9,
|
|
||||||
|
|
||||||
LFS3_FROM_BPTR = 10,
|
LFS3_FROM_BPTR = 10,
|
||||||
LFS3_FROM_BTREE = 11,
|
LFS3_FROM_BTREE = 11,
|
||||||
LFS3_FROM_SHRUB = 12,
|
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 stuff ///
|
||||||
|
|
||||||
// erased-state checksum
|
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
typedef struct lfs3_ecksum {
|
static int lfs3_ecksum_eck(lfs3_t *lfs3, lfs3_ecksum_t *ecksum,
|
||||||
// cksize=-1 indicates no ecksum
|
lfs3_block_t block, lfs3_off_t off) {
|
||||||
lfs3_ssize_t cksize;
|
// keep track of prog size
|
||||||
uint32_t cksum;
|
ecksum->cksize = lfs3->cfg->prog_size;
|
||||||
} lfs3_ecksum_t;
|
// 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
|
#endif
|
||||||
|
|
||||||
// erased-state checksum on-disk encoding
|
// 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
|
// check that erased-state matches our checksum, if this fails
|
||||||
// most likely a write was interrupted
|
// most likely a write was interrupted
|
||||||
uint32_t ecksum_ = 0;
|
return lfs3_ecksum_ck(lfs3, ecksum,
|
||||||
err = lfs3_bd_cksum(lfs3,
|
rbyd->blocks[0], lfs3_rbyd_eoff(rbyd));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -3323,16 +3350,15 @@ static int lfs3_rbyd_appendrattr_(lfs3_t *lfs3, lfs3_rbyd_t *rbyd,
|
|||||||
lfs3_data_t datas[2];
|
lfs3_data_t datas[2];
|
||||||
uint8_t buf[LFS3_LEB128_DSIZE];
|
uint8_t buf[LFS3_LEB128_DSIZE];
|
||||||
} name;
|
} name;
|
||||||
|
|
||||||
struct {
|
|
||||||
lfs3_data_t data;
|
|
||||||
uint8_t buf[LFS3_ECKSUM_DSIZE];
|
|
||||||
} ecksum;
|
|
||||||
struct {
|
struct {
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
uint8_t buf[LFS3_BRANCH_DSIZE];
|
uint8_t buf[LFS3_BRANCH_DSIZE];
|
||||||
} branch;
|
} branch;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
lfs3_data_t data;
|
||||||
|
uint8_t buf[LFS3_ECKSUM_DSIZE];
|
||||||
|
} ecksum;
|
||||||
struct {
|
struct {
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
uint8_t buf[LFS3_BPTR_DSIZE];
|
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;
|
datas = ctx.u.name.datas;
|
||||||
data_count = 2;
|
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?
|
// branch?
|
||||||
} else if (from == LFS3_FROM_BRANCH) {
|
} else if (from == LFS3_FROM_BRANCH) {
|
||||||
ctx.u.branch.data = lfs3_data_frombranch(
|
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;
|
datas = &ctx.u.branch.data;
|
||||||
data_count = 1;
|
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?
|
// bptr?
|
||||||
} else if (from == LFS3_FROM_BPTR) {
|
} else if (from == LFS3_FROM_BPTR) {
|
||||||
ctx.u.bptr.data = lfs3_data_frombptr(
|
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));
|
perturb = ((e >> 7) == lfs3_parity(cksum));
|
||||||
|
|
||||||
// calculate the erased-state checksum
|
// calculate the erased-state checksum
|
||||||
uint32_t ecksum = 0;
|
lfs3_ecksum_t ecksum;
|
||||||
err = lfs3_bd_cksum(lfs3,
|
err = lfs3_ecksum_eck(lfs3, &ecksum,
|
||||||
rbyd->blocks[0], off_, lfs3->cfg->prog_size,
|
rbyd->blocks[0], off_);
|
||||||
lfs3->cfg->prog_size,
|
|
||||||
&ecksum);
|
|
||||||
if (err && err != LFS3_ERR_CORRUPT) {
|
if (err && err != LFS3_ERR_CORRUPT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -4363,8 +4385,7 @@ static int lfs3_rbyd_appendcksum_(lfs3_t *lfs3, lfs3_rbyd_t *rbyd,
|
|||||||
err = lfs3_rbyd_appendrattr_(lfs3, rbyd,
|
err = lfs3_rbyd_appendrattr_(lfs3, rbyd,
|
||||||
LFS3_TAG_ECKSUM, 0,
|
LFS3_TAG_ECKSUM, 0,
|
||||||
LFS3_FROM_ECKSUM, 0, LFS3_RATTRS(
|
LFS3_FROM_ECKSUM, 0, LFS3_RATTRS(
|
||||||
LFS3_RATTR_ARG(lfs3->cfg->prog_size),
|
LFS3_RATTR_ARG(&ecksum)));
|
||||||
LFS3_RATTR_ARG(ecksum)));
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -7226,6 +7247,17 @@ static inline bool lfs3_t_islookahead(uint32_t flags) {
|
|||||||
#endif
|
#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) {
|
static inline bool lfs3_t_compact(uint32_t flags) {
|
||||||
(void)flags;
|
(void)flags;
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
@@ -10481,7 +10513,14 @@ eot:;
|
|||||||
static void lfs3_gbmap_init(lfs3_gbmap_t *gbmap) {
|
static void lfs3_gbmap_init(lfs3_gbmap_t *gbmap) {
|
||||||
gbmap->window = 0;
|
gbmap->window = 0;
|
||||||
gbmap->known = 0;
|
gbmap->known = 0;
|
||||||
|
#ifndef LFS3_RDONLY
|
||||||
gbmap->free = 0;
|
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);
|
||||||
lfs3_btree_init(&gbmap->b_p);
|
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
|
#ifdef LFS3_GBMAP
|
||||||
static lfs3_stag_t lfs3_gbmap_lookupnext(lfs3_t *lfs3, lfs3_btree_t *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 *bid_, lfs3_bid_t *weight_) {
|
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_ecksum_t *ecksum_) {
|
||||||
return lfs3_btree_lookupnext(lfs3, gbmap, bid,
|
lfs3_data_t data;
|
||||||
bid_, weight_, NULL);
|
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
|
#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
|
// the purpose of weight is really just to provide a shortcut for bulk
|
||||||
// clearing ranges in lfs3_alloc_lookgbmap
|
// clearing ranges in lfs3_alloc_lookgbmap
|
||||||
static int lfs3_gbmap_mark_(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
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
|
// lookup gbmap range
|
||||||
lfs3_bid_t bid__;
|
lfs3_bid_t bid__;
|
||||||
lfs3_bid_t weight__;
|
lfs3_bid_t weight__;
|
||||||
|
lfs3_ecksum_t ecksum__;
|
||||||
lfs3_stag_t tag__ = lfs3_gbmap_lookupnext(lfs3, gbmap, block,
|
lfs3_stag_t tag__ = lfs3_gbmap_lookupnext(lfs3, gbmap, block,
|
||||||
&bid__, &weight__);
|
&bid__, &weight__, &ecksum__);
|
||||||
if (tag__ < 0) {
|
if (tag__ < 0) {
|
||||||
LFS3_ASSERT(tag__ != LFS3_ERR_NOENT);
|
LFS3_ASSERT(tag__ != LFS3_ERR_NOENT);
|
||||||
return tag__;
|
return tag__;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait, already set to expected type? guess we're done
|
// wait, already set to expected type? guess we're done
|
||||||
if (tag__ == tag) {
|
if (tag__ == tag && lfs3_ecksum_cmp(&ecksum__, ecksum) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10607,15 +10665,16 @@ static int lfs3_gbmap_mark_(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
|||||||
&& block < lfs3->block_count-1) {
|
&& block < lfs3->block_count-1) {
|
||||||
lfs3_bid_t r_bid;
|
lfs3_bid_t r_bid;
|
||||||
lfs3_bid_t r_weight;
|
lfs3_bid_t r_weight;
|
||||||
|
lfs3_ecksum_t r_ecksum;
|
||||||
lfs3_stag_t r_tag = lfs3_gbmap_lookupnext(lfs3, gbmap, block+1,
|
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) {
|
if (r_tag < 0) {
|
||||||
LFS3_ASSERT(r_tag != LFS3_ERR_NOENT);
|
LFS3_ASSERT(r_tag != LFS3_ERR_NOENT);
|
||||||
return r_tag;
|
return r_tag;
|
||||||
}
|
}
|
||||||
LFS3_ASSERT(r_weight == r_bid - block);
|
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
|
// delete to prepare merge
|
||||||
int err = lfs3_gbmap_commit(lfs3, &gbmap_, r_bid, LFS3_RATTRS(
|
int err = lfs3_gbmap_commit(lfs3, &gbmap_, r_bid, LFS3_RATTRS(
|
||||||
LFS3_RATTR(2, LFS3_tag_RM, -2),
|
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) {
|
&& block-(weight-1) > 0) {
|
||||||
lfs3_bid_t l_bid;
|
lfs3_bid_t l_bid;
|
||||||
lfs3_bid_t l_weight;
|
lfs3_bid_t l_weight;
|
||||||
|
lfs3_ecksum_t l_ecksum;
|
||||||
lfs3_stag_t l_tag = lfs3_gbmap_lookupnext(lfs3, gbmap, block-weight,
|
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) {
|
if (l_tag < 0) {
|
||||||
LFS3_ASSERT(l_tag != LFS3_ERR_NOENT);
|
LFS3_ASSERT(l_tag != LFS3_ERR_NOENT);
|
||||||
return l_tag;
|
return l_tag;
|
||||||
}
|
}
|
||||||
LFS3_ASSERT(l_bid == block-weight);
|
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
|
// delete to prepare merge
|
||||||
int err = lfs3_gbmap_commit(lfs3, &gbmap_, l_bid, LFS3_RATTRS(
|
int err = lfs3_gbmap_commit(lfs3, &gbmap_, l_bid, LFS3_RATTRS(
|
||||||
LFS3_RATTR(2, LFS3_tag_RM, -2),
|
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_GROW, -2)
|
||||||
: LFS3_RATTR(2, LFS3_tag_RM, -2),
|
: LFS3_RATTR(2, LFS3_tag_RM, -2),
|
||||||
LFS3_RATTR_WEIGHT(-((bid__+1) - (block-(weight-1)))),
|
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_WEIGHT(+weight_),
|
||||||
|
LFS3_RATTR_ARG(ecksum),
|
||||||
(bid__ > block)
|
(bid__ > block)
|
||||||
? LFS3_RATTR(2, tag__, -2)
|
? ((ecksum__.cksize != -1)
|
||||||
: LFS3_RATTR(2, LFS3_TAG_NULL, 0),
|
? 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_WEIGHT(+(bid__ - block)),
|
||||||
|
LFS3_RATTR_ARG(&ecksum__),
|
||||||
LFS3_RATTR_NULL));
|
LFS3_RATTR_NULL));
|
||||||
if (err) {
|
if (err) {
|
||||||
return 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)
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP)
|
||||||
static int lfs3_gbmap_mark(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
static int lfs3_gbmap_mark(lfs3_t *lfs3, lfs3_btree_t *gbmap,
|
||||||
lfs3_block_t block, lfs3_tag_t tag) {
|
lfs3_block_t block, lfs3_tag_t tag, const lfs3_ecksum_t *ecksum) {
|
||||||
return lfs3_gbmap_mark_(lfs3, gbmap, block, 1, tag);
|
return lfs3_gbmap_mark_(lfs3, gbmap, block, 1, tag, ecksum);
|
||||||
}
|
}
|
||||||
#endif
|
#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++) {
|
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) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -10743,7 +10809,7 @@ static int lfs3_gbmap_zero(lfs3_t *lfs3, lfs3_btree_t *gbmap) {
|
|||||||
while (true) {
|
while (true) {
|
||||||
lfs3_block_t weight__;
|
lfs3_block_t weight__;
|
||||||
lfs3_stag_t tag__ = lfs3_gbmap_lookupnext(lfs3, gbmap, block__+1,
|
lfs3_stag_t tag__ = lfs3_gbmap_lookupnext(lfs3, gbmap, block__+1,
|
||||||
&block__, &weight__);
|
&block__, &weight__, NULL);
|
||||||
if (tag__ < 0) {
|
if (tag__ < 0) {
|
||||||
if (tag__ == LFS3_ERR_NOENT) {
|
if (tag__ == LFS3_ERR_NOENT) {
|
||||||
break;
|
break;
|
||||||
@@ -10753,8 +10819,8 @@ static int lfs3_gbmap_zero(lfs3_t *lfs3, lfs3_btree_t *gbmap) {
|
|||||||
|
|
||||||
// mark in-use/erased ranges as free
|
// mark in-use/erased ranges as free
|
||||||
if (tag__ == LFS3_TAG_BMINUSE || tag__ == LFS3_TAG_BMERASED) {
|
if (tag__ == LFS3_TAG_BMINUSE || tag__ == LFS3_TAG_BMERASED) {
|
||||||
int err = lfs3_gbmap_mark_(lfs3, gbmap, block__, weight__,
|
int err = lfs3_gbmap_mark_(lfs3, gbmap,
|
||||||
LFS3_TAG_BMFREE);
|
block__, weight__, LFS3_TAG_BMFREE, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -10826,8 +10892,8 @@ static inline int lfs3_alloc_ckpoint(lfs3_t *lfs3) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// can we repopulate the lookahead buffer?
|
// can we repopulate the lookahead buffer?
|
||||||
#ifndef LFS3_RDONLY
|
|
||||||
static inline bool lfs3_alloc_canlookahead(const lfs3_t *lfs3) {
|
static inline bool lfs3_alloc_canlookahead(const lfs3_t *lfs3) {
|
||||||
|
#ifndef LFS3_RDONLY
|
||||||
// below gc_lookahead_thresh?
|
// below gc_lookahead_thresh?
|
||||||
return lfs3_max(
|
return lfs3_max(
|
||||||
lfs3->lookahead.known,
|
lfs3->lookahead.known,
|
||||||
@@ -10844,13 +10910,16 @@ static inline bool lfs3_alloc_canlookahead(const lfs3_t *lfs3) {
|
|||||||
lfs3_min(
|
lfs3_min(
|
||||||
8*lfs3->cfg->lookahead_size-1,
|
8*lfs3->cfg->lookahead_size-1,
|
||||||
lfs3->block_count-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?
|
// can we repopulate the gbmap?
|
||||||
#ifndef LFS3_RDONLY
|
|
||||||
static inline bool lfs3_alloc_canlookgbmap(const lfs3_t *lfs3) {
|
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?
|
// do we even have a gbmap?
|
||||||
return lfs3_f_isgbmap(lfs3->flags)
|
return lfs3_f_isgbmap(lfs3->flags)
|
||||||
// below gc_lookgbmap_thresh?
|
// below gc_lookgbmap_thresh?
|
||||||
@@ -10866,7 +10935,26 @@ static inline bool lfs3_alloc_canlookgbmap(const lfs3_t *lfs3) {
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#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
|
// discard any lookahead/gbmap windows, this is necessary if block_count
|
||||||
// changes
|
// changes
|
||||||
@@ -11030,7 +11118,7 @@ static lfs3_sblock_t lfs3_alloc_findfree(lfs3_t *lfs3) {
|
|||||||
lfs3_block_t block;
|
lfs3_block_t block;
|
||||||
lfs3_stag_t tag = lfs3_gbmap_lookupnext(lfs3, &lfs3->gbmap.b,
|
lfs3_stag_t tag = lfs3_gbmap_lookupnext(lfs3, &lfs3->gbmap.b,
|
||||||
lfs3->gbmap.window,
|
lfs3->gbmap.window,
|
||||||
&block, NULL);
|
&block, NULL, NULL);
|
||||||
if (tag < 0) {
|
if (tag < 0) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
@@ -11172,6 +11260,7 @@ static lfs3_sblock_t lfs3_alloc(lfs3_t *lfs3, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// rebuild the gbmap
|
||||||
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP)
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP)
|
||||||
static int lfs3_alloc_lookgbmap(lfs3_t *lfs3) {
|
static int lfs3_alloc_lookgbmap(lfs3_t *lfs3) {
|
||||||
LFS3_INFO("Repopulating gbmap (gbmap %"PRId32"/%"PRId32")",
|
LFS3_INFO("Repopulating gbmap (gbmap %"PRId32"/%"PRId32")",
|
||||||
@@ -11225,6 +11314,66 @@ static int lfs3_alloc_lookgbmap(lfs3_t *lfs3) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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_ASSERT((lfs3->cfg->gc_flags & ~(
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||||
| LFS3_GC_CKMETA
|
| LFS3_GC_CKMETA
|
||||||
| LFS3_GC_CKDATA)) == 0);
|
| 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)
|
| LFS3_IFDEF_RDONLY(0, LFS3_I_MKCONSISTENT)
|
||||||
// default to lookaheadable
|
// default to lookaheadable
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_I_LOOKAHEAD)
|
| LFS3_IFDEF_RDONLY(0, LFS3_I_LOOKAHEAD)
|
||||||
// default to assuming we need compaction somewhere, worst case
|
// default to assuming we need compaction somewhere, worst
|
||||||
// this just makes lfs3_fs_gc read more than is strictly needed
|
// case this just makes lfs3_fs_gc read more than is
|
||||||
|
// strictly needed
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_I_COMPACT)
|
| LFS3_IFDEF_RDONLY(0, LFS3_I_COMPACT)
|
||||||
// default to needing a ckmeta/ckdata scan
|
// default to needing a ckmeta/ckdata scan
|
||||||
| LFS3_I_CKMETA
|
| LFS3_I_CKMETA
|
||||||
@@ -15728,6 +15881,9 @@ int lfs3_mount(lfs3_t *lfs3, uint32_t flags,
|
|||||||
#ifdef LFS3_YES_LOOKAHEAD
|
#ifdef LFS3_YES_LOOKAHEAD
|
||||||
flags |= LFS3_M_LOOKAHEAD;
|
flags |= LFS3_M_LOOKAHEAD;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LFS3_YES_PREERASE
|
||||||
|
flags |= LFS3_M_PREERASE;
|
||||||
|
#endif
|
||||||
#ifdef LFS3_YES_COMPACT
|
#ifdef LFS3_YES_COMPACT
|
||||||
flags |= LFS3_M_COMPACT;
|
flags |= LFS3_M_COMPACT;
|
||||||
#endif
|
#endif
|
||||||
@@ -15752,12 +15908,16 @@ int lfs3_mount(lfs3_t *lfs3, uint32_t flags,
|
|||||||
| LFS3_IFDEF_CKDATACKSUMS(LFS3_M_CKDATACKSUMS, 0)
|
| LFS3_IFDEF_CKDATACKSUMS(LFS3_M_CKDATACKSUMS, 0)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_M_MKCONSISTENT)
|
| LFS3_IFDEF_RDONLY(0, LFS3_M_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_M_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_M_COMPACT)
|
||||||
| LFS3_M_CKMETA
|
| LFS3_M_CKMETA
|
||||||
| LFS3_M_CKDATA)) == 0);
|
| LFS3_M_CKDATA)) == 0);
|
||||||
// these flags require a writable filesystem
|
// these flags require a writable filesystem
|
||||||
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_ismkconsistent(flags));
|
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_islookahead(flags));
|
||||||
|
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_ispreerase(flags));
|
||||||
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_compact(flags));
|
LFS3_ASSERT(!lfs3_m_isrdonly(flags) || !lfs3_t_compact(flags));
|
||||||
|
|
||||||
int err = lfs3_init(lfs3,
|
int err = lfs3_init(lfs3,
|
||||||
@@ -15786,12 +15946,18 @@ int lfs3_mount(lfs3_t *lfs3, uint32_t flags,
|
|||||||
if (flags & (
|
if (flags & (
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||||
| LFS3_GC_CKMETA
|
| LFS3_GC_CKMETA
|
||||||
| LFS3_GC_CKDATA)) {
|
| LFS3_GC_CKDATA)) {
|
||||||
err = lfs3_fs_ck(lfs3, flags & (
|
err = lfs3_fs_ck(lfs3, flags & (
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||||
| LFS3_GC_CKMETA
|
| LFS3_GC_CKMETA
|
||||||
| LFS3_GC_CKDATA));
|
| LFS3_GC_CKDATA));
|
||||||
@@ -16036,6 +16202,9 @@ int lfs3_format(lfs3_t *lfs3, uint32_t flags,
|
|||||||
#ifdef LFS3_YES_LOOKAHEAD
|
#ifdef LFS3_YES_LOOKAHEAD
|
||||||
flags |= LFS3_F_LOOKAHEAD;
|
flags |= LFS3_F_LOOKAHEAD;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LFS3_YES_PREERASE
|
||||||
|
flags |= LFS3_F_PREERASE;
|
||||||
|
#endif
|
||||||
#ifdef LFS3_YES_COMPACT
|
#ifdef LFS3_YES_COMPACT
|
||||||
flags |= LFS3_F_COMPACT;
|
flags |= LFS3_F_COMPACT;
|
||||||
#endif
|
#endif
|
||||||
@@ -16058,6 +16227,9 @@ int lfs3_format(lfs3_t *lfs3, uint32_t flags,
|
|||||||
| LFS3_IFDEF_CKDATACKSUMS(LFS3_F_CKDATACKSUMS, 0)
|
| LFS3_IFDEF_CKDATACKSUMS(LFS3_F_CKDATACKSUMS, 0)
|
||||||
| LFS3_F_MKCONSISTENT
|
| LFS3_F_MKCONSISTENT
|
||||||
| LFS3_F_LOOKAHEAD
|
| LFS3_F_LOOKAHEAD
|
||||||
|
| LFS3_IFDEF_RDONLY(0,
|
||||||
|
LFS3_IFDEF_GBMAP(
|
||||||
|
LFS3_IFDEF_PREERASE(LFS3_F_PREERASE, 0), 0))
|
||||||
| LFS3_F_COMPACT
|
| LFS3_F_COMPACT
|
||||||
| LFS3_F_CKMETA
|
| LFS3_F_CKMETA
|
||||||
| LFS3_F_CKDATA)) == 0);
|
| LFS3_F_CKDATA)) == 0);
|
||||||
@@ -16098,12 +16270,18 @@ int lfs3_format(lfs3_t *lfs3, uint32_t flags,
|
|||||||
if (flags & (
|
if (flags & (
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||||
| LFS3_GC_CKMETA
|
| LFS3_GC_CKMETA
|
||||||
| LFS3_GC_CKDATA)) {
|
| LFS3_GC_CKDATA)) {
|
||||||
err = lfs3_fs_ck(lfs3, flags & (
|
err = lfs3_fs_ck(lfs3, flags & (
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||||
| LFS3_GC_CKMETA
|
| LFS3_GC_CKMETA
|
||||||
| LFS3_GC_CKDATA));
|
| LFS3_GC_CKDATA));
|
||||||
@@ -16150,7 +16328,16 @@ int lfs3_fs_stat(lfs3_t *lfs3, struct lfs3_fsinfo *fsinfo) {
|
|||||||
| LFS3_IFDEF_RDONLY(0,
|
| LFS3_IFDEF_RDONLY(0,
|
||||||
(lfs3_grm_count(lfs3) > 0)
|
(lfs3_grm_count(lfs3) > 0)
|
||||||
? LFS3_I_MKCONSISTENT
|
? 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
|
// return filesystem config, this may come from disk
|
||||||
fsinfo->block_size = lfs3->cfg->block_size;
|
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,
|
static int lfs3_fs_gc_(lfs3_t *lfs3, lfs3_mgc_t *mgc,
|
||||||
uint32_t flags, lfs3_soff_t steps) {
|
uint32_t flags, lfs3_soff_t steps) {
|
||||||
while ((lfs3_off_t)steps > 0) {
|
while ((lfs3_off_t)steps > 0) {
|
||||||
// do we have any pending work?
|
// do we have any pending gc work?
|
||||||
uint32_t pending = flags & (
|
uint32_t pending = flags & (
|
||||||
(lfs3->flags & (
|
(lfs3->flags & (
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
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_grm_count(lfs3) > 0)
|
||||||
? LFS3_GC_MKCONSISTENT
|
? LFS3_GC_MKCONSISTENT
|
||||||
: 0));
|
: 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;
|
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
|
// decrement steps
|
||||||
if (steps > 0) {
|
if (steps > 0) {
|
||||||
@@ -16452,6 +16661,9 @@ int lfs3_fs_ck(lfs3_t *lfs3, uint32_t flags) {
|
|||||||
LFS3_ASSERT((flags & ~(
|
LFS3_ASSERT((flags & ~(
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_CK_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_CK_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_CK_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_CK_COMPACT)
|
||||||
| LFS3_CK_CKMETA
|
| LFS3_CK_CKMETA
|
||||||
| LFS3_CK_CKDATA)) == 0);
|
| LFS3_CK_CKDATA)) == 0);
|
||||||
@@ -16460,6 +16672,8 @@ int lfs3_fs_ck(lfs3_t *lfs3, uint32_t flags) {
|
|||||||
|| !lfs3_t_ismkconsistent(flags));
|
|| !lfs3_t_ismkconsistent(flags));
|
||||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||||
|| !lfs3_t_islookahead(flags));
|
|| !lfs3_t_islookahead(flags));
|
||||||
|
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||||
|
|| !lfs3_t_ispreerase(flags));
|
||||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||||
|| !lfs3_t_compact(flags));
|
|| !lfs3_t_compact(flags));
|
||||||
|
|
||||||
@@ -16481,6 +16695,9 @@ int lfs3_fs_gc(lfs3_t *lfs3) {
|
|||||||
LFS3_ASSERT((lfs3->cfg->gc_flags & ~(
|
LFS3_ASSERT((lfs3->cfg->gc_flags & ~(
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||||
| LFS3_GC_CKMETA
|
| LFS3_GC_CKMETA
|
||||||
| LFS3_GC_CKDATA)) == 0);
|
| LFS3_GC_CKDATA)) == 0);
|
||||||
@@ -16489,6 +16706,8 @@ int lfs3_fs_gc(lfs3_t *lfs3) {
|
|||||||
|| !lfs3_t_ismkconsistent(lfs3->cfg->gc_flags));
|
|| !lfs3_t_ismkconsistent(lfs3->cfg->gc_flags));
|
||||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||||
|| !lfs3_t_islookahead(lfs3->cfg->gc_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_ASSERT(!lfs3_m_isrdonly(lfs3->flags)
|
||||||
|| !lfs3_t_compact(lfs3->cfg->gc_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_ASSERT((flags & ~(
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT)
|
||||||
| LFS3_GC_CKMETA
|
| LFS3_GC_CKMETA
|
||||||
| LFS3_GC_CKDATA)) == 0);
|
| LFS3_GC_CKDATA)) == 0);
|
||||||
@@ -16571,7 +16793,7 @@ int lfs3_fs_grow(lfs3_t *lfs3, lfs3_size_t block_count_) {
|
|||||||
// need a new range
|
// need a new range
|
||||||
lfs3_stag_t tag = lfs3_gbmap_lookupnext(lfs3, &lfs3->gbmap.b,
|
lfs3_stag_t tag = lfs3_gbmap_lookupnext(lfs3, &lfs3->gbmap.b,
|
||||||
block_count-1,
|
block_count-1,
|
||||||
NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
if (tag < 0) {
|
if (tag < 0) {
|
||||||
LFS3_ASSERT(tag != LFS3_ERR_NOENT);
|
LFS3_ASSERT(tag != LFS3_ERR_NOENT);
|
||||||
err = tag;
|
err = tag;
|
||||||
@@ -16745,6 +16967,9 @@ int lfs3_trv_open(lfs3_t *lfs3, lfs3_trv_t *trv, uint32_t flags) {
|
|||||||
| LFS3_T_EXCL
|
| LFS3_T_EXCL
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_T_MKCONSISTENT)
|
| LFS3_IFDEF_RDONLY(0, LFS3_T_MKCONSISTENT)
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_T_LOOKAHEAD)
|
| 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_IFDEF_RDONLY(0, LFS3_T_COMPACT)
|
||||||
| LFS3_T_CKMETA
|
| LFS3_T_CKMETA
|
||||||
| LFS3_T_CKDATA)) == 0);
|
| 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
|
// these flags require a writable traversal
|
||||||
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_ismkconsistent(flags));
|
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_islookahead(flags));
|
||||||
|
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_ispreerase(flags));
|
||||||
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_compact(flags));
|
LFS3_ASSERT(!lfs3_t_isrdonly(flags) || !lfs3_t_compact(flags));
|
||||||
// some flags don't make sense when only traversing the mtree
|
// some flags don't make sense when only traversing the mtree
|
||||||
LFS3_ASSERT(!lfs3_t_ismtreeonly(flags) || !lfs3_t_islookahead(flags));
|
LFS3_ASSERT(!lfs3_t_ismtreeonly(flags) || !lfs3_t_islookahead(flags));
|
||||||
|
|||||||
@@ -211,6 +211,9 @@ enum lfs3_type {
|
|||||||
#define LFS3_F_LOOKAHEAD \
|
#define LFS3_F_LOOKAHEAD \
|
||||||
0x00000200 // Repopulate lookahead/gbmap
|
0x00000200 // Repopulate lookahead/gbmap
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define LFS3_F_PREERASE 0x00000400 // Try to pre-erase free blocks
|
||||||
|
#endif
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
#define LFS3_F_COMPACT 0x00000800 // Compact metadata logs
|
#define LFS3_F_COMPACT 0x00000800 // Compact metadata logs
|
||||||
#endif
|
#endif
|
||||||
@@ -228,6 +231,9 @@ enum lfs3_type {
|
|||||||
#define LFS3_F_GC ( \
|
#define LFS3_F_GC ( \
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_F_MKCONSISTENT) \
|
LFS3_IFDEF_RDONLY(0, LFS3_F_MKCONSISTENT) \
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_F_LOOKAHEAD) \
|
| LFS3_IFDEF_RDONLY(0, LFS3_F_LOOKAHEAD) \
|
||||||
|
| LFS3_IFDEF_RDONLY(0, \
|
||||||
|
LFS3_IFDEF_GBMAP( \
|
||||||
|
LFS3_IFDEF_PREERASE(LFS3_F_PREERASE, 0), 0)) \
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_F_COMPACT) \
|
| LFS3_IFDEF_RDONLY(0, LFS3_F_COMPACT) \
|
||||||
| LFS3_F_CKMETA \
|
| LFS3_F_CKMETA \
|
||||||
| LFS3_F_CKDATA)
|
| LFS3_F_CKDATA)
|
||||||
@@ -269,6 +275,9 @@ enum lfs3_type {
|
|||||||
#define LFS3_M_LOOKAHEAD \
|
#define LFS3_M_LOOKAHEAD \
|
||||||
0x00000200 // Repopulate lookahead/gbmap
|
0x00000200 // Repopulate lookahead/gbmap
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define LFS3_M_PREERASE 0x00000400 // Try to pre-erase free blocks
|
||||||
|
#endif
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
#define LFS3_M_COMPACT 0x00000800 // Compact metadata logs
|
#define LFS3_M_COMPACT 0x00000800 // Compact metadata logs
|
||||||
#endif
|
#endif
|
||||||
@@ -282,6 +291,9 @@ enum lfs3_type {
|
|||||||
#define LFS3_M_GC ( \
|
#define LFS3_M_GC ( \
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_M_MKCONSISTENT) \
|
LFS3_IFDEF_RDONLY(0, LFS3_M_MKCONSISTENT) \
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_M_LOOKAHEAD) \
|
| 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_IFDEF_RDONLY(0, LFS3_M_COMPACT) \
|
||||||
| LFS3_M_CKMETA \
|
| LFS3_M_CKMETA \
|
||||||
| LFS3_M_CKDATA)
|
| LFS3_M_CKDATA)
|
||||||
@@ -322,6 +334,9 @@ enum lfs3_type {
|
|||||||
#define LFS3_I_LOOKAHEAD \
|
#define LFS3_I_LOOKAHEAD \
|
||||||
0x00000200 // Lookahead/gbmap is not full
|
0x00000200 // Lookahead/gbmap is not full
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define LFS3_I_PREERASE 0x00000400 // Blocks can be pre-erased
|
||||||
|
#endif
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
#define LFS3_I_COMPACT 0x00000800 // Filesystem may have uncompacted metadata
|
#define LFS3_I_COMPACT 0x00000800 // Filesystem may have uncompacted metadata
|
||||||
#endif
|
#endif
|
||||||
@@ -352,6 +367,9 @@ enum lfs3_btype {
|
|||||||
#define LFS3_T_LOOKAHEAD \
|
#define LFS3_T_LOOKAHEAD \
|
||||||
0x00000200 // Repopulate lookahead/gbmap
|
0x00000200 // Repopulate lookahead/gbmap
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define LFS3_T_PREERASE 0x00000400 // Try to pre-erase free blocks
|
||||||
|
#endif
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
#define LFS3_T_COMPACT 0x00000800 // Compact metadata logs
|
#define LFS3_T_COMPACT 0x00000800 // Compact metadata logs
|
||||||
#endif
|
#endif
|
||||||
@@ -374,6 +392,9 @@ enum lfs3_btype {
|
|||||||
#define LFS3_T_GC ( \
|
#define LFS3_T_GC ( \
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_T_MKCONSISTENT) \
|
LFS3_IFDEF_RDONLY(0, LFS3_T_MKCONSISTENT) \
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_T_LOOKAHEAD) \
|
| 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_IFDEF_RDONLY(0, LFS3_T_COMPACT) \
|
||||||
| LFS3_T_CKMETA \
|
| LFS3_T_CKMETA \
|
||||||
| LFS3_T_CKDATA)
|
| LFS3_T_CKDATA)
|
||||||
@@ -387,6 +408,10 @@ enum lfs3_btype {
|
|||||||
#define LFS3_CK_LOOKAHEAD \
|
#define LFS3_CK_LOOKAHEAD \
|
||||||
0x00000200 // Repopulate lookahead/gbmap
|
0x00000200 // Repopulate lookahead/gbmap
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define LFS3_CK_PREERASE \
|
||||||
|
0x00000400 // Try to pre-erase free blocks
|
||||||
|
#endif
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
#define LFS3_CK_COMPACT 0x00000800 // Compact metadata logs
|
#define LFS3_CK_COMPACT 0x00000800 // Compact metadata logs
|
||||||
#endif
|
#endif
|
||||||
@@ -400,6 +425,9 @@ enum lfs3_btype {
|
|||||||
#define LFS3_CK_GC ( \
|
#define LFS3_CK_GC ( \
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_CK_MKCONSISTENT) \
|
LFS3_IFDEF_RDONLY(0, LFS3_CK_MKCONSISTENT) \
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_CK_LOOKAHEAD) \
|
| 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_IFDEF_RDONLY(0, LFS3_CK_COMPACT) \
|
||||||
| LFS3_CK_CKMETA \
|
| LFS3_CK_CKMETA \
|
||||||
| LFS3_CK_CKDATA)
|
| LFS3_CK_CKDATA)
|
||||||
@@ -413,6 +441,10 @@ enum lfs3_btype {
|
|||||||
#define LFS3_GC_LOOKAHEAD \
|
#define LFS3_GC_LOOKAHEAD \
|
||||||
0x00000200 // Repopulate lookahead/gbmap
|
0x00000200 // Repopulate lookahead/gbmap
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define LFS3_GC_PREERASE \
|
||||||
|
0x00000400 // Try to pre-erase free blocks
|
||||||
|
#endif
|
||||||
#ifndef LFS3_RDONLY
|
#ifndef LFS3_RDONLY
|
||||||
#define LFS3_GC_COMPACT 0x00000800 // Compact metadata logs
|
#define LFS3_GC_COMPACT 0x00000800 // Compact metadata logs
|
||||||
#endif
|
#endif
|
||||||
@@ -426,6 +458,9 @@ enum lfs3_btype {
|
|||||||
#define LFS3_GC_GC ( \
|
#define LFS3_GC_GC ( \
|
||||||
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT) \
|
LFS3_IFDEF_RDONLY(0, LFS3_GC_MKCONSISTENT) \
|
||||||
| LFS3_IFDEF_RDONLY(0, LFS3_GC_LOOKAHEAD) \
|
| 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_IFDEF_RDONLY(0, LFS3_GC_COMPACT) \
|
||||||
| LFS3_GC_CKMETA \
|
| LFS3_GC_CKMETA \
|
||||||
| LFS3_GC_CKDATA)
|
| LFS3_GC_CKDATA)
|
||||||
@@ -577,6 +612,22 @@ struct lfs3_cfg {
|
|||||||
lfs3_block_t gc_lookgbmap_thresh;
|
lfs3_block_t gc_lookgbmap_thresh;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Number of blocks to try to pre-erase during gc. When erase is
|
||||||
|
// expensive (flash), pre-erasing blocks can help reduce the latency
|
||||||
|
// of block allocation.
|
||||||
|
//
|
||||||
|
// Requires the gbmap to track pre-erased blocks.
|
||||||
|
//
|
||||||
|
// 0 only erases blocks immediately before prog, while -1 or any
|
||||||
|
// value >= block_count attempts to pre-erase all known free blocks
|
||||||
|
// during gc.
|
||||||
|
//
|
||||||
|
#if !defined(LFS3_RDONLY) \
|
||||||
|
&& defined(LFS3_GBMAP) \
|
||||||
|
&& !defined(LFS3_NO_PREERASE)
|
||||||
|
lfs3_block_t gc_preerase_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Threshold for metadata compaction during gc in bytes.
|
// Threshold for metadata compaction during gc in bytes.
|
||||||
//
|
//
|
||||||
// Metadata logs that exceed this threshold will be compacted during
|
// Metadata logs that exceed this threshold will be compacted during
|
||||||
@@ -1083,6 +1134,15 @@ typedef struct lfs3_bptr {
|
|||||||
#endif
|
#endif
|
||||||
} lfs3_bptr_t;
|
} lfs3_bptr_t;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
#endif
|
||||||
|
|
||||||
// littlefs's core metadata log type
|
// littlefs's core metadata log type
|
||||||
typedef struct lfs3_rbyd {
|
typedef struct lfs3_rbyd {
|
||||||
lfs3_rid_t weight;
|
lfs3_rid_t weight;
|
||||||
@@ -1317,7 +1377,16 @@ typedef struct lfs3 {
|
|||||||
struct lfs3_gbmap {
|
struct lfs3_gbmap {
|
||||||
lfs3_block_t window;
|
lfs3_block_t window;
|
||||||
lfs3_block_t known;
|
lfs3_block_t known;
|
||||||
|
#if !defined(LFS3_RDONLY)
|
||||||
lfs3_sblock_t free;
|
lfs3_sblock_t free;
|
||||||
|
#endif
|
||||||
|
#if !defined(LFS3_RDONLY) && !defined(LFS3_NO_PREERASE)
|
||||||
|
lfs3_ecksum_t ecksum;
|
||||||
|
struct lfs3_preeraser {
|
||||||
|
lfs3_block_t known;
|
||||||
|
lfs3_block_t count;
|
||||||
|
} preeraser;
|
||||||
|
#endif
|
||||||
lfs3_btree_t b;
|
lfs3_btree_t b;
|
||||||
lfs3_btree_t b_p;
|
lfs3_btree_t b_p;
|
||||||
} gbmap;
|
} gbmap;
|
||||||
|
|||||||
@@ -276,6 +276,12 @@
|
|||||||
#define LFS3_IFDEF_YES_GBMAP(a, b) (b)
|
#define LFS3_IFDEF_YES_GBMAP(a, b) (b)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_NO_PREERASE
|
||||||
|
#define LFS3_IFDEF_PREERASE(a, b) (a)
|
||||||
|
#else
|
||||||
|
#define LFS3_IFDEF_PREERASE(a, b) (b)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LFS3_BLEAFCACHE
|
#ifdef LFS3_BLEAFCACHE
|
||||||
#define LFS3_IFDEF_BLEAFCACHE(a, b) (a)
|
#define LFS3_IFDEF_BLEAFCACHE(a, b) (a)
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
BENCH_DEFINE(GC_STEPS, 0 ) \
|
BENCH_DEFINE(GC_STEPS, 0 ) \
|
||||||
BENCH_DEFINE(GC_LOOKAHEAD_THRESH, -1 ) \
|
BENCH_DEFINE(GC_LOOKAHEAD_THRESH, -1 ) \
|
||||||
BENCH_DEFINE(GC_LOOKGBMAP_THRESH, -1 ) \
|
BENCH_DEFINE(GC_LOOKGBMAP_THRESH, -1 ) \
|
||||||
|
BENCH_DEFINE(GC_PREERASE_COUNT, -1 ) \
|
||||||
BENCH_DEFINE(GC_COMPACT_THRESH, 0 ) \
|
BENCH_DEFINE(GC_COMPACT_THRESH, 0 ) \
|
||||||
BENCH_DEFINE(SHRUB_SIZE, BLOCK_SIZE/4 ) \
|
BENCH_DEFINE(SHRUB_SIZE, BLOCK_SIZE/4 ) \
|
||||||
BENCH_DEFINE(FRAGMENT_SIZE, LFS3_MIN(BLOCK_SIZE/8, 512) ) \
|
BENCH_DEFINE(FRAGMENT_SIZE, LFS3_MIN(BLOCK_SIZE/8, 512) ) \
|
||||||
@@ -148,6 +149,7 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
.fcache_size = FCACHE_SIZE, \
|
.fcache_size = FCACHE_SIZE, \
|
||||||
.lookahead_size = LOOKAHEAD_SIZE, \
|
.lookahead_size = LOOKAHEAD_SIZE, \
|
||||||
BENCH_GBMAP_CFG \
|
BENCH_GBMAP_CFG \
|
||||||
|
BENCH_PREERASE_CFG \
|
||||||
BENCH_GC_CFG \
|
BENCH_GC_CFG \
|
||||||
.gc_lookahead_thresh = GC_LOOKAHEAD_THRESH, \
|
.gc_lookahead_thresh = GC_LOOKAHEAD_THRESH, \
|
||||||
.gc_compact_thresh = GC_COMPACT_THRESH, \
|
.gc_compact_thresh = GC_COMPACT_THRESH, \
|
||||||
@@ -163,6 +165,13 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
#define BENCH_GBMAP_CFG
|
#define BENCH_GBMAP_CFG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define BENCH_PREERASE_CFG \
|
||||||
|
.gc_preerase_count = GC_PREERASE_COUNT,
|
||||||
|
#else
|
||||||
|
#define BENCH_PREERASE_CFG
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LFS3_GC
|
#ifdef LFS3_GC
|
||||||
#define BENCH_GC_CFG \
|
#define BENCH_GC_CFG \
|
||||||
.gc_flags = GC_FLAGS, \
|
.gc_flags = GC_FLAGS, \
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
TEST_DEFINE(GC_STEPS, 0 ) \
|
TEST_DEFINE(GC_STEPS, 0 ) \
|
||||||
TEST_DEFINE(GC_LOOKAHEAD_THRESH, -1 ) \
|
TEST_DEFINE(GC_LOOKAHEAD_THRESH, -1 ) \
|
||||||
TEST_DEFINE(GC_LOOKGBMAP_THRESH, -1 ) \
|
TEST_DEFINE(GC_LOOKGBMAP_THRESH, -1 ) \
|
||||||
|
TEST_DEFINE(GC_PREERASE_COUNT, -1 ) \
|
||||||
TEST_DEFINE(GC_COMPACT_THRESH, 0 ) \
|
TEST_DEFINE(GC_COMPACT_THRESH, 0 ) \
|
||||||
TEST_DEFINE(SHRUB_SIZE, BLOCK_SIZE/4 ) \
|
TEST_DEFINE(SHRUB_SIZE, BLOCK_SIZE/4 ) \
|
||||||
TEST_DEFINE(FRAGMENT_SIZE, LFS3_MIN(BLOCK_SIZE/8, 512) ) \
|
TEST_DEFINE(FRAGMENT_SIZE, LFS3_MIN(BLOCK_SIZE/8, 512) ) \
|
||||||
@@ -139,6 +140,7 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
.fcache_size = FCACHE_SIZE, \
|
.fcache_size = FCACHE_SIZE, \
|
||||||
.lookahead_size = LOOKAHEAD_SIZE, \
|
.lookahead_size = LOOKAHEAD_SIZE, \
|
||||||
TEST_GBMAP_CFG \
|
TEST_GBMAP_CFG \
|
||||||
|
TEST_PREERASE_CFG \
|
||||||
TEST_GC_CFG \
|
TEST_GC_CFG \
|
||||||
.gc_lookahead_thresh = GC_LOOKAHEAD_THRESH, \
|
.gc_lookahead_thresh = GC_LOOKAHEAD_THRESH, \
|
||||||
.gc_compact_thresh = GC_COMPACT_THRESH, \
|
.gc_compact_thresh = GC_COMPACT_THRESH, \
|
||||||
@@ -154,6 +156,13 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
#define TEST_GBMAP_CFG
|
#define TEST_GBMAP_CFG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LFS3_GBMAP) && !defined(LFS3_NO_PREERASE)
|
||||||
|
#define TEST_PREERASE_CFG \
|
||||||
|
.gc_preerase_count = GC_PREERASE_COUNT,
|
||||||
|
#else
|
||||||
|
#define TEST_PREERASE_CFG
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LFS3_GC
|
#ifdef LFS3_GC
|
||||||
#define TEST_GC_CFG \
|
#define TEST_GC_CFG \
|
||||||
.gc_flags = GC_FLAGS, \
|
.gc_flags = GC_FLAGS, \
|
||||||
|
|||||||
+11
-5
@@ -84,11 +84,12 @@ F_CKDATACKSUMS = 0x01000000 # y- Check data checksums on reads
|
|||||||
|
|
||||||
F_MKCONSISTENT = 0x00000100 # y- Make the filesystem consistent
|
F_MKCONSISTENT = 0x00000100 # y- Make the filesystem consistent
|
||||||
F_LOOKAHEAD = 0x00000200 # y- Repopulate lookahead buffer
|
F_LOOKAHEAD = 0x00000200 # y- Repopulate lookahead buffer
|
||||||
|
F_PREERASE = 0x00000400 # y- Try to pre-erase free blocks
|
||||||
F_COMPACT = 0x00000800 # y- Compact metadata logs
|
F_COMPACT = 0x00000800 # y- Compact metadata logs
|
||||||
F_CKMETA = 0x00001000 # y- Check metadata checksums
|
F_CKMETA = 0x00001000 # y- Check metadata checksums
|
||||||
F_CKDATA = 0x00002000 # y- Check metadata + data checksums
|
F_CKDATA = 0x00002000 # y- Check metadata + data checksums
|
||||||
F_CK = 0x00003000 # a- Alias for all check work
|
F_CK = 0x00003000 # a- Alias for all check work
|
||||||
F_GC = 0x00003b00 # a- Alias for all gc work
|
F_GC = 0x00003f00 # a- Alias for all gc work
|
||||||
|
|
||||||
# Filesystem mount flags
|
# Filesystem mount flags
|
||||||
M_MODE = 1 # -m Mount's access mode
|
M_MODE = 1 # -m Mount's access mode
|
||||||
@@ -105,29 +106,32 @@ M_CKDATACKSUMS = 0x01000000 # y- Check data checksums on reads
|
|||||||
|
|
||||||
M_MKCONSISTENT = 0x00000100 # y- Make the filesystem consistent
|
M_MKCONSISTENT = 0x00000100 # y- Make the filesystem consistent
|
||||||
M_LOOKAHEAD = 0x00000200 # y- Repopulate lookahead buffer
|
M_LOOKAHEAD = 0x00000200 # y- Repopulate lookahead buffer
|
||||||
|
M_PREERASE = 0x00000400 # y- Try to pre-erase free blocks
|
||||||
M_COMPACT = 0x00000800 # y- Compact metadata logs
|
M_COMPACT = 0x00000800 # y- Compact metadata logs
|
||||||
M_CKMETA = 0x00001000 # y- Check metadata checksums
|
M_CKMETA = 0x00001000 # y- Check metadata checksums
|
||||||
M_CKDATA = 0x00002000 # y- Check metadata + data checksums
|
M_CKDATA = 0x00002000 # y- Check metadata + data checksums
|
||||||
M_CK = 0x00003000 # a- Alias for all check work
|
M_CK = 0x00003000 # a- Alias for all check work
|
||||||
M_GC = 0x00003b00 # a- Alias for all gc work
|
M_GC = 0x00003f00 # a- Alias for all gc work
|
||||||
|
|
||||||
# File/filesystem check flags
|
# File/filesystem check flags
|
||||||
CK_MKCONSISTENT = 0x00000100 # -- Make the filesystem consistent
|
CK_MKCONSISTENT = 0x00000100 # -- Make the filesystem consistent
|
||||||
CK_LOOKAHEAD = 0x00000200 # -- Repopulate lookahead buffer
|
CK_LOOKAHEAD = 0x00000200 # -- Repopulate lookahead buffer
|
||||||
|
CK_PREERASE = 0x00000400 # -- Try to pre-erase free blocks
|
||||||
CK_COMPACT = 0x00000800 # -- Compact metadata logs
|
CK_COMPACT = 0x00000800 # -- Compact metadata logs
|
||||||
CK_CKMETA = 0x00001000 # -- Check metadata checksums
|
CK_CKMETA = 0x00001000 # -- Check metadata checksums
|
||||||
CK_CKDATA = 0x00002000 # -- Check metadata + data checksums
|
CK_CKDATA = 0x00002000 # -- Check metadata + data checksums
|
||||||
CK_CK = 0x00003000 # a- Alias for all check work
|
CK_CK = 0x00003000 # a- Alias for all check work
|
||||||
CK_GC = 0x00003b00 # a- Alias for all gc work
|
CK_GC = 0x00003f00 # a- Alias for all gc work
|
||||||
|
|
||||||
# GC flags
|
# GC flags
|
||||||
GC_MKCONSISTENT = 0x00000100 # -- Make the filesystem consistent
|
GC_MKCONSISTENT = 0x00000100 # -- Make the filesystem consistent
|
||||||
GC_LOOKAHEAD = 0x00000200 # -- Repopulate lookahead buffer
|
GC_LOOKAHEAD = 0x00000200 # -- Repopulate lookahead buffer
|
||||||
|
GC_PREERASE = 0x00000400 # -- Try to pre-erase free blocks
|
||||||
GC_COMPACT = 0x00000800 # -- Compact metadata logs
|
GC_COMPACT = 0x00000800 # -- Compact metadata logs
|
||||||
GC_CKMETA = 0x00001000 # -- Check metadata checksums
|
GC_CKMETA = 0x00001000 # -- Check metadata checksums
|
||||||
GC_CKDATA = 0x00002000 # -- Check metadata + data checksums
|
GC_CKDATA = 0x00002000 # -- Check metadata + data checksums
|
||||||
GC_CK = 0x00003000 # a- Alias for all check work
|
GC_CK = 0x00003000 # a- Alias for all check work
|
||||||
GC_GC = 0x00003b00 # a- Alias for all gc work
|
GC_GC = 0x00003f00 # a- Alias for all gc work
|
||||||
|
|
||||||
# Filesystem info flags
|
# Filesystem info flags
|
||||||
I_RDONLY = 0x00000001 # -- Mounted read only
|
I_RDONLY = 0x00000001 # -- Mounted read only
|
||||||
@@ -144,6 +148,7 @@ I_CKDATACKSUMS = 0x01000000 # -- Mounted with LFS3_M_CKDATACKSUMS
|
|||||||
|
|
||||||
I_MKCONSISTENT = 0x00000100 # -- Filesystem needs mkconsistent to write
|
I_MKCONSISTENT = 0x00000100 # -- Filesystem needs mkconsistent to write
|
||||||
I_LOOKAHEAD = 0x00000200 # -- Lookahead buffer is not full
|
I_LOOKAHEAD = 0x00000200 # -- Lookahead buffer is not full
|
||||||
|
I_PREERASE = 0x00000400 # -- Blocks can be pre-erased
|
||||||
I_COMPACT = 0x00000800 # -- Filesystem may have uncompacted metadata
|
I_COMPACT = 0x00000800 # -- Filesystem may have uncompacted metadata
|
||||||
I_CKMETA = 0x00001000 # -- Metadata checksums not checked recently
|
I_CKMETA = 0x00001000 # -- Metadata checksums not checked recently
|
||||||
I_CKDATA = 0x00002000 # -- Data checksums not checked recently
|
I_CKDATA = 0x00002000 # -- Data checksums not checked recently
|
||||||
@@ -156,11 +161,12 @@ T_MTREEONLY = 0x00000002 # -- Only traverse the mtree
|
|||||||
T_EXCL = 0x00000008 # -- Error if filesystem modified
|
T_EXCL = 0x00000008 # -- Error if filesystem modified
|
||||||
T_MKCONSISTENT = 0x00000100 # -- Make the filesystem consistent
|
T_MKCONSISTENT = 0x00000100 # -- Make the filesystem consistent
|
||||||
T_LOOKAHEAD = 0x00000200 # -- Repopulate lookahead buffer
|
T_LOOKAHEAD = 0x00000200 # -- Repopulate lookahead buffer
|
||||||
|
T_PREERASE = 0x00000400 # -- Try to pre-erase free blocks
|
||||||
T_COMPACT = 0x00000800 # -- Compact metadata logs
|
T_COMPACT = 0x00000800 # -- Compact metadata logs
|
||||||
T_CKMETA = 0x00001000 # -- Check metadata checksums
|
T_CKMETA = 0x00001000 # -- Check metadata checksums
|
||||||
T_CKDATA = 0x00002000 # -- Check metadata + data checksums
|
T_CKDATA = 0x00002000 # -- Check metadata + data checksums
|
||||||
T_CK = 0x00003000 # a- Alias for all check work
|
T_CK = 0x00003000 # a- Alias for all check work
|
||||||
T_GC = 0x00003b00 # a- Alias for all gc work
|
T_GC = 0x00003f00 # a- Alias for all gc work
|
||||||
|
|
||||||
t_TYPE = 0xf0000000 # im The traversal's type
|
t_TYPE = 0xf0000000 # im The traversal's type
|
||||||
t_REG = 0x10000000 # i^ Type = regular-file
|
t_REG = 0x10000000 # i^ Type = regular-file
|
||||||
|
|||||||
+582
-59
@@ -29,9 +29,9 @@ code = '''
|
|||||||
LFS3_RATTR_NULL)) => 0;
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
// set some blocks as in-use, avoid any weird merges for now
|
// set some blocks as in-use, avoid any weird merges for now
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
printf("gbmap: w%d 0x%x.%x\n",
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
gbmap.r.weight,
|
gbmap.r.weight,
|
||||||
gbmap.r.blocks[0],
|
gbmap.r.blocks[0],
|
||||||
@@ -44,31 +44,31 @@ code = '''
|
|||||||
lfs3_bid_t bid_;
|
lfs3_bid_t bid_;
|
||||||
lfs3_bid_t weight_;
|
lfs3_bid_t weight_;
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 5);
|
assert(bid_ == 5);
|
||||||
assert(weight_ == 6);
|
assert(weight_ == 6);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 6);
|
assert(bid_ == 6);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 7);
|
assert(bid_ == 7);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 8);
|
assert(bid_ == 8);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 9);
|
assert(bid_ == 9);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 10);
|
assert(bid_ == 10);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == BLOCK_COUNT-1);
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
assert(weight_ == BLOCK_COUNT-11);
|
assert(weight_ == BLOCK_COUNT-11);
|
||||||
|
|
||||||
@@ -92,13 +92,13 @@ code = '''
|
|||||||
LFS3_RATTR_NULL)) => 0;
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
// set some blocks as in-use, avoid any weird merges for now
|
// set some blocks as in-use, avoid any weird merges for now
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
// replace those blocks as bad, this tests deleting ranges
|
// replace those blocks as bad, this tests deleting ranges
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMBAD) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMBAD, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMBAD) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMBAD, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMBAD) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMBAD, NULL) => 0;
|
||||||
printf("gbmap: w%d 0x%x.%x\n",
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
gbmap.r.weight,
|
gbmap.r.weight,
|
||||||
gbmap.r.blocks[0],
|
gbmap.r.blocks[0],
|
||||||
@@ -111,31 +111,31 @@ code = '''
|
|||||||
lfs3_bid_t bid_;
|
lfs3_bid_t bid_;
|
||||||
lfs3_bid_t weight_;
|
lfs3_bid_t weight_;
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 5);
|
assert(bid_ == 5);
|
||||||
assert(weight_ == 6);
|
assert(weight_ == 6);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMBAD;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMBAD;
|
||||||
assert(bid_ == 6);
|
assert(bid_ == 6);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 7);
|
assert(bid_ == 7);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMBAD;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMBAD;
|
||||||
assert(bid_ == 8);
|
assert(bid_ == 8);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 9);
|
assert(bid_ == 9);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMBAD;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMBAD;
|
||||||
assert(bid_ == 10);
|
assert(bid_ == 10);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == BLOCK_COUNT-1);
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
assert(weight_ == BLOCK_COUNT-11);
|
assert(weight_ == BLOCK_COUNT-11);
|
||||||
|
|
||||||
@@ -159,14 +159,14 @@ code = '''
|
|||||||
LFS3_RATTR_NULL)) => 0;
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
// set some blocks as in-use, avoid any weird merges for now
|
// set some blocks as in-use, avoid any weird merges for now
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 12, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 12, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
// set neighboring blocks as in-use, triggering merges
|
// set neighboring blocks as in-use, triggering merges
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 5, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 5, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 9, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 9, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 13, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 13, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
printf("gbmap: w%d 0x%x.%x\n",
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
gbmap.r.weight,
|
gbmap.r.weight,
|
||||||
gbmap.r.blocks[0],
|
gbmap.r.blocks[0],
|
||||||
@@ -179,31 +179,31 @@ code = '''
|
|||||||
lfs3_bid_t bid_;
|
lfs3_bid_t bid_;
|
||||||
lfs3_bid_t weight_;
|
lfs3_bid_t weight_;
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 4);
|
assert(bid_ == 4);
|
||||||
assert(weight_ == 5);
|
assert(weight_ == 5);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 5,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 5,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 6);
|
assert(bid_ == 6);
|
||||||
assert(weight_ == 2);
|
assert(weight_ == 2);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 7);
|
assert(bid_ == 7);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 10);
|
assert(bid_ == 10);
|
||||||
assert(weight_ == 3);
|
assert(weight_ == 3);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 11);
|
assert(bid_ == 11);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 12,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 12,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 13);
|
assert(bid_ == 13);
|
||||||
assert(weight_ == 2);
|
assert(weight_ == 2);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 14,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 14,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == BLOCK_COUNT-1);
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
assert(weight_ == BLOCK_COUNT-14);
|
assert(weight_ == BLOCK_COUNT-14);
|
||||||
|
|
||||||
@@ -227,15 +227,15 @@ code = '''
|
|||||||
LFS3_RATTR_NULL)) => 0;
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
// set some blocks as in-use, avoid any weird merges for now
|
// set some blocks as in-use, avoid any weird merges for now
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
// test a bunch of noops
|
// test a bunch of noops
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 7, LFS3_TAG_BMFREE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 7, LFS3_TAG_BMFREE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 9, LFS3_TAG_BMFREE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 9, LFS3_TAG_BMFREE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
printf("gbmap: w%d 0x%x.%x\n",
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
gbmap.r.weight,
|
gbmap.r.weight,
|
||||||
gbmap.r.blocks[0],
|
gbmap.r.blocks[0],
|
||||||
@@ -248,31 +248,31 @@ code = '''
|
|||||||
lfs3_bid_t bid_;
|
lfs3_bid_t bid_;
|
||||||
lfs3_bid_t weight_;
|
lfs3_bid_t weight_;
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 5);
|
assert(bid_ == 5);
|
||||||
assert(weight_ == 6);
|
assert(weight_ == 6);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 6);
|
assert(bid_ == 6);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 7);
|
assert(bid_ == 7);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 8);
|
assert(bid_ == 8);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == 9);
|
assert(bid_ == 9);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 10);
|
assert(bid_ == 10);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == BLOCK_COUNT-1);
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
assert(weight_ == BLOCK_COUNT-11);
|
assert(weight_ == BLOCK_COUNT-11);
|
||||||
|
|
||||||
@@ -298,8 +298,8 @@ code = '''
|
|||||||
// test that setting the first and last blocks don't break anything
|
// test that setting the first and last blocks don't break anything
|
||||||
//
|
//
|
||||||
// though in theory blocks 0x{0,1} are immutable...
|
// though in theory blocks 0x{0,1} are immutable...
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, 0, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, 0, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, BLOCK_COUNT-1, LFS3_TAG_BMINUSE) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, BLOCK_COUNT-1, LFS3_TAG_BMINUSE, NULL) => 0;
|
||||||
printf("gbmap: w%d 0x%x.%x\n",
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
gbmap.r.weight,
|
gbmap.r.weight,
|
||||||
gbmap.r.blocks[0],
|
gbmap.r.blocks[0],
|
||||||
@@ -312,15 +312,15 @@ code = '''
|
|||||||
lfs3_bid_t bid_;
|
lfs3_bid_t bid_;
|
||||||
lfs3_bid_t weight_;
|
lfs3_bid_t weight_;
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == 0);
|
assert(bid_ == 0);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 1,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 1,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMFREE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMFREE;
|
||||||
assert(bid_ == BLOCK_COUNT-2);
|
assert(bid_ == BLOCK_COUNT-2);
|
||||||
assert(weight_ == BLOCK_COUNT-2);
|
assert(weight_ == BLOCK_COUNT-2);
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, BLOCK_COUNT-1,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, BLOCK_COUNT-1,
|
||||||
&bid_, &weight_) => LFS3_TAG_BMINUSE;
|
&bid_, &weight_, NULL) => LFS3_TAG_BMINUSE;
|
||||||
assert(bid_ == BLOCK_COUNT-1);
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
assert(weight_ == 1);
|
assert(weight_ == 1);
|
||||||
|
|
||||||
@@ -361,7 +361,7 @@ code = '''
|
|||||||
lfs3_tag_t tag = LFS3_TAG_BMRANGE + (TEST_PRNG(&prng) % TYPES);
|
lfs3_tag_t tag = LFS3_TAG_BMRANGE + (TEST_PRNG(&prng) % TYPES);
|
||||||
|
|
||||||
// set in gbmap
|
// set in gbmap
|
||||||
lfs3_gbmap_mark(&lfs3, &gbmap, block, tag) => 0;
|
lfs3_gbmap_mark(&lfs3, &gbmap, block, tag, NULL) => 0;
|
||||||
|
|
||||||
// and set in sim
|
// and set in sim
|
||||||
sim[block] = tag;
|
sim[block] = tag;
|
||||||
@@ -386,7 +386,7 @@ code = '''
|
|||||||
lfs3_bid_t bid_;
|
lfs3_bid_t bid_;
|
||||||
lfs3_bid_t weight_;
|
lfs3_bid_t weight_;
|
||||||
lfs3_gbmap_lookupnext(&lfs3, &gbmap, i,
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, i,
|
||||||
&bid_, &weight_) => tag;
|
&bid_, &weight_, NULL) => tag;
|
||||||
assert(bid_ == i+(weight_-1));
|
assert(bid_ == i+(weight_-1));
|
||||||
assert(weight_ == d);
|
assert(weight_ == d);
|
||||||
|
|
||||||
@@ -398,6 +398,413 @@ code = '''
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
# set operations with ecksums are a bit more complicated
|
||||||
|
[cases.test_gbmap_mark_ecksum_split]
|
||||||
|
in = 'lfs3.c'
|
||||||
|
code = '''
|
||||||
|
lfs3_t lfs3;
|
||||||
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
||||||
|
lfs3_alloc_ckpoint(&lfs3);
|
||||||
|
|
||||||
|
// create an initial gbmap
|
||||||
|
lfs3_btree_t gbmap;
|
||||||
|
lfs3_btree_init(&gbmap);
|
||||||
|
lfs3_gbmap_commit(&lfs3, &gbmap, 0, LFS3_RATTRS(
|
||||||
|
LFS3_RATTR(2, LFS3_TAG_BMFREE, -2),
|
||||||
|
LFS3_RATTR_WEIGHT(+BLOCK_COUNT),
|
||||||
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
|
// set some blocks as erased with ecksums, avoid any weird merges
|
||||||
|
// for now
|
||||||
|
lfs3_ecksum_t ecksum = {.cksize=CFG->prog_size, .cksum=0x12345678};
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
|
gbmap.r.weight,
|
||||||
|
gbmap.r.blocks[0],
|
||||||
|
gbmap.r.trunk);
|
||||||
|
|
||||||
|
// weight should stay the same
|
||||||
|
assert(gbmap.r.weight == BLOCK_COUNT);
|
||||||
|
|
||||||
|
// check ranges
|
||||||
|
lfs3_bid_t bid_;
|
||||||
|
lfs3_bid_t weight_;
|
||||||
|
lfs3_ecksum_t ecksum_;
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 5);
|
||||||
|
assert(weight_ == 6);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 6);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 7);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 8);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 9);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 10);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
|
assert(weight_ == BLOCK_COUNT-11);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
|
||||||
|
lfs3_unmount(&lfs3) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_gbmap_mark_ecksum_replace]
|
||||||
|
in = 'lfs3.c'
|
||||||
|
code = '''
|
||||||
|
lfs3_t lfs3;
|
||||||
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
||||||
|
lfs3_alloc_ckpoint(&lfs3);
|
||||||
|
|
||||||
|
// create an initial gbmap
|
||||||
|
lfs3_btree_t gbmap;
|
||||||
|
lfs3_btree_init(&gbmap);
|
||||||
|
lfs3_gbmap_commit(&lfs3, &gbmap, 0, LFS3_RATTRS(
|
||||||
|
LFS3_RATTR(2, LFS3_TAG_BMFREE, -2),
|
||||||
|
LFS3_RATTR_WEIGHT(+BLOCK_COUNT),
|
||||||
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
|
// set some blocks as erased with ecksums, avoid any weird merges
|
||||||
|
// for now
|
||||||
|
lfs3_ecksum_t ecksum_a = {.cksize=CFG->prog_size, .cksum=0x12345678};
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMERASED, &ecksum_a) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMERASED, &ecksum_a) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMERASED, &ecksum_a) => 0;
|
||||||
|
// replace those blocks with different ecksums
|
||||||
|
lfs3_ecksum_t ecksum_b = {.cksize=CFG->prog_size, .cksum=0x9abcdef0};
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMERASED, &ecksum_b) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMERASED, &ecksum_b) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMERASED, &ecksum_b) => 0;
|
||||||
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
|
gbmap.r.weight,
|
||||||
|
gbmap.r.blocks[0],
|
||||||
|
gbmap.r.trunk);
|
||||||
|
|
||||||
|
// weight should stay the same
|
||||||
|
assert(gbmap.r.weight == BLOCK_COUNT);
|
||||||
|
|
||||||
|
// check ranges
|
||||||
|
lfs3_bid_t bid_;
|
||||||
|
lfs3_bid_t weight_;
|
||||||
|
lfs3_ecksum_t ecksum_;
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 5);
|
||||||
|
assert(weight_ == 6);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 6);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_b) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 7);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 8);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_b) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 9);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 10);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_b) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
|
assert(weight_ == BLOCK_COUNT-11);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
|
||||||
|
lfs3_unmount(&lfs3) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_gbmap_mark_ecksum_merge]
|
||||||
|
in = 'lfs3.c'
|
||||||
|
code = '''
|
||||||
|
lfs3_t lfs3;
|
||||||
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
||||||
|
lfs3_alloc_ckpoint(&lfs3);
|
||||||
|
|
||||||
|
// create an initial gbmap
|
||||||
|
lfs3_btree_t gbmap;
|
||||||
|
lfs3_btree_init(&gbmap);
|
||||||
|
lfs3_gbmap_commit(&lfs3, &gbmap, 0, LFS3_RATTRS(
|
||||||
|
LFS3_RATTR(2, LFS3_TAG_BMFREE, -2),
|
||||||
|
LFS3_RATTR_WEIGHT(+BLOCK_COUNT),
|
||||||
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
|
// set some blocks as erased with ecksums, avoid any weird merges
|
||||||
|
// for now
|
||||||
|
lfs3_ecksum_t ecksum = {.cksize=CFG->prog_size, .cksum=0x12345678};
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 12, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
// set neighboring blocks as erased with ecksums, triggering merges
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 5, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 9, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 13, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
|
gbmap.r.weight,
|
||||||
|
gbmap.r.blocks[0],
|
||||||
|
gbmap.r.trunk);
|
||||||
|
|
||||||
|
// weight should stay the same
|
||||||
|
assert(gbmap.r.weight == BLOCK_COUNT);
|
||||||
|
|
||||||
|
// check ranges
|
||||||
|
lfs3_bid_t bid_;
|
||||||
|
lfs3_bid_t weight_;
|
||||||
|
lfs3_ecksum_t ecksum_;
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 4);
|
||||||
|
assert(weight_ == 5);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 5,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 6);
|
||||||
|
assert(weight_ == 2);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 7);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 10);
|
||||||
|
assert(weight_ == 3);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 11);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 12,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 13);
|
||||||
|
assert(weight_ == 2);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 14,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
|
assert(weight_ == BLOCK_COUNT-14);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
|
||||||
|
lfs3_unmount(&lfs3) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_gbmap_mark_ecksum_nomerge]
|
||||||
|
in = 'lfs3.c'
|
||||||
|
code = '''
|
||||||
|
lfs3_t lfs3;
|
||||||
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
||||||
|
lfs3_alloc_ckpoint(&lfs3);
|
||||||
|
|
||||||
|
// create an initial gbmap
|
||||||
|
lfs3_btree_t gbmap;
|
||||||
|
lfs3_btree_init(&gbmap);
|
||||||
|
lfs3_gbmap_commit(&lfs3, &gbmap, 0, LFS3_RATTRS(
|
||||||
|
LFS3_RATTR(2, LFS3_TAG_BMFREE, -2),
|
||||||
|
LFS3_RATTR_WEIGHT(+BLOCK_COUNT),
|
||||||
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
|
// set some blocks as erased with ecksums, avoid any weird merges
|
||||||
|
// for now
|
||||||
|
lfs3_ecksum_t ecksum_a = {.cksize=CFG->prog_size, .cksum=0x12345678};
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 6, LFS3_TAG_BMERASED, &ecksum_a) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 8, LFS3_TAG_BMERASED, &ecksum_a) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 10, LFS3_TAG_BMERASED, &ecksum_a) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 12, LFS3_TAG_BMERASED, &ecksum_a) => 0;
|
||||||
|
// set neighboring blocks as erased with _different_ ecksums, this
|
||||||
|
// should _not_ trigger a merge!
|
||||||
|
lfs3_ecksum_t ecksum_b = {.cksize=CFG->prog_size, .cksum=0x9abcdef0};
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 5, LFS3_TAG_BMERASED, &ecksum_b) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 9, LFS3_TAG_BMERASED, &ecksum_b) => 0;
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap, 13, LFS3_TAG_BMERASED, &ecksum_b) => 0;
|
||||||
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
|
gbmap.r.weight,
|
||||||
|
gbmap.r.blocks[0],
|
||||||
|
gbmap.r.trunk);
|
||||||
|
|
||||||
|
// weight should stay the same
|
||||||
|
assert(gbmap.r.weight == BLOCK_COUNT);
|
||||||
|
|
||||||
|
// check ranges
|
||||||
|
lfs3_bid_t bid_;
|
||||||
|
lfs3_bid_t weight_;
|
||||||
|
lfs3_ecksum_t ecksum_;
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 0,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 4);
|
||||||
|
assert(weight_ == 5);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 5,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 5);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_b) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 6,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 6);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_a) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 7,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 7);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 8,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 8);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_a) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 9,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 9);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_b) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 10,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 10);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_a) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 11,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == 11);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 12,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 12);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_a) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 13,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == 13);
|
||||||
|
assert(weight_ == 1);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, &ecksum_b) == 0);
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, 14,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMFREE;
|
||||||
|
assert(bid_ == BLOCK_COUNT-1);
|
||||||
|
assert(weight_ == BLOCK_COUNT-14);
|
||||||
|
assert(lfs3_ecksum_cmp(&ecksum_, NULL) == 0);
|
||||||
|
|
||||||
|
lfs3_unmount(&lfs3) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_gbmap_mark_ecksum_fuzz]
|
||||||
|
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
|
||||||
|
defines.MASK = [0x1, 0x3, 0xf, 0xffff]
|
||||||
|
defines.SEED = 'range(20)'
|
||||||
|
fuzz = 'SEED'
|
||||||
|
in = 'lfs3.c'
|
||||||
|
code = '''
|
||||||
|
lfs3_t lfs3;
|
||||||
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
||||||
|
lfs3_alloc_ckpoint(&lfs3);
|
||||||
|
|
||||||
|
// create an initial gbmap
|
||||||
|
lfs3_ecksum_t ecksum = {.cksize=CFG->prog_size, .cksum=0x00000000};
|
||||||
|
lfs3_btree_t gbmap;
|
||||||
|
lfs3_btree_init(&gbmap);
|
||||||
|
lfs3_gbmap_commit(&lfs3, &gbmap, 0, LFS3_RATTRS(
|
||||||
|
LFS3_RATTR(3, LFS3_TAG_BMERASED, -2, LFS3_FROM_ECKSUM),
|
||||||
|
LFS3_RATTR_WEIGHT(+BLOCK_COUNT),
|
||||||
|
LFS3_RATTR_ARG(&ecksum),
|
||||||
|
LFS3_RATTR_NULL)) => 0;
|
||||||
|
|
||||||
|
// create a simulation to compare against
|
||||||
|
lfs3_tag_t *sim = malloc(BLOCK_COUNT*sizeof(uint32_t));
|
||||||
|
for (lfs3_size_t i = 0; i < BLOCK_COUNT; i++) {
|
||||||
|
sim[i] = 0x00000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t prng = SEED;
|
||||||
|
for (lfs3_size_t i = 0; i < N; i++) {
|
||||||
|
// choose a pseudo-random block
|
||||||
|
lfs3_block_t block = TEST_PRNG(&prng) % BLOCK_COUNT;
|
||||||
|
// and pseudo-random ecksum
|
||||||
|
ecksum.cksum = TEST_PRNG(&prng) & MASK;
|
||||||
|
|
||||||
|
// set in gbmap
|
||||||
|
lfs3_gbmap_mark(&lfs3, &gbmap,
|
||||||
|
block, LFS3_TAG_BMERASED, &ecksum) => 0;
|
||||||
|
|
||||||
|
// and set in sim
|
||||||
|
sim[block] = ecksum.cksum;
|
||||||
|
}
|
||||||
|
printf("gbmap: w%d 0x%x.%x\n",
|
||||||
|
gbmap.r.weight,
|
||||||
|
gbmap.r.blocks[0],
|
||||||
|
gbmap.r.trunk);
|
||||||
|
|
||||||
|
// check if gbmap matches sim
|
||||||
|
lfs3_size_t i = 0;
|
||||||
|
while (i < BLOCK_COUNT) {
|
||||||
|
// we need to convert our sim's raw blocks to compressed ranges,
|
||||||
|
// in theory our gbmap is optimal
|
||||||
|
uint32_t cksum = sim[i];
|
||||||
|
lfs3_size_t d = 1;
|
||||||
|
while (i+d < BLOCK_COUNT && sim[i+d] == cksum) {
|
||||||
|
d += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// does our gbmap contain the optimal range?
|
||||||
|
lfs3_bid_t bid_;
|
||||||
|
lfs3_bid_t weight_;
|
||||||
|
lfs3_ecksum_t ecksum_;
|
||||||
|
lfs3_gbmap_lookupnext(&lfs3, &gbmap, i,
|
||||||
|
&bid_, &weight_, &ecksum_) => LFS3_TAG_BMERASED;
|
||||||
|
assert(bid_ == i+(weight_-1));
|
||||||
|
assert(weight_ == d);
|
||||||
|
assert(ecksum_.cksize == CFG->prog_size);
|
||||||
|
assert(ecksum_.cksum == cksum);
|
||||||
|
|
||||||
|
i += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sim);
|
||||||
|
lfs3_unmount(&lfs3) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# test high-level gbmap operations
|
# test high-level gbmap operations
|
||||||
|
|
||||||
@@ -499,6 +906,122 @@ code = '''
|
|||||||
lfs3_unmount(&lfs3) => 0;
|
lfs3_unmount(&lfs3) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
# test that the gbmap with gc generally works
|
||||||
|
[cases.test_gbmap_gc_files]
|
||||||
|
defines.COUNT = [
|
||||||
|
'BLOCK_COUNT',
|
||||||
|
'BLOCK_COUNT-1',
|
||||||
|
'BLOCK_COUNT/2',
|
||||||
|
'BLOCK_COUNT/4',
|
||||||
|
'5',
|
||||||
|
'3',
|
||||||
|
]
|
||||||
|
defines.SIZE = [
|
||||||
|
'BLOCK_SIZE',
|
||||||
|
'2*BLOCK_SIZE',
|
||||||
|
'8*BLOCK_SIZE',
|
||||||
|
]
|
||||||
|
defines.N = ['5', 'BLOCK_COUNT/2']
|
||||||
|
defines.WRAPAROUND = 3
|
||||||
|
defines.PREERASE = [false, true]
|
||||||
|
defines.GC_FLAGS = '''
|
||||||
|
LFS3_GC_LOOKAHEAD
|
||||||
|
| ((PREERASE) ? LFS3_GC_PREERASE : 0)
|
||||||
|
'''
|
||||||
|
defines.GC_STEPS = -1
|
||||||
|
defines.GC_PREERASE_COUNT = ['0', '4', 'COUNT/2', 'COUNT-4', '-1']
|
||||||
|
ifdef = 'LFS3_GC'
|
||||||
|
if = [
|
||||||
|
'COUNT >= 3',
|
||||||
|
'COUNT >= 2*N*SIZE/BLOCK_SIZE',
|
||||||
|
'LFS3_IFDEF_PREERASE(true, !PREERASE)',
|
||||||
|
# this is just to reduce useless permutations
|
||||||
|
'PREERASE || GC_PREERASE_COUNT == 0',
|
||||||
|
]
|
||||||
|
code = '''
|
||||||
|
// test various block counts
|
||||||
|
struct lfs3_cfg cfg = *CFG;
|
||||||
|
cfg.block_count = COUNT;
|
||||||
|
lfs3_t lfs3;
|
||||||
|
// note the gbmap flag
|
||||||
|
lfs3_format(&lfs3, LFS3_F_RDWR | LFS3_F_GBMAP, &cfg) => 0;
|
||||||
|
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||||
|
|
||||||
|
// check that we were formatted with the gbmap
|
||||||
|
struct lfs3_fsinfo fsinfo;
|
||||||
|
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||||
|
assert(fsinfo.flags & LFS3_I_GBMAP);
|
||||||
|
|
||||||
|
// run gc to prebuild gbmap, preerase blocks, etc
|
||||||
|
lfs3_fs_gc(&lfs3) => 0;
|
||||||
|
|
||||||
|
// create n files repeatedly until we're sure we've wrapped around
|
||||||
|
// a few times
|
||||||
|
uint32_t prng = 42;
|
||||||
|
uint32_t prng_ = prng;
|
||||||
|
for (lfs3_size_t i = 0;
|
||||||
|
i < (WRAPAROUND*COUNT)
|
||||||
|
/ (N*(SIZE/BLOCK_SIZE));
|
||||||
|
i++) {
|
||||||
|
prng = prng_;
|
||||||
|
for (lfs3_size_t n = 0; n < N; n++) {
|
||||||
|
char name[256];
|
||||||
|
sprintf(name, "file%08d", n);
|
||||||
|
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs3_file_t file;
|
||||||
|
lfs3_file_open(&lfs3, &file, name,
|
||||||
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||||
|
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||||
|
lfs3_file_close(&lfs3, &file) => 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int remount = 0; remount < 2; remount++) {
|
||||||
|
// remount?
|
||||||
|
if (remount) {
|
||||||
|
lfs3_unmount(&lfs3) => 0;
|
||||||
|
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that our file writes worked
|
||||||
|
prng_ = prng;
|
||||||
|
for (lfs3_size_t i = 0; i < N; i++) {
|
||||||
|
// check with stat
|
||||||
|
char name[256];
|
||||||
|
sprintf(name, "file%08d", i);
|
||||||
|
struct lfs3_info info;
|
||||||
|
lfs3_stat(&lfs3, name, &info) => 0;
|
||||||
|
assert(strcmp(info.name, name) == 0);
|
||||||
|
assert(info.type == LFS3_TYPE_REG);
|
||||||
|
assert(info.size == SIZE);
|
||||||
|
|
||||||
|
// try reading the file, note we reset prng above
|
||||||
|
uint8_t wbuf[SIZE];
|
||||||
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||||
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs3_file_t file;
|
||||||
|
uint8_t rbuf[SIZE];
|
||||||
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
||||||
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
||||||
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||||
|
lfs3_file_close(&lfs3, &file) => 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs3_unmount(&lfs3) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# test high-high-level gbmap operations
|
||||||
|
|
||||||
# test that we can remove the gbmap and things still work
|
# test that we can remove the gbmap and things still work
|
||||||
[cases.test_gbmap_rmgbmap]
|
[cases.test_gbmap_rmgbmap]
|
||||||
ifndef = 'LFS3_YES_GBMAP'
|
ifndef = 'LFS3_YES_GBMAP'
|
||||||
|
|||||||
Reference in New Issue
Block a user