Different rbyd struct usage in commit, moved append into its own function

Under any optimization level the compiler should inline lfs_rbyd_append
into lfs_rbyd_commit, but this code organization was desperately needed.
This commit is contained in:
Christopher Haster
2022-12-29 13:09:21 -06:00
parent 12edc5aee3
commit cde3ba4cd8
+148 -189
View File
@@ -969,6 +969,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
/// Red-black-yellow Dhara tree operations /// /// Red-black-yellow Dhara tree operations ///
// TODO actually should this be an lfs_bd_ operation?
static lfs_ssize_t lfs_rbyd_readtag(lfs_t *lfs, static lfs_ssize_t lfs_rbyd_readtag(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off, lfs_block_t block, lfs_off_t off,
@@ -1052,16 +1053,18 @@ static int lfs_rbyd_fetch(lfs_t *lfs,
// calculate crc before endian conversion // calculate crc before endian conversion
uint32_t crc = lfs_crc32c(0, &rev, sizeof(uint32_t)); uint32_t crc = lfs_crc32c(0, &rev, sizeof(uint32_t));
rev = lfs_fromle32_(&rev);
rbyd->block = block;
rbyd->off = 0;
rbyd->rev = rev;
// temporary state until we validate a crc
lfs_off_t off = sizeof(uint32_t); lfs_off_t off = sizeof(uint32_t);
lfs_off_t trunk = 0; lfs_off_t trunk = 0;
bool wastrunk = false; bool wastrunk = false;
uint16_t count = 0; uint16_t count = 0;
rbyd->block = block;
rbyd->rev = lfs_fromle32_(&rev);
rbyd->trunk = 0;
rbyd->off = 0;
// assume unerased until proven otherwise // assume unerased until proven otherwise
bool maybeerased = false; bool maybeerased = false;
bool hasfcrc = false; bool hasfcrc = false;
@@ -1297,24 +1300,27 @@ static lfs_ssize_t lfs_rbyd_get(lfs_t *lfs, const lfs_rbyd_t *rbyd,
return found_size; return found_size;
} }
static int lfs_rbyd_prog(lfs_t *lfs, static int lfs_rbyd_prog(lfs_t *lfs, lfs_rbyd_t *rbyd_,
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_block_t block, lfs_off_t off,
const void *buffer, lfs_size_t size, uint32_t *crc) { const void *buffer, lfs_size_t size, uint32_t *crc) {
// check for out-of-bounds here // check for out-of-bounds here
// TODO should we just move this to lfs_bd_prog? // TODO should we just move this to lfs_bd_prog?
// TODO actually should we just build crc into lfs_bd_prog as well? // TODO actually should we just build crc into lfs_bd_prog as well?
if (off+size > lfs->cfg->block_size) { if (rbyd_->off+size > lfs->cfg->block_size) {
return LFS_ERR_RANGE; return LFS_ERR_RANGE;
} }
int err = lfs_bd_prog(lfs, int err = lfs_bd_prog(lfs,
pcache, rcache, false, &lfs->pcache, &lfs->rcache, false,
block, off, buffer, size); rbyd_->block, rbyd_->off, buffer, size);
if (err) { if (err) {
return err; return err;
} }
// update off
rbyd_->off += size;
// TODO should this not be optional? should we move the range check
// into bd_prog? so we can get rid of the one use of this in
// lfs_rbyd_commit?
// optionally crc // optionally crc
if (crc) { if (crc) {
*crc = lfs_crc32c(*crc, buffer, size); *crc = lfs_crc32c(*crc, buffer, size);
@@ -1323,86 +1329,67 @@ static int lfs_rbyd_prog(lfs_t *lfs,
return 0; return 0;
} }
static lfs_ssize_t lfs_rbyd_progtag(lfs_t *lfs, static int lfs_rbyd_progtag(lfs_t *lfs, lfs_rbyd_t *rbyd_,
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_block_t block, lfs_off_t off,
lfs_rtag_t tag, lfs_size_t size, uint32_t *crc) { lfs_rtag_t tag, lfs_size_t size, uint32_t *crc) {
// convert to on-disk repr // convert to on-disk repr
tag <<= 1; tag <<= 1;
// make sure to include the parity of the current crc // make sure to include the parity of the current crc
tag |= lfs_popc(*crc) & 1; tag |= lfs_popc(rbyd_->crc) & 1;
// compress into pair of leb128s // compress into pair of leb128s
uint8_t buffer[2*4]; uint8_t buffer[2*4];
lfs_size_t i = 0; lfs_size_t delta = 0;
ssize_t delta = lfs_toleb128(tag, &buffer[i], 4); ssize_t delta_ = lfs_toleb128(tag, &buffer[delta], 4);
if (delta < 0) { if (delta_ < 0) {
return delta; return delta_;
} }
i += delta; delta += delta_;
delta = lfs_toleb128(size, &buffer[i], 4); delta_ = lfs_toleb128(size, &buffer[delta], 4);
if (delta < 0) { if (delta_ < 0) {
return delta; return delta_;
} }
i += delta; delta += delta_;
int err = lfs_rbyd_prog(lfs, int err = lfs_rbyd_prog(lfs, rbyd_, &buffer, delta, crc);
pcache, rcache,
block, off, &buffer, i, crc);
if (err) { if (err) {
return err; return err;
} }
return i; return 0;
} }
static lfs_ssize_t lfs_rbyd_p_flush(lfs_t *lfs, static int lfs_rbyd_p_flush(lfs_t *lfs, lfs_rbyd_t *rbyd_,
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_block_t block, lfs_off_t off,
lfs_rtag_t p_alts[static 3], lfs_rtag_t p_alts[static 3],
lfs_rtag_t p_jumps[static 3], lfs_rtag_t p_jumps[static 3],
unsigned count, unsigned count) {
uint32_t *crc) {
lfs_off_t off_ = off;
// write out some number of alt pointers in our queue // write out some number of alt pointers in our queue
for (unsigned i = 0; i < count; i++) { for (unsigned i = 0; i < count; i++) {
if (p_alts[3-1-i]) { if (p_alts[3-1-i]) {
// change to a relative jump at the last minute // change to a relative jump at the last minute
lfs_rtag_t alt = p_alts[3-1-i]; lfs_rtag_t alt = p_alts[3-1-i];
lfs_off_t jump = off_ - p_jumps[3-1-i]; lfs_off_t jump = rbyd_->off - p_jumps[3-1-i];
printf("%x: writing %08x %08x\n", off_, alt, jump); printf("%x: writing %08x %08x\n", rbyd_->off, alt, jump);
lfs_ssize_t delta = lfs_rbyd_progtag(lfs, int err = lfs_rbyd_progtag(lfs, rbyd_, alt, jump, &rbyd_->crc);
pcache, rcache, if (err) {
block, off_, return err;
alt, jump, crc);
if (delta < 0) {
return delta;
} }
off_ += delta;
} }
} }
return off_ - off; return 0;
} }
static inline lfs_ssize_t lfs_rbyd_p_push(lfs_t *lfs, static inline int lfs_rbyd_p_push(lfs_t *lfs, lfs_rbyd_t *rbyd_,
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_block_t block, lfs_off_t off,
lfs_rtag_t p_alts[static 3], lfs_rtag_t p_alts[static 3],
lfs_off_t p_jumps[static 3], lfs_off_t p_jumps[static 3],
lfs_rtag_t alt, lfs_off_t jump, lfs_rtag_t alt, lfs_off_t jump) {
uint32_t *crc) { int err = lfs_rbyd_p_flush(lfs, rbyd_, p_alts, p_jumps, 1);
lfs_ssize_t delta = lfs_rbyd_p_flush(lfs, if (err) {
pcache, rcache, return err;
block, off,
p_alts, p_jumps, 1, crc);
if (delta < 0) {
return delta;
} }
p_alts[2] = p_alts[1]; p_alts[2] = p_alts[1];
@@ -1412,7 +1399,7 @@ static inline lfs_ssize_t lfs_rbyd_p_push(lfs_t *lfs,
p_alts[0] = alt; p_alts[0] = alt;
p_jumps[0] = jump; p_jumps[0] = jump;
return delta; return 0;
} }
static inline void lfs_rbyd_p_pop( static inline void lfs_rbyd_p_pop(
@@ -1462,44 +1449,14 @@ static void lfs_rbyd_p_red(
} }
} }
static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, static int lfs_rbyd_append(lfs_t *lfs, lfs_rbyd_t *rbyd_,
const struct lfs_rattr *attrs) { lfs_rtag_t tag, const void *buffer, lfs_size_t size) {
printf("commit()\n");
LFS_ASSERT(rbyd->erased);
// setup commit state
const lfs_block_t block = rbyd->block;
lfs_off_t trunk = rbyd->trunk;
lfs_off_t off = rbyd->off;
uint32_t crc = rbyd->crc;
uint16_t count = rbyd->count;
bool erased = false;
// mark as unerased in case we fail
rbyd->erased = false;
// include revision count?
if (!off) {
uint32_t rev;
lfs_tole32_(rbyd->rev, &rev);
int err = lfs_rbyd_prog(lfs,
&lfs->pcache, &lfs->rcache,
block, off, &rev, sizeof(uint32_t), &crc);
if (err) {
return err;
}
off += sizeof(uint32_t);
}
// append each tag to the tree
for (const struct lfs_rattr *attr = attrs; attr; attr = attr->next) {
printf("append()\n"); printf("append()\n");
LFS_ASSERT(lfs_rtag_id(attr->tag) <= count+1); LFS_ASSERT(lfs_rtag_id(tag) <= rbyd_->count+1);
// assume we'll update our trunk // assume we'll update our trunk
lfs_off_t branch = trunk; lfs_off_t branch = rbyd_->trunk;
trunk = off; rbyd_->trunk = rbyd_->off;
// no trunk yet? // no trunk yet?
if (!branch) { if (!branch) {
@@ -1509,7 +1466,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// weights for pruning // weights for pruning
lfs_srtag_t lt; lfs_srtag_t lt;
lfs_srtag_t gt; lfs_srtag_t gt;
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) { if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) {
// inserting a new id? align down // inserting a new id? align down
// TODO special function for this? // TODO special function for this?
// if (lfs_rtag_id(attr->tag) == count+1) { // if (lfs_rtag_id(attr->tag) == count+1) {
@@ -1519,11 +1476,11 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1); // lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1);
// gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1); // gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1);
// } // }
lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1); lt = lfs_rtag_weight_lt(tag & ~0x7fff, rbyd_->count+1);
gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1) + 1; gt = lfs_rtag_weight_gt(tag & ~0x7fff, rbyd_->count+1) + 1;
} else { } else {
lt = lfs_rtag_weight_lt(attr->tag, count+1); lt = lfs_rtag_weight_lt(tag, rbyd_->count+1);
gt = lfs_rtag_weight_gt(attr->tag, count+1); gt = lfs_rtag_weight_gt(tag, rbyd_->count+1);
} }
printf("lt, gt = (%x, %x)\n", lt, gt); printf("lt, gt = (%x, %x)\n", lt, gt);
@@ -1531,7 +1488,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// queue of pending alts we can emulate rotations with // queue of pending alts we can emulate rotations with
lfs_rtag_t p_alts[3] = {0, 0, 0}; lfs_rtag_t p_alts[3] = {0, 0, 0};
lfs_off_t p_jumps[3] = {0, 0, 0}; lfs_off_t p_jumps[3] = {0, 0, 0};
lfs_off_t xylem = 0; lfs_off_t graft = 0;
// descend down tree, building alt pointers // descend down tree, building alt pointers
while (true) { while (true) {
@@ -1539,7 +1496,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
lfs_off_t jump; lfs_off_t jump;
lfs_ssize_t delta = lfs_rbyd_readtag(lfs, lfs_ssize_t delta = lfs_rbyd_readtag(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size, &lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
block, branch, &alt, &jump, NULL); rbyd_->block, branch, &alt, &jump, NULL);
if (delta < 0) { if (delta < 0) {
return delta; return delta;
} }
@@ -1591,12 +1548,12 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
printf("ysplit nofollow\n"); printf("ysplit nofollow\n");
p_alts[0] = lfs_rtag_black( p_alts[0] = lfs_rtag_black(
lfs_rtag_merge(alt, p_alts[0])); lfs_rtag_merge(alt, p_alts[0]));
p_jumps[0] = xylem; p_jumps[0] = graft;
lfs_rtag_trim(alt, &lt, &gt); lfs_rtag_trim(alt, &lt, &gt);
lfs_rbyd_p_red(p_alts, p_jumps); lfs_rbyd_p_red(p_alts, p_jumps);
xylem = branch; graft = branch;
branch = branch_; branch = branch_;
continue; continue;
} }
@@ -1641,19 +1598,16 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
} }
// push alt onto queue // push alt onto queue
lfs_ssize_t delta = lfs_rbyd_p_push(lfs, int err = lfs_rbyd_p_push(lfs, rbyd_,
&lfs->pcache, &lfs->rcache,
block, off,
p_alts, p_jumps, p_alts, p_jumps,
alt, jump, &crc); alt, jump);
if (delta < 0) { if (err) {
return delta; return err;
} }
off += delta;
// continue to next alt // continue to next alt
lfs_rtag_trim(alt, &lt, &gt); lfs_rtag_trim(alt, &lt, &gt);
xylem = branch; graft = branch;
branch = branch_; branch = branch_;
// found end of tree? // found end of tree?
@@ -1663,9 +1617,9 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// TODO alternatively can we do this a bit more directly here // TODO alternatively can we do this a bit more directly here
// lfs_rtag_t tag_ = lfs_rtag_setid(alt, // lfs_rtag_t tag_ = lfs_rtag_setid(alt,
// lfs_min(lfs_rtag_id(attr->tag), count)); // lfs_min(lfs_rtag_id(attr->tag), count));
lfs_rtag_t tag_ = lfs_rtag_setid(alt, lfs_rtag_id(attr->tag)); lfs_rtag_t tag_ = lfs_rtag_setid(alt, lfs_rtag_id(tag));
// TODO I don't really know why this works // TODO I don't really know why this works
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE && gt == 0) { if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE && gt == 0) {
tag_ = lfs_rtag_decid(tag_); tag_ = lfs_rtag_decid(tag_);
} }
//gt == 0 ? lfs_rtag_id(attr->tag)-1 : lfs_rtag_id(attr->tag)); //gt == 0 ? lfs_rtag_id(attr->tag)-1 : lfs_rtag_id(attr->tag));
@@ -1673,14 +1627,14 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// split leaf? // split leaf?
// TODO we might be able to rearrange this a bit better // TODO we might be able to rearrange this a bit better
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE
|| tag_ != attr->tag) { || tag_ != tag) {
// inserting a new id? // inserting a new id?
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) { if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) {
// bias the weights so that lookups always find the // bias the weights so that lookups always find the
// next biggest tag // next biggest tag
if (lfs_rtag_weight(tag_) if (lfs_rtag_weight(tag_)
< lfs_rtag_weight(attr->tag & ~0x7fff)) { < lfs_rtag_weight(tag & ~0x7fff)) {
printf("lt insert\n"); printf("lt insert\n");
// //
// lt gt // lt gt
@@ -1691,12 +1645,12 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// a old new d e // a old new d e
// //
alt = LFS_MKRALT(B, LT, lt alt = LFS_MKRALT(B, LT, lt
- (lfs_rtag_weight(attr->tag & ~0x7fff)-1 - (lfs_rtag_weight(tag & ~0x7fff)-1
- lfs_rtag_weight(tag_)) - lfs_rtag_weight(tag_))
+ 1); + 1);
} else { } else {
printf("gt insert\n"); printf("gt insert\n");
printf("hmmm? %08x %08x\n", lfs_rtag_weight(tag_), lfs_rtag_weight(attr->tag & ~0x7fff)); printf("hmmm? %08x %08x\n", lfs_rtag_weight(tag_), lfs_rtag_weight(tag & ~0x7fff));
// //
// lt gt // lt gt
// .-----'--. .-'. // .-----'--. .-'.
@@ -1708,13 +1662,13 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
alt = LFS_MKRALT(B, GT, alt = LFS_MKRALT(B, GT,
// TODO hm, can this be done differently? // TODO hm, can this be done differently?
lfs_rtag_weight(lfs_rtag_incid(tag_)) lfs_rtag_weight(lfs_rtag_incid(tag_))
- lfs_rtag_weight(attr->tag)); - lfs_rtag_weight(tag));
} }
} else { } else {
// bias the weights so that lookups always find the // bias the weights so that lookups always find the
// next biggest tag // next biggest tag
if (lfs_rtag_weight(tag_) if (lfs_rtag_weight(tag_)
< lfs_rtag_weight(attr->tag)) { < lfs_rtag_weight(tag)) {
// //
// lt gt // lt gt
// .-----'-----. .--'--. // .-----'-----. .--'--.
@@ -1725,7 +1679,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// //
alt = LFS_MKRALT(B, LT, lt alt = LFS_MKRALT(B, LT, lt
+ 1 + 1
- (lfs_rtag_weight(attr->tag) - (lfs_rtag_weight(tag)
- lfs_rtag_weight(tag_))); - lfs_rtag_weight(tag_)));
} else { } else {
// //
@@ -1740,28 +1694,22 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
} }
} }
lfs_ssize_t delta = lfs_rbyd_p_push(lfs, int err = lfs_rbyd_p_push(lfs, rbyd_,
&lfs->pcache, &lfs->rcache,
block, off,
p_alts, p_jumps, p_alts, p_jumps,
alt, branch, &crc); alt, branch);
if (delta < 0) { if (err) {
return delta; return err;
} }
off += delta;
lfs_rbyd_p_red(p_alts, p_jumps); lfs_rbyd_p_red(p_alts, p_jumps);
} }
// flush any pending alts // flush any pending alts
delta = lfs_rbyd_p_flush(lfs, int err = lfs_rbyd_p_flush(lfs, rbyd_,
&lfs->pcache, &lfs->rcache, p_alts, p_jumps, 3);
block, off, if (err) {
p_alts, p_jumps, 3, &crc); return err;
if (delta < 0) {
return delta;
} }
off += delta;
// done! lets get out of here // done! lets get out of here
goto leaf; goto leaf;
@@ -1770,35 +1718,58 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
leaf:; leaf:;
// write the tag // write the tag
lfs_ssize_t delta = lfs_rbyd_progtag(lfs, int err = lfs_rbyd_progtag(lfs, rbyd_, tag, size, &rbyd_->crc);
&lfs->pcache, &lfs->rcache, if (err) {
block, off, return err;
attr->tag, attr->size, &crc); }
if (delta < 0) {
return delta; // don't forget the actual data!
} err = lfs_rbyd_prog(lfs, rbyd_, buffer, size, &rbyd_->crc);
off += delta;
// don't forget the actual data!
int err = lfs_rbyd_prog(lfs,
&lfs->pcache, &lfs->rcache,
block, off,
attr->buffer, attr->size, &crc);
if (err) { if (err) {
return err; return err;
} }
off += attr->size;
// if we're inserting, increase the id count, indirectly shifting // if we're inserting, increase the id count, indirectly shifting
// all ids >= over one // all ids >= over one
// //
// note we do this here since it is possible to insert into an // note we do this here since it is possible to insert into an
// empty tree // empty tree
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) { if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) {
count += 1; rbyd_->count += 1;
} }
continue; return 0;
}
static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
const struct lfs_rattr *attrs) {
printf("commit()\n");
LFS_ASSERT(rbyd->erased);
// mark as unerased in case we fail
rbyd->erased = false;
// setup commit state
lfs_rbyd_t rbyd_ = *rbyd;
// include revision count?
if (!rbyd_.off) {
uint32_t rev;
lfs_tole32_(rbyd_.rev, &rev);
int err = lfs_rbyd_prog(lfs, &rbyd_,
&rev, sizeof(uint32_t), &rbyd_.crc);
if (err) {
return err;
}
}
// append each tag to the tree
for (const struct lfs_rattr *attr = attrs; attr; attr = attr->next) {
int err = lfs_rbyd_append(lfs, &rbyd_,
attr->tag, attr->buffer, attr->size);
if (err) {
return err;
}
} }
// align to the next prog unit // align to the next prog unit
@@ -1820,7 +1791,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// = 9 bytes // = 9 bytes
// //
const lfs_off_t aligned = lfs_alignup( const lfs_off_t aligned = lfs_alignup(
off + 1+1+4+4 + 1+4+4, rbyd_.off + 1+1+4+4 + 1+4+4,
lfs->cfg->prog_size); lfs->cfg->prog_size);
// space for fcrc? // space for fcrc?
@@ -1830,7 +1801,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// value of the next tag's valid bit // value of the next tag's valid bit
int err = lfs_bd_read(lfs, int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->prog_size, &lfs->pcache, &lfs->rcache, lfs->cfg->prog_size,
block, aligned, &perturb, 1); rbyd_.block, aligned, &perturb, 1);
if (err && err != LFS_ERR_CORRUPT) { if (err && err != LFS_ERR_CORRUPT) {
return err; return err;
} }
@@ -1840,31 +1811,25 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
struct lfs_rfcrc fcrc = {.crc=0, .size=lfs->cfg->prog_size}; struct lfs_rfcrc fcrc = {.crc=0, .size=lfs->cfg->prog_size};
err = lfs_bd_crc32c(lfs, err = lfs_bd_crc32c(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->prog_size, &lfs->pcache, &lfs->rcache, lfs->cfg->prog_size,
block, aligned, fcrc.size, &fcrc.crc); rbyd_.block, aligned, fcrc.size, &fcrc.crc);
if (err && err != LFS_ERR_CORRUPT) { if (err && err != LFS_ERR_CORRUPT) {
return err; return err;
} }
lfs_size_t fcrc_delta = lfs_rfcrc_todisk(&fcrc); lfs_size_t fcrc_delta = lfs_rfcrc_todisk(&fcrc);
lfs_ssize_t delta = lfs_rbyd_progtag(lfs, err = lfs_rbyd_progtag(lfs, &rbyd_,
&lfs->pcache, &lfs->rcache, LFS_MKRTAG(FCRC, 0, 0), fcrc_delta, &rbyd_.crc);
block, off,
LFS_MKRTAG(FCRC, 0, 0), fcrc_delta, &crc);
if (delta < 0) {
return delta;
}
off += delta;
err = lfs_rbyd_prog(lfs,
&lfs->pcache, &lfs->rcache,
block, off,
&fcrc, fcrc_delta, &crc);
if (err) { if (err) {
return err; return err;
} }
off += fcrc_delta;
erased = true; err = lfs_rbyd_prog(lfs, &rbyd_,
&fcrc, fcrc_delta, &rbyd_.crc);
if (err) {
return err;
}
rbyd_.erased = true;
} }
// build end-of-commit crc // build end-of-commit crc
@@ -1873,32 +1838,29 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// get around this catch-22 we just always write a fully-expanded leb128 // get around this catch-22 we just always write a fully-expanded leb128
// encoding // encoding
uint8_t buffer[1+4+4]; uint8_t buffer[1+4+4];
buffer[0] = (LFS_MKRTAG(CRC, 0, 0) << 1) | (lfs_popc(crc) & 1); buffer[0] = (LFS_MKRTAG(CRC, 0, 0) << 1) | (lfs_popc(rbyd_.crc) & 1);
lfs_off_t padding = aligned - (off + 1+4); lfs_off_t padding = aligned - (rbyd_.off + 1+4);
buffer[1] = 0x80 | (0x7f & (padding >> 0)); buffer[1] = 0x80 | (0x7f & (padding >> 0));
buffer[2] = 0x80 | (0x7f & (padding >> 7)); buffer[2] = 0x80 | (0x7f & (padding >> 7));
buffer[3] = 0x80 | (0x7f & (padding >> 14)); buffer[3] = 0x80 | (0x7f & (padding >> 14));
buffer[4] = 0x00 | (0x7f & (padding >> 21)); buffer[4] = 0x00 | (0x7f & (padding >> 21));
crc = lfs_crc32c(crc, buffer, 1+4); rbyd_.crc = lfs_crc32c(rbyd_.crc, buffer, 1+4);
// we can't let the next tag appear as valid, so intentionally perturb the // we can't let the next tag appear as valid, so intentionally perturb the
// commit if this happens, note parity(crc(m)) == parity(m) with crc32c, // commit if this happens, note parity(crc(m)) == parity(m) with crc32c,
// so we can really change any bit to make this happen, we've reserved a bit // so we can really change any bit to make this happen, we've reserved a bit
// in crc tags just for this purpose // in crc tags just for this purpose
if ((lfs_popc(crc) & 1) == (perturb & 1)) { if ((lfs_popc(rbyd_.crc) & 1) == (perturb & 1)) {
buffer[0] ^= 0x2; buffer[0] ^= 0x2;
crc ^= 0x7022df58; // note crc(a ^ b) == crc(a) ^ crc(b) rbyd_.crc ^= 0x7022df58; // note crc(a ^ b) == crc(a) ^ crc(b)
} }
lfs_tole32_(crc, &buffer[1+4]); lfs_tole32_(rbyd_.crc, &buffer[1+4]);
int err = lfs_rbyd_prog(lfs, int err = lfs_rbyd_prog(lfs, &rbyd_, buffer, 1+4+4, NULL);
&lfs->pcache, &lfs->rcache,
block, off, buffer, 1+4+4, NULL);
if (err) { if (err) {
return err; return err;
} }
off += 1+4+4;
// flush our caches, finalizing the commit on-disk // flush our caches, finalizing the commit on-disk
err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false);
@@ -1909,24 +1871,21 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
// succesful commit, check checksum to make sure // succesful commit, check checksum to make sure
uint32_t crc_ = rbyd->crc; uint32_t crc_ = rbyd->crc;
err = lfs_bd_crc32c(lfs, err = lfs_bd_crc32c(lfs,
NULL, &lfs->rcache, off-4, NULL, &lfs->rcache, rbyd_.off-4,
block, rbyd->off, off-4 - rbyd->off, &crc_); rbyd_.block, rbyd->off, rbyd_.off-4 - rbyd->off, &crc_);
if (err) { if (err) {
return err; return err;
} }
if (crc_ != crc) { if (crc_ != rbyd_.crc) {
// oh no, something went wrong // oh no, something went wrong
printf("oh no %08x != %08x\n", crc_, crc); printf("oh no %08x != %08x\n", crc_, rbyd_.crc);
return LFS_ERR_CORRUPT; return LFS_ERR_CORRUPT;
} }
// ok, everything is good, save what we've committed // ok, everything is good, save what we've committed
rbyd->trunk = trunk; rbyd_.off = aligned;
rbyd->off = aligned; *rbyd = rbyd_;
rbyd->crc = crc;
rbyd->count = count;
rbyd->erased = erased;
return 0; return 0;
} }