Adopted lfsr_data_t in low-level rbyd functions

The low-level rbyd functions need to parse things (mostly tags), so why
not use our parsers? In theory this offers a bit more code reuse.

In theory we can also rely on lfsr_data_t to do bounds checking of
offsets in the block, in practice we need to setup those bounds
correctly for lfsr_data_t, so not so much...

Code/stack cost:

            code          stack
  before:  21702           1992
  after:   21626 (-0.4%)   2024 (+1.6%)
This commit is contained in:
Christopher Haster
2023-08-09 19:16:29 -05:00
parent 1d39c5dd68
commit 7614cf29c1
+162 -169
View File
@@ -908,116 +908,6 @@ static inline void lfsr_tag_trim2(
lower_tag, upper_tag); lower_tag, upper_tag);
} }
// support for encoding/decoding tags on disk
// each piece of metadata in an rbyd tree is prefixed with a 4-piece tag:
//
// - 8-bit suptype => 1 byte
// - 8-bit subtype => 1 byte
// - 32-bit rid/weight => 5 byte leb128 (worst case)
// - 32-bit size/jump => 5 byte leb128 (worst case)
// => 12 bytes total
//
#define LFSR_TAG_DSIZE (2+5+5)
static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs,
lfs_block_t block, lfs_off_t off, lfs_size_t hint,
lfsr_tag_t *tag_, lfs_size_t *weight_, lfs_size_t *size_,
uint32_t *cksum_) {
// read the largest possible tag size
uint8_t tag_buf[LFSR_TAG_DSIZE];
lfs_size_t tag_dsize = lfs_min32(LFSR_TAG_DSIZE, lfs->cfg->block_size-off);
int err = lfsr_bd_read(lfs, block, off, hint, &tag_buf, tag_dsize);
if (err) {
return err;
}
if (tag_dsize < 2) {
return LFS_ERR_CORRUPT;
}
uint16_t tag
= ((lfsr_tag_t)tag_buf[0] << 8)
| ((lfsr_tag_t)tag_buf[1] << 0);
ssize_t d = 2;
if (cksum_) {
// on-disk, the tags valid bit must reflect the parity of the
// preceding data, fortunately for crc32c, this is the same as the
// parity of the crc
//
// note we need to do this before leb128 decoding as we may not have
// valid leb128 if we're erased, but we shouldn't treat a truncated
// leb128 here as corruption
if ((tag >> 15) != (lfs_popc(*cksum_) & 1)) {
return LFS_ERR_INVAL;
}
}
lfs_ssize_t weight;
lfs_ssize_t d_ = lfs_fromleb128(&weight, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
lfs_ssize_t size;
d_ = lfs_fromleb128(&size, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
// optional checksum
if (cksum_) {
*cksum_ = lfs_crc32c(*cksum_, tag_buf, d);
}
// save what we found, clearing the valid bit from the tag, note we
// checked this earlier
*tag_ = tag & 0x7fff;
*weight_ = weight;
*size_ = size;
return d;
}
static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
lfs_block_t block, lfs_off_t off,
lfsr_tag_t tag, lfs_size_t weight, lfs_size_t size,
uint32_t *cksum_) {
// check for underflow issues
LFS_ASSERT(weight < 0x80000000);
LFS_ASSERT(size < 0x80000000);
// make sure to include the parity of the current crc
tag |= (lfs_popc(*cksum_) & 1) << 15;
// encode into a be16 and pair of leb128s
uint8_t tag_buf[LFSR_TAG_DSIZE];
tag_buf[0] = (uint8_t)(tag >> 8);
tag_buf[1] = (uint8_t)(tag >> 0);
lfs_size_t d = 2;
ssize_t d_ = lfs_toleb128(weight, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
d_ = lfs_toleb128(size, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
int err = lfsr_bd_prog(lfs, block, off, &tag_buf, d, cksum_);
if (err) {
return err;
}
return d;
}
/// lfsr_data_t stuff /// /// lfsr_data_t stuff ///
@@ -1310,6 +1200,121 @@ static int lfsr_bd_progdata(lfs_t *lfs,
} }
// support for encoding/decoding tags on disk
// each piece of metadata in an rbyd tree is prefixed with a 4-piece tag:
//
// - 8-bit suptype => 1 byte
// - 8-bit subtype => 1 byte
// - 32-bit rid/weight => 5 byte leb128 (worst case)
// - 32-bit size/jump => 5 byte leb128 (worst case)
// => 12 bytes total
//
#define LFSR_TAG_DSIZE (2+5+5)
static int lfsr_data_readtag(lfs_t *lfs, lfsr_data_t *data,
lfsr_tag_t *tag_, lfs_size_t *weight_, lfs_size_t *size_,
uint32_t *cksum_) {
// note we make sure not to update our data offset until after decoding
lfsr_data_t data_ = *data;
// read the largest possible tag size
uint8_t tag_buf[LFSR_TAG_DSIZE];
lfs_ssize_t tag_dsize = lfsr_data_read(lfs, &data_,
tag_buf, LFSR_TAG_DSIZE);
if (tag_dsize < 0) {
return tag_dsize;
}
if (tag_dsize < 2) {
return LFS_ERR_CORRUPT;
}
uint16_t tag
= ((lfsr_tag_t)tag_buf[0] << 8)
| ((lfsr_tag_t)tag_buf[1] << 0);
ssize_t d = 2;
if (cksum_) {
// on-disk, the tags valid bit must reflect the parity of the
// preceding data, fortunately for crc32c, this is the same as the
// parity of the crc
//
// note we need to do this before leb128 decoding as we may not have
// valid leb128 if we're erased, but we shouldn't treat a truncated
// leb128 here as corruption
if ((tag >> 15) != (lfs_popc(*cksum_) & 1)) {
return LFS_ERR_INVAL;
}
}
lfs_ssize_t weight;
lfs_ssize_t d_ = lfs_fromleb128(&weight, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
lfs_ssize_t size;
d_ = lfs_fromleb128(&size, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
// optional checksum
if (cksum_) {
*cksum_ = lfs_crc32c(*cksum_, tag_buf, d);
}
// save what we found, clearing the valid bit from the tag, note we
// checked this earlier
lfsr_data_add(data, d);
*tag_ = tag & 0x7fff;
*weight_ = weight;
*size_ = size;
return 0;
}
static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
lfs_block_t block, lfs_off_t off,
lfsr_tag_t tag, lfs_size_t weight, lfs_size_t size,
uint32_t *cksum_) {
// check for underflow issues
LFS_ASSERT(weight < 0x80000000);
LFS_ASSERT(size < 0x80000000);
// make sure to include the parity of the current crc
tag |= (lfs_popc(*cksum_) & 1) << 15;
// encode into a be16 and pair of leb128s
uint8_t tag_buf[LFSR_TAG_DSIZE];
tag_buf[0] = (uint8_t)(tag >> 8);
tag_buf[1] = (uint8_t)(tag >> 0);
lfs_size_t d = 2;
ssize_t d_ = lfs_toleb128(weight, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
d_ = lfs_toleb128(size, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
int err = lfsr_bd_prog(lfs, block, off, &tag_buf, d, cksum_);
if (err) {
return err;
}
return d;
}
// operations on attribute lists // operations on attribute lists
//struct lfs_mattr { //struct lfs_mattr {
@@ -1833,7 +1838,8 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
rbyd->trunk = 0; rbyd->trunk = 0;
// temporary state until we validate a cksum // temporary state until we validate a cksum
lfs_off_t off = sizeof(uint32_t); lfsr_data_t data = LFSR_DATA_DISK(block, sizeof(uint32_t),
lfs->cfg->block_size - sizeof(uint32_t));
lfs_off_t trunk_ = 0; lfs_off_t trunk_ = 0;
bool wastrunk = false; bool wastrunk = false;
lfs_size_t weight = 0; lfs_size_t weight = 0;
@@ -1845,31 +1851,32 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
bool maybeerased = false; bool maybeerased = false;
// scan tags, checking valid bits, cksums, etc // scan tags, checking valid bits, cksums, etc
while (off < lfs->cfg->block_size && (!trunk || rbyd->eoff <= trunk)) { while (lfsr_data_size(&data) > 0 && (!trunk || rbyd->eoff <= trunk)) {
lfsr_tag_t tag; lfsr_tag_t tag;
lfs_size_t weight__; lfs_size_t weight__;
lfs_size_t size; lfs_size_t size;
lfs_ssize_t d = lfsr_bd_readtag(lfs, lfsr_data_t data_ = data;
block, off, lfs->cfg->block_size, err = lfsr_data_readtag(lfs, &data_,
&tag, &weight__, &size, &cksum); &tag, &weight__, &size, &cksum);
if (d < 0) { if (err) {
if (d == LFS_ERR_INVAL || d == LFS_ERR_CORRUPT) { if (err == LFS_ERR_INVAL || err == LFS_ERR_CORRUPT) {
maybeerased = maybeerased && d == LFS_ERR_INVAL; maybeerased = maybeerased && err == LFS_ERR_INVAL;
break; break;
} }
return d; return err;
} }
off += d;
// tag goes out of range? // tag goes out of range?
if (!lfsr_tag_isalt(tag) && off + size > lfs->cfg->block_size) { if (!lfsr_tag_isalt(tag)
&& data_.u.d.off + size > lfs->cfg->block_size) {
break; break;
} }
// not an end-of-commit cksum // not an end-of-commit cksum
if (!lfsr_tag_isalt(tag) && lfsr_tag_suptype(tag) != LFSR_TAG_CKSUM) { if (!lfsr_tag_isalt(tag) && lfsr_tag_suptype(tag) != LFSR_TAG_CKSUM) {
// cksum the entry, hopefully leaving it in the cache // cksum the entry, hopefully leaving it in the cache
err = lfsr_bd_cksum(lfs, block, off, lfs->cfg->block_size, size, err = lfsr_bd_cksum(lfs,
block, data_.u.d.off, lfs->cfg->block_size, size,
&cksum); &cksum);
if (err) { if (err) {
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_CORRUPT) {
@@ -1880,21 +1887,8 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// found an ecksum? save for later // found an ecksum? save for later
if (tag == LFSR_TAG_ECKSUM) { if (tag == LFSR_TAG_ECKSUM) {
// TODO should we use LFSR_DATA_DISK here? hint issues? lfsr_data_t ecksum_data = data_;
uint8_t ecksum_buf[LFSR_ECKSUM_DSIZE]; err = lfsr_data_readecksum(lfs, &ecksum_data, &ecksum);
err = lfsr_bd_read(lfs, block, off, lfs->cfg->block_size,
ecksum_buf, lfs_min32(size, LFSR_ECKSUM_DSIZE));
if (err) {
if (err == LFS_ERR_CORRUPT) {
break;
}
return err;
}
err = lfsr_data_readecksum(lfs,
&LFSR_DATA(ecksum_buf,
lfs_min32(size, LFSR_ECKSUM_DSIZE)),
&ecksum);
if (err && err != LFS_ERR_CORRUPT) { if (err && err != LFS_ERR_CORRUPT) {
return err; return err;
} }
@@ -1907,15 +1901,14 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// is an end-of-commit cksum // is an end-of-commit cksum
} else if (!lfsr_tag_isalt(tag)) { } else if (!lfsr_tag_isalt(tag)) {
uint32_t cksum_ = 0; uint32_t cksum_ = 0;
err = lfsr_bd_read(lfs, block, off, lfs->cfg->block_size, lfsr_data_t cksum_data = data_;
&cksum_, sizeof(uint32_t)); err = lfsr_data_readle32(lfs, &cksum_data, &cksum_);
if (err) { if (err) {
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_CORRUPT) {
break; break;
} }
return err; return err;
} }
cksum_ = lfs_fromle32_(&cksum_);
if (cksum != cksum_) { if (cksum != cksum_) {
// uh oh, cksums don't match // uh oh, cksums don't match
@@ -1933,7 +1926,7 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
hasecksum = false; hasecksum = false;
// save what we've found so far // save what we've found so far
rbyd->eoff = off + size; rbyd->eoff = data_.u.d.off + size;
rbyd->cksum = cksum; rbyd->cksum = cksum;
rbyd->trunk = trunk_; rbyd->trunk = trunk_;
rbyd->weight = weight; rbyd->weight = weight;
@@ -1941,12 +1934,12 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// found a trunk of a tree? // found a trunk of a tree?
if (lfsr_tag_istrunk(tag) if (lfsr_tag_istrunk(tag)
&& (!trunk || trunk >= off-d || wastrunk)) { && (!trunk || trunk >= data.u.d.off || wastrunk)) {
// start of trunk? // start of trunk?
if (!wastrunk) { if (!wastrunk) {
wastrunk = true; wastrunk = true;
// save trunk entry point // save trunk entry point
trunk_ = off-d; trunk_ = data.u.d.off;
// reset weight // reset weight
weight_ = 0; weight_ = 0;
} }
@@ -1967,9 +1960,12 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
} }
} }
// skip data
if (!lfsr_tag_isalt(tag)) { if (!lfsr_tag_isalt(tag)) {
off += size; lfsr_data_add(&data_, size);
} }
data = data_;
} }
// no valid commits? // no valid commits?
@@ -2029,11 +2025,12 @@ static int lfsr_rbyd_lookupnext(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
lfsr_tag_t alt; lfsr_tag_t alt;
lfs_size_t weight; lfs_size_t weight;
lfs_off_t jump; lfs_off_t jump;
lfs_ssize_t d = lfsr_bd_readtag(lfs, lfsr_data_t data = LFSR_DATA_DISK(rbyd->block, branch,
rbyd->block, branch, 0, lfs_min32(LFSR_TAG_DSIZE, lfs->cfg->block_size-branch));
int err = lfsr_data_readtag(lfs, &data,
&alt, &weight, &jump, NULL); &alt, &weight, &jump, NULL);
if (d < 0) { if (err) {
return d; return err;
} }
// found an alt? // found an alt?
@@ -2044,7 +2041,7 @@ static int lfsr_rbyd_lookupnext(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
branch = branch - jump; branch = branch - jump;
} else { } else {
lfsr_tag_trim(alt, weight, &lower, &upper, NULL, NULL); lfsr_tag_trim(alt, weight, &lower, &upper, NULL, NULL);
branch = branch + d; branch = data.u.d.off;
} }
// found end of tree? // found end of tree?
@@ -2073,7 +2070,7 @@ static int lfsr_rbyd_lookupnext(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
*weight_ = rid__ - lower; *weight_ = rid__ - lower;
} }
if (data_) { if (data_) {
*data_ = LFSR_DATA_DISK(rbyd->block, branch + d, jump); *data_ = LFSR_DATA_DISK(rbyd->block, data.u.d.off, jump);
} }
return 0; return 0;
} }
@@ -2393,11 +2390,11 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfsr_tag_t alt; lfsr_tag_t alt;
lfs_size_t weight; lfs_size_t weight;
lfs_off_t jump; lfs_off_t jump;
lfs_ssize_t d = lfsr_bd_readtag(lfs, lfsr_data_t data = LFSR_DATA_DISK(rbyd->block, branch,
rbyd->block, branch, 0, lfs_min32(LFSR_TAG_DSIZE, lfs->cfg->block_size-branch));
err = lfsr_data_readtag(lfs, &data,
&alt, &weight, &jump, NULL); &alt, &weight, &jump, NULL);
if (d < 0) { if (err) {
err = d;
goto failed; goto failed;
} }
@@ -2405,7 +2402,7 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
if (lfsr_tag_isalt(alt)) { if (lfsr_tag_isalt(alt)) {
// make jump absolute // make jump absolute
jump = branch - jump; jump = branch - jump;
lfs_off_t branch_ = branch + d; lfs_off_t branch_ = data.u.d.off;
// do bounds want to take different paths? begin cutting // do bounds want to take different paths? begin cutting
if (!lfsr_tag_hasdiverged(tag_) if (!lfsr_tag_hasdiverged(tag_)
@@ -2907,7 +2904,7 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfs_size_t layer_weight = 0; lfs_size_t layer_weight = 0;
// first copy over raw tags, note this doesn't create a tree // first copy over raw tags, note this doesn't create a tree
lfs_off_t layer_start = rbyd->eoff; lfs_off_t layer_off = rbyd->eoff;
lfs_ssize_t rid = start_rid; lfs_ssize_t rid = start_rid;
lfsr_tag_t tag = 0; lfsr_tag_t tag = 0;
while (true) { while (true) {
@@ -2951,7 +2948,6 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
layer_trunks += 1; layer_trunks += 1;
layer_weight += weight; layer_weight += weight;
} }
lfs_off_t layer_end = rbyd->eoff;
// connect every other trunk together, building layers of a perfectly // connect every other trunk together, building layers of a perfectly
// balanced binary tree upwards until we have a single trunk // balanced binary tree upwards until we have a single trunk
@@ -2960,30 +2956,28 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
layer_trunks = 0; layer_trunks = 0;
layer_weight = 0; layer_weight = 0;
lfs_off_t off = layer_start; lfsr_data_t data = LFSR_DATA_DISK(rbyd->block,
layer_start = rbyd->eoff; layer_off, rbyd->eoff - layer_off);
while (off < layer_end) { layer_off = rbyd->eoff;
while (lfsr_data_size(&data) > 0) {
// connect two trunks together with a new binary trunk // connect two trunks together with a new binary trunk
for (int i = 0; i < 2 && off < layer_end; i++) { for (int i = 0; i < 2 && lfsr_data_size(&data) > 0; i++) {
lfs_off_t trunk_off = off; lfs_off_t trunk_off = data.u.d.off;
lfsr_tag_t trunk_tag = 0; lfsr_tag_t trunk_tag = 0;
lfs_size_t trunk_weight = 0; lfs_size_t trunk_weight = 0;
while (true) { while (true) {
lfsr_tag_t tag; lfsr_tag_t tag;
lfs_size_t weight; lfs_size_t weight;
lfs_size_t size; lfs_size_t size;
lfs_ssize_t d = lfsr_bd_readtag(lfs, rbyd->block, off, err = lfsr_data_readtag(lfs, &data,
layer_end-off,
&tag, &weight, &size, NULL); &tag, &weight, &size, NULL);
if (d < 0) { if (err) {
err = d;
goto failed; goto failed;
} }
off += d;
// skip any data // skip any data
if (!lfsr_tag_isalt(tag)) { if (!lfsr_tag_isalt(tag)) {
off += size; lfsr_data_add(&data, size);
} }
// keep track of trunk/layer weight, and the last non-null // keep track of trunk/layer weight, and the last non-null
@@ -3028,14 +3022,13 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// keep track of the number of trunks // keep track of the number of trunks
layer_trunks += 1; layer_trunks += 1;
} }
layer_end = rbyd->eoff;
} }
// done! just need to update our trunk/weight, note we could have // done! just need to update our trunk/weight, note we could have
// no trunks after compaction. Leave this to upper layers to take // no trunks after compaction. Leave this to upper layers to take
// care of // care of
if (layer_trunks >= 1) { if (layer_trunks >= 1) {
rbyd->trunk = layer_start; rbyd->trunk = layer_off;
} }
rbyd->weight = layer_weight; rbyd->weight = layer_weight;