Attempted to clean up lfsr_ftree_flush a bit
Block/fragment relevant variables are at least now localized to their respective loops, though block writing still has some ugly gotos to skip a few lookups when erased-state is found. Though finding erased-state does sort of just break through the rest of the block-writing heuristics, so maybe it's good that the code matches the underlying logic... Also made crystal_size lookups a bit more aggressive. The previous logic assumed worst-case crystal size when near the beginning of a file, and best best-case crystal size near the end. At the very least, this is wildly inconsistent with crystals in the middle of sparse files.
This commit is contained in:
@@ -9312,10 +9312,10 @@ static int lfsr_ftree_lookupnext(lfs_t *lfs,
|
|||||||
lfs_off_t pos,
|
lfs_off_t pos,
|
||||||
lfsr_bid_t *bid_, lfsr_tag_t *tag_, lfsr_bid_t *weight_,
|
lfsr_bid_t *bid_, lfsr_tag_t *tag_, lfsr_bid_t *weight_,
|
||||||
lfsr_bptr_t *bptr_, lfsr_ecksum_t *becksum_) {
|
lfsr_bptr_t *bptr_, lfsr_ecksum_t *becksum_) {
|
||||||
if (pos > lfsr_ftree_size(ftree)) {
|
if (pos >= lfsr_ftree_size(ftree)) {
|
||||||
return LFS_ERR_NOENT;
|
return LFS_ERR_NOENT;
|
||||||
}
|
}
|
||||||
// the uweight check should make this impossible
|
// the above size check should make this impossible
|
||||||
LFS_ASSERT(!lfsr_ftree_isnull(ftree));
|
LFS_ASSERT(!lfsr_ftree_isnull(ftree));
|
||||||
|
|
||||||
// inlined sprout?
|
// inlined sprout?
|
||||||
@@ -9690,90 +9690,90 @@ static int lfsr_ftree_carve(lfs_t *lfs,
|
|||||||
static int lfsr_ftree_flush(lfs_t *lfs,
|
static int lfsr_ftree_flush(lfs_t *lfs,
|
||||||
lfsr_mdir_t *mdir, lfsr_ftree_t *ftree,
|
lfsr_mdir_t *mdir, lfsr_ftree_t *ftree,
|
||||||
lfs_off_t pos, const uint8_t *buffer, lfs_size_t size) {
|
lfs_off_t pos, const uint8_t *buffer, lfs_size_t size) {
|
||||||
lfs_off_t pos_ = pos;
|
// we can skip some btree lookups if we know we are aligned from a
|
||||||
lfsr_bptr_t bptr_;
|
// previous iteration, we already do way too many btree lookups
|
||||||
|
bool aligned = false;
|
||||||
// first we need to figure out our current crystal, we do this
|
|
||||||
// heuristically.
|
|
||||||
//
|
|
||||||
// note that we may end up including holes in our crystal, but this
|
|
||||||
// is fine. we don't want small holes breaking up blocks anyways
|
|
||||||
//
|
|
||||||
lfs_off_t crystal_start;
|
|
||||||
lfs_off_t crystal_end;
|
|
||||||
lfs_off_t block_start;
|
|
||||||
// at beginning of file?
|
|
||||||
if (pos_ < lfs->cfg->crystal_size) {
|
|
||||||
crystal_start = 0;
|
|
||||||
|
|
||||||
// beyond the end of the tree?
|
|
||||||
} else if (pos_ - lfs->cfg->crystal_size
|
|
||||||
>= lfsr_ftree_size(ftree)) {
|
|
||||||
crystal_start = pos_;
|
|
||||||
|
|
||||||
// find left crystal neighbor
|
|
||||||
} else {
|
|
||||||
lfsr_bid_t bid_;
|
|
||||||
lfsr_tag_t tag_;
|
|
||||||
lfsr_bid_t weight_;
|
|
||||||
lfsr_ecksum_t becksum_;
|
|
||||||
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
|
||||||
pos_ - lfs->cfg->crystal_size,
|
|
||||||
&bid_, &tag_, &weight_, &bptr_, &becksum_);
|
|
||||||
if (err) {
|
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if left crystal neighbor is a fragment and there is no hole
|
|
||||||
// between our own crystal and our neighbor, include as a part of
|
|
||||||
// our crystal
|
|
||||||
if (tag_ == LFSR_TAG_DATA
|
|
||||||
&& bid_-(weight_-1)+lfsr_data_size(&bptr_.data)
|
|
||||||
>= pos_ - lfs->cfg->crystal_size) {
|
|
||||||
crystal_start = bid_-(weight_-1);
|
|
||||||
|
|
||||||
// otherwise our neighbor determines our crystal boundary
|
|
||||||
} else {
|
|
||||||
crystal_start = lfs_min32(bid_+1, pos_);
|
|
||||||
|
|
||||||
// wait, found block-level erased-state?
|
|
||||||
if (tag_ == LFSR_TAG_BLOCK
|
|
||||||
&& pos_ - (bid_-(weight_-1))
|
|
||||||
>= lfsr_data_size(&bptr_.data)
|
|
||||||
&& lfsr_data_size(&bptr_.data) == bptr_.cksize
|
|
||||||
&& bptr_.cksize < lfs->cfg->block_size
|
|
||||||
&& becksum_.size != -1) {
|
|
||||||
err = lfsr_ecksum_validate(lfs, &becksum_,
|
|
||||||
bptr_.data.u.disk.block, bptr_.cksize);
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// found _valid_ block-level erased-state? eagerly append
|
|
||||||
if (err != LFS_ERR_CORRUPT) {
|
|
||||||
block_start = bid_-(weight_-1);
|
|
||||||
crystal_end = pos_ + size;
|
|
||||||
goto append;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// iteratively write blocks
|
// iteratively write blocks
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
|
// first we need to figure out our current crystal, we do this
|
||||||
|
// heuristically.
|
||||||
|
//
|
||||||
|
// note that we may end up including holes in our crystal, but this
|
||||||
|
// is fine. we don't want small holes breaking up blocks anyways
|
||||||
|
|
||||||
|
// default to arbitrary alignment
|
||||||
|
lfs_off_t crystal_start = pos;
|
||||||
|
lfs_off_t crystal_end = pos + size;
|
||||||
|
lfs_off_t block_start;
|
||||||
|
lfsr_bptr_t bptr;
|
||||||
|
|
||||||
|
// within our tree? find left crystal neighbor
|
||||||
|
if (pos > 0
|
||||||
|
&& (lfs_soff_t)(pos - lfs->cfg->crystal_size)
|
||||||
|
< (lfs_soff_t)lfsr_ftree_size(ftree)
|
||||||
|
&& lfsr_ftree_size(ftree) > 0
|
||||||
|
// don't bother to lookup left after the first block
|
||||||
|
&& !aligned) {
|
||||||
|
lfsr_bid_t bid;
|
||||||
|
lfsr_tag_t tag;
|
||||||
|
lfsr_bid_t weight;
|
||||||
|
lfsr_ecksum_t becksum;
|
||||||
|
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
||||||
|
lfs_smax32(pos - lfs->cfg->crystal_size, 0),
|
||||||
|
&bid, &tag, &weight, &bptr, &becksum);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if left crystal neighbor is a fragment and there is no hole
|
||||||
|
// between our own crystal and our neighbor, include as a part
|
||||||
|
// of our crystal
|
||||||
|
if (tag == LFSR_TAG_DATA
|
||||||
|
&& bid-(weight-1)+lfsr_data_size(&bptr.data)
|
||||||
|
>= pos - lfs->cfg->crystal_size) {
|
||||||
|
crystal_start = bid-(weight-1);
|
||||||
|
|
||||||
|
// otherwise our neighbor determines our crystal boundary
|
||||||
|
} else {
|
||||||
|
crystal_start = lfs_min32(bid+1, pos);
|
||||||
|
|
||||||
|
// wait, found block-level erased-state?
|
||||||
|
if (tag == LFSR_TAG_BLOCK
|
||||||
|
&& pos - (bid-(weight-1))
|
||||||
|
>= lfsr_data_size(&bptr.data)
|
||||||
|
&& lfsr_data_size(&bptr.data) == bptr.cksize
|
||||||
|
&& bptr.cksize < lfs->cfg->block_size
|
||||||
|
&& becksum.size != -1) {
|
||||||
|
err = lfsr_ecksum_validate(lfs, &becksum,
|
||||||
|
bptr.data.u.disk.block, bptr.cksize);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found _valid_ block-level erased-state? eagerly
|
||||||
|
// append
|
||||||
|
if (err != LFS_ERR_CORRUPT) {
|
||||||
|
block_start = bid-(weight-1);
|
||||||
|
goto compact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if we haven't already exceeded our crystallization threshold,
|
// if we haven't already exceeded our crystallization threshold,
|
||||||
// find right crystal neighbor
|
// find right crystal neighbor
|
||||||
crystal_end = pos_ + size;
|
|
||||||
if (crystal_end - crystal_start <= lfs->cfg->crystal_size
|
if (crystal_end - crystal_start <= lfs->cfg->crystal_size
|
||||||
&& crystal_start + lfs->cfg->crystal_size
|
&& lfsr_ftree_size(ftree) > 0) {
|
||||||
< lfsr_ftree_size(ftree)) {
|
lfsr_bid_t bid;
|
||||||
lfsr_bid_t bid_;
|
lfsr_tag_t tag;
|
||||||
lfsr_tag_t tag_;
|
lfsr_bid_t weight;
|
||||||
lfsr_bid_t weight_;
|
|
||||||
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
||||||
crystal_start + lfs->cfg->crystal_size,
|
lfs_min32(
|
||||||
&bid_, &tag_, &weight_, &bptr_, NULL);
|
crystal_start + lfs->cfg->crystal_size,
|
||||||
|
lfsr_ftree_size(ftree)-1),
|
||||||
|
&bid, &tag, &weight, &bptr, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
return err;
|
return err;
|
||||||
@@ -9781,16 +9781,16 @@ static int lfsr_ftree_flush(lfs_t *lfs,
|
|||||||
|
|
||||||
// if right crystal neighbor is a fragment, include as a part
|
// if right crystal neighbor is a fragment, include as a part
|
||||||
// of our crystal
|
// of our crystal
|
||||||
if (tag_ == LFSR_TAG_DATA) {
|
if (tag == LFSR_TAG_DATA) {
|
||||||
crystal_end = lfs_max32(
|
crystal_end = lfs_max32(
|
||||||
bid_-(weight_-1)+lfsr_data_size(&bptr_.data),
|
bid-(weight-1)+lfsr_data_size(&bptr.data),
|
||||||
pos_ + size);
|
pos + size);
|
||||||
|
|
||||||
// otherwise treat as crystal boundary
|
// otherwise treat as crystal boundary
|
||||||
} else {
|
} else {
|
||||||
crystal_end = lfs_max32(
|
crystal_end = lfs_max32(
|
||||||
bid_-(weight_-1),
|
bid-(weight-1),
|
||||||
pos_ + size);
|
pos + size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9807,123 +9807,122 @@ static int lfsr_ftree_flush(lfs_t *lfs,
|
|||||||
block_start = crystal_start;
|
block_start = crystal_start;
|
||||||
if (crystal_start > 0
|
if (crystal_start > 0
|
||||||
&& lfsr_ftree_size(ftree) > 0
|
&& lfsr_ftree_size(ftree) > 0
|
||||||
// don't bother to lookup left after first fragment
|
// don't bother to lookup left after the first block
|
||||||
&& pos_ == pos) {
|
&& !aligned) {
|
||||||
lfsr_bid_t bid_;
|
lfsr_bid_t bid;
|
||||||
lfsr_tag_t tag_;
|
lfsr_tag_t tag;
|
||||||
lfsr_bid_t weight_;
|
lfsr_bid_t weight;
|
||||||
lfsr_ecksum_t becksum_;
|
lfsr_ecksum_t becksum;
|
||||||
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
||||||
lfs_min32(
|
lfs_min32(
|
||||||
crystal_start-1,
|
crystal_start-1,
|
||||||
lfsr_ftree_size(ftree)-1),
|
lfsr_ftree_size(ftree)-1),
|
||||||
&bid_, &tag_, &weight_, &bptr_, &becksum_);
|
&bid, &tag, &weight, &bptr, &becksum);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// is our left neighbor in the same block?
|
// is our left neighbor in the same block?
|
||||||
if (crystal_start - (bid_-(weight_-1))
|
if (crystal_start - (bid-(weight-1))
|
||||||
< lfs->cfg->block_size
|
< lfs->cfg->block_size
|
||||||
&& lfsr_data_size(&bptr_.data) > 0) {
|
&& lfsr_data_size(&bptr.data) > 0) {
|
||||||
block_start = bid_-(weight_-1);
|
block_start = bid-(weight-1);
|
||||||
|
|
||||||
// wait, found block-level erased-state?
|
// wait, found block-level erased-state?
|
||||||
if (tag_ == LFSR_TAG_BLOCK
|
if (tag == LFSR_TAG_BLOCK
|
||||||
&& crystal_start - (bid_-(weight_-1))
|
&& crystal_start - (bid-(weight-1))
|
||||||
>= lfsr_data_size(&bptr_.data)
|
>= lfsr_data_size(&bptr.data)
|
||||||
&& lfsr_data_size(&bptr_.data) == bptr_.cksize
|
&& lfsr_data_size(&bptr.data) == bptr.cksize
|
||||||
&& bptr_.cksize < lfs->cfg->block_size
|
&& bptr.cksize < lfs->cfg->block_size
|
||||||
&& becksum_.size != -1) {
|
&& becksum.size != -1) {
|
||||||
err = lfsr_ecksum_validate(lfs, &becksum_,
|
err = lfsr_ecksum_validate(lfs, &becksum,
|
||||||
bptr_.data.u.disk.block, bptr_.cksize);
|
bptr.data.u.disk.block, bptr.cksize);
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// found _valid_ block-level erased-state? eagerly append
|
// found _valid_ block-level erased-state? eagerly
|
||||||
|
// append
|
||||||
if (err != LFS_ERR_CORRUPT) {
|
if (err != LFS_ERR_CORRUPT) {
|
||||||
goto append;
|
goto compact;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no? is our left neighbor at least our left block neighbor?
|
// no? is our left neighbor at least our left block neighbor?
|
||||||
// align to block alignment
|
// align to block alignment
|
||||||
} else if (crystal_start - (bid_-(weight_-1))
|
} else if (crystal_start - (bid-(weight-1))
|
||||||
< 2*lfs->cfg->block_size
|
< 2*lfs->cfg->block_size
|
||||||
&& lfsr_data_size(&bptr_.data) > 0) {
|
&& lfsr_data_size(&bptr.data) > 0) {
|
||||||
block_start = bid_-(weight_-1) + lfs->cfg->block_size;
|
block_start = bid-(weight-1) + lfs->cfg->block_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO lfsr_bptr_alloc?
|
|
||||||
// allocate a new block
|
// allocate a new block
|
||||||
int err = lfs_alloc(lfs, &bptr_.data.u.disk.block);
|
int err = lfs_alloc(lfs, &bptr.data.u.disk.block);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO should lfs_alloc handle erase?
|
// TODO should lfs_alloc handle erase?
|
||||||
err = lfsr_bd_erase(lfs, bptr_.data.u.disk.block);
|
err = lfsr_bd_erase(lfs, bptr.data.u.disk.block);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bptr_.data.u.disk.off = 0;
|
bptr.data = LFSR_DATA_DISK(bptr.data.u.disk.block, 0, 0);
|
||||||
bptr_.data.u.disk.size = LFSR_DATA_ONDISK | 0;
|
bptr.cksize = 0;
|
||||||
bptr_.cksize = 0;
|
bptr.cksum = 0;
|
||||||
bptr_.cksum = 0;
|
|
||||||
|
|
||||||
append:;
|
compact:;
|
||||||
// compact data into our new block
|
// compact data into our new block
|
||||||
//
|
//
|
||||||
// eagerly merge any right neighbors we see unless that would
|
// eagerly merge any right neighbors we see unless that would
|
||||||
// put us over our block size
|
// put us over our block size
|
||||||
lfs_off_t pos__ = block_start + lfsr_data_size(&bptr_.data);
|
lfs_off_t pos_ = block_start + lfsr_data_size(&bptr.data);
|
||||||
while (pos__ < lfs_min32(
|
while (pos_ < lfs_min32(
|
||||||
block_start + lfs->cfg->block_size,
|
block_start + lfs->cfg->block_size,
|
||||||
lfs_max32(
|
lfs_max32(
|
||||||
pos_ + size,
|
pos + size,
|
||||||
lfsr_ftree_size(ftree)))) {
|
lfsr_ftree_size(ftree)))) {
|
||||||
// keep track of the next highest priority data offset
|
// keep track of the next highest priority data offset
|
||||||
lfs_ssize_t d = lfs_min32(
|
lfs_ssize_t d = lfs_min32(
|
||||||
block_start + lfs->cfg->block_size,
|
block_start + lfs->cfg->block_size,
|
||||||
lfs_max32(
|
lfs_max32(
|
||||||
pos_ + size,
|
pos + size,
|
||||||
lfsr_ftree_size(ftree))) - pos__;
|
lfsr_ftree_size(ftree))) - pos_;
|
||||||
|
|
||||||
// any data in our write buffer?
|
// any data in our write buffer?
|
||||||
if (pos__ < pos_ + size) {
|
if (pos_ < pos + size) {
|
||||||
if (pos__ >= pos_) {
|
if (pos_ >= pos) {
|
||||||
lfs_ssize_t d_ = lfs_min32(
|
lfs_ssize_t d_ = lfs_min32(
|
||||||
d,
|
d,
|
||||||
size - (pos__ - pos_));
|
size - (pos_ - pos));
|
||||||
err = lfsr_bd_prog(lfs, bptr_.data.u.disk.block,
|
err = lfsr_bd_prog(lfs, bptr.data.u.disk.block,
|
||||||
bptr_.cksize,
|
bptr.cksize,
|
||||||
&buffer[pos__ - pos_], d_,
|
&buffer[pos_ - pos], d_,
|
||||||
&bptr_.cksum);
|
&bptr.cksum);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos__ += d_;
|
pos_ += d_;
|
||||||
bptr_.cksize += d_;
|
bptr.cksize += d_;
|
||||||
d -= d_;
|
d -= d_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffered data takes priority
|
// buffered data takes priority
|
||||||
d = lfs_min32(d, pos_ - pos__);
|
d = lfs_min32(d, pos - pos_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// any data on disk?
|
// any data on disk?
|
||||||
if (pos__ < lfsr_ftree_size(ftree)) {
|
if (pos_ < lfsr_ftree_size(ftree)) {
|
||||||
lfsr_bid_t bid;
|
lfsr_bid_t bid_;
|
||||||
lfsr_tag_t tag;
|
lfsr_tag_t tag_;
|
||||||
lfsr_bid_t weight;
|
lfsr_bid_t weight_;
|
||||||
lfsr_bptr_t bptr;
|
lfsr_bptr_t bptr_;
|
||||||
err = lfsr_ftree_lookupnext(lfs, mdir, ftree, pos__,
|
err = lfsr_ftree_lookupnext(lfs, mdir, ftree, pos_,
|
||||||
&bid, &tag, &weight, &bptr, NULL);
|
&bid_, &tag_, &weight_, &bptr_, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
return err;
|
return err;
|
||||||
@@ -9931,62 +9930,61 @@ append:;
|
|||||||
|
|
||||||
// make sure to include all of our crystal, or else this
|
// make sure to include all of our crystal, or else this
|
||||||
// loop may never terminate
|
// loop may never terminate
|
||||||
if (bid-(weight-1) >= crystal_end
|
if (bid_-(weight_-1) >= crystal_end
|
||||||
// is this data a pure hole? stop early to better
|
// is this data a pure hole? stop early to better
|
||||||
// leverage becksums in sparse files
|
// leverage becksums in sparse files
|
||||||
&& (pos__ >= bid-(weight-1)
|
&& (pos_ >= bid_-(weight_-1)
|
||||||
+ lfsr_data_size(&bptr.data)
|
+ lfsr_data_size(&bptr_.data)
|
||||||
// does this data exceed our block_size?
|
// does this data exceed our block_size?
|
||||||
// stop early to try to avoid messing up
|
// stop early to try to avoid messing up
|
||||||
// block alignment
|
// block alignment
|
||||||
|| bid-(weight-1) + lfsr_data_size(&bptr.data)
|
|| bid_-(weight_-1) + lfsr_data_size(&bptr_.data)
|
||||||
- block_start
|
- block_start
|
||||||
> lfs->cfg->block_size)) {
|
> lfs->cfg->block_size)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos__ < bid-(weight-1) + lfsr_data_size(&bptr.data)) {
|
if (pos_ < bid_-(weight_-1) + lfsr_data_size(&bptr_.data)) {
|
||||||
// note one important side-effect here is a strict
|
// note one important side-effect here is a strict
|
||||||
// data hint
|
// data hint
|
||||||
lfs_ssize_t d_ = lfs_min32(
|
lfs_ssize_t d_ = lfs_min32(
|
||||||
d,
|
d,
|
||||||
lfsr_data_size(&bptr.data)
|
lfsr_data_size(&bptr_.data)
|
||||||
- (pos__ - (bid-(weight-1))));
|
- (pos_ - (bid_-(weight_-1))));
|
||||||
err = lfsr_bd_progdata(lfs, bptr_.data.u.disk.block,
|
err = lfsr_bd_progdata(lfs, bptr.data.u.disk.block,
|
||||||
bptr_.cksize,
|
bptr.cksize,
|
||||||
lfsr_data_slice(bptr.data,
|
lfsr_data_slice(bptr_.data,
|
||||||
pos__ - (bid-(weight-1)),
|
pos_ - (bid_-(weight_-1)),
|
||||||
d_),
|
d_),
|
||||||
&bptr_.cksum);
|
&bptr.cksum);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos__ += d_;
|
pos_ += d_;
|
||||||
bptr_.cksize += d_;
|
bptr.cksize += d_;
|
||||||
d -= d_;
|
d -= d_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// found a hole? just make sure next leaf takes priority
|
// found a hole? just make sure next leaf takes priority
|
||||||
d = lfs_min32(d, bid+1 - pos__);
|
d = lfs_min32(d, bid_+1 - pos_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// found a hole? write zeros
|
// found a hole? write zeros
|
||||||
// TODO do something better than byte-level progs here
|
// TODO do something better than byte-level progs here
|
||||||
for (lfs_size_t i = 0; i < (lfs_size_t)d; i++) {
|
for (lfs_size_t i = 0; i < (lfs_size_t)d; i++) {
|
||||||
err = lfsr_bd_prog(lfs, bptr_.data.u.disk.block,
|
err = lfsr_bd_prog(lfs, bptr.data.u.disk.block,
|
||||||
bptr_.cksize + i,
|
bptr.cksize + i,
|
||||||
&(uint8_t){0}, 1,
|
&(uint8_t){0}, 1,
|
||||||
&bptr_.cksum);
|
&bptr.cksum);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos__ += d;
|
pos_ += d;
|
||||||
bptr_.cksize += d;
|
bptr.cksize += d;
|
||||||
}
|
}
|
||||||
lfs_off_t block_end = pos__;
|
|
||||||
|
|
||||||
// A bit of a hack here, we need to truncate our block to prog_size
|
// A bit of a hack here, we need to truncate our block to prog_size
|
||||||
// alignment to avoid padding issues. Doing this retroactively to
|
// alignment to avoid padding issues. Doing this retroactively to
|
||||||
@@ -9998,33 +9996,33 @@ append:;
|
|||||||
lfs_ssize_t d = (lfs->pcache.off + lfs->pcache.size)
|
lfs_ssize_t d = (lfs->pcache.off + lfs->pcache.size)
|
||||||
% lfs->cfg->prog_size;
|
% lfs->cfg->prog_size;
|
||||||
lfs->pcache.size -= d;
|
lfs->pcache.size -= d;
|
||||||
block_end -= d;
|
bptr.cksize -= d;
|
||||||
bptr_.cksize -= d;
|
|
||||||
|
|
||||||
// TODO validate?
|
// TODO validate?
|
||||||
// finalize our write
|
// finalize our write
|
||||||
// TODO need this if statement?
|
err = lfsr_bd_flush(lfs);
|
||||||
if (lfs->pcache.size > 0) {
|
if (err) {
|
||||||
err = lfsr_bd_flush(lfs);
|
return err;
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare our block pointer
|
// prepare our block pointer
|
||||||
LFS_ASSERT(bptr_.cksize > 0);
|
LFS_ASSERT(bptr.cksize > 0);
|
||||||
LFS_ASSERT(bptr_.cksize >= lfs->cfg->crystal_size);
|
LFS_ASSERT(bptr.cksize >= lfs->cfg->crystal_size);
|
||||||
bptr_.data.u.disk.size = LFSR_DATA_ONDISK
|
LFS_ASSERT(bptr.cksize <= lfs->cfg->block_size);
|
||||||
| (bptr_.cksize - bptr_.data.u.disk.off);
|
bptr.data = LFSR_DATA_DISK(
|
||||||
|
bptr.data.u.disk.block,
|
||||||
|
bptr.data.u.disk.off,
|
||||||
|
bptr.cksize - bptr.data.u.disk.off);
|
||||||
|
lfs_off_t block_end = block_start + lfsr_data_size(&bptr.data);
|
||||||
|
|
||||||
// do we have space for a block ecksum?
|
// do we have space for a block ecksum?
|
||||||
lfsr_ecksum_t becksum_ = {.size=-1};
|
lfsr_ecksum_t becksum = {.size=-1};
|
||||||
if (bptr_.cksize < lfs->cfg->block_size) {
|
if (bptr.cksize < lfs->cfg->block_size) {
|
||||||
becksum_.size = lfs->cfg->prog_size;
|
becksum.size = lfs->cfg->prog_size;
|
||||||
err = lfsr_bd_cksum(lfs, bptr_.data.u.disk.off,
|
err = lfsr_bd_cksum(lfs, bptr.data.u.disk.off,
|
||||||
bptr_.cksize, lfs->cfg->prog_size,
|
bptr.cksize, lfs->cfg->prog_size,
|
||||||
lfs->cfg->prog_size,
|
lfs->cfg->prog_size,
|
||||||
&becksum_.cksum);
|
&becksum.cksum);
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -10036,10 +10034,10 @@ append:;
|
|||||||
err = lfsr_ftree_carve(lfs, mdir, ftree,
|
err = lfsr_ftree_carve(lfs, mdir, ftree,
|
||||||
block_start, block_end - block_start, 0,
|
block_start, block_end - block_start, 0,
|
||||||
LFSR_ATTRS(
|
LFSR_ATTRS(
|
||||||
LFSR_ATTR(0, BLOCK, 0, FROMBPTR(&bptr_, bptr_buf)),
|
LFSR_ATTR(0, BLOCK, 0, FROMBPTR(&bptr, bptr_buf)),
|
||||||
(becksum_.size != -1)
|
(becksum.size != -1)
|
||||||
? LFSR_ATTR(0,
|
? LFSR_ATTR(0,
|
||||||
BECKSUM, 0, FROMECKSUM(&becksum_, becksum_buf))
|
BECKSUM, 0, FROMECKSUM(&becksum, becksum_buf))
|
||||||
: LFSR_ATTR_NOOP()));
|
: LFSR_ATTR_NOOP()));
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -10047,18 +10045,17 @@ append:;
|
|||||||
|
|
||||||
// note compacting fragments -> blocks may not actually make any
|
// note compacting fragments -> blocks may not actually make any
|
||||||
// progress on flushing the buffer on the first pass
|
// progress on flushing the buffer on the first pass
|
||||||
d = lfs_max32(pos_, block_end) - pos_;
|
d = lfs_max32(pos, block_end) - pos;
|
||||||
pos_ += d;
|
pos += d;
|
||||||
buffer += lfs_min32(d, size);
|
buffer += lfs_min32(d, size);
|
||||||
size -= lfs_min32(d, size);
|
size -= lfs_min32(d, size);
|
||||||
|
aligned = true;
|
||||||
crystal_start = block_end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// iteratively write fragments (inlined leaves)
|
// iteratively write fragments (inlined leaves)
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
// truncate to our fragment size
|
// truncate to our fragment size
|
||||||
lfs_off_t fragment_start = pos_;
|
lfs_off_t fragment_start = pos;
|
||||||
lfs_off_t fragment_end = fragment_start
|
lfs_off_t fragment_end = fragment_start
|
||||||
+ lfs_min32(size, lfs->cfg->fragment_size);
|
+ lfs_min32(size, lfs->cfg->fragment_size);
|
||||||
lfsr_data_t data = LFSR_DATA_BUF(
|
lfsr_data_t data = LFSR_DATA_BUF(
|
||||||
@@ -10073,36 +10070,36 @@ append:;
|
|||||||
if (fragment_start > 0
|
if (fragment_start > 0
|
||||||
&& lfsr_ftree_size(ftree) >= fragment_start
|
&& lfsr_ftree_size(ftree) >= fragment_start
|
||||||
// don't bother to lookup left after first fragment
|
// don't bother to lookup left after first fragment
|
||||||
&& pos_ == pos) {
|
&& !aligned) {
|
||||||
lfsr_bid_t bid_;
|
lfsr_bid_t bid;
|
||||||
lfsr_tag_t tag_;
|
lfsr_tag_t tag;
|
||||||
lfsr_bid_t weight_;
|
lfsr_bid_t weight;
|
||||||
lfsr_bptr_t bptr_;
|
lfsr_bptr_t bptr;
|
||||||
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
||||||
fragment_start-1,
|
fragment_start-1,
|
||||||
&bid_, &tag_, &weight_, &bptr_, NULL);
|
&bid, &tag, &weight, &bptr, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// can we coalesce?
|
// can we coalesce?
|
||||||
if (bid_-(weight_-1) + lfsr_data_size(&bptr_.data)
|
if (bid-(weight-1) + lfsr_data_size(&bptr.data)
|
||||||
>= fragment_start
|
>= fragment_start
|
||||||
&& lfsr_data_size(&bptr_.data)
|
&& lfsr_data_size(&bptr.data)
|
||||||
< lfs->cfg->fragment_size) {
|
< lfs->cfg->fragment_size) {
|
||||||
// coalesce, but truncate to our fragment size
|
// coalesce, but truncate to our fragment size
|
||||||
// TODO this is a bit of a hacky way to prepend data...
|
// TODO this is a bit of a hacky way to prepend data...
|
||||||
LFS_ASSERT(data_count == 1);
|
LFS_ASSERT(data_count == 1);
|
||||||
datas[0] = lfsr_data_truncate(bptr_.data,
|
datas[0] = lfsr_data_truncate(bptr.data,
|
||||||
fragment_start - (bid_-(weight_-1)));
|
fragment_start - (bid-(weight-1)));
|
||||||
datas[1] = lfsr_data_truncate(data,
|
datas[1] = lfsr_data_truncate(data,
|
||||||
lfs->cfg->fragment_size
|
lfs->cfg->fragment_size
|
||||||
- (fragment_start - (bid_-(weight_-1))));
|
- (fragment_start - (bid-(weight-1))));
|
||||||
data_count = 2;
|
data_count = 2;
|
||||||
data = lfsr_data_fromcat(datas, data_count);
|
data = lfsr_data_fromcat(datas, data_count);
|
||||||
|
|
||||||
fragment_start = bid_-(weight_-1);
|
fragment_start = bid-(weight-1);
|
||||||
fragment_end = fragment_start + lfsr_data_size(&data);
|
fragment_end = fragment_start + lfsr_data_size(&data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10114,26 +10111,26 @@ append:;
|
|||||||
// don't bother to lookup right if fragment is already full
|
// don't bother to lookup right if fragment is already full
|
||||||
&& fragment_end - fragment_start
|
&& fragment_end - fragment_start
|
||||||
< lfs->cfg->fragment_size) {
|
< lfs->cfg->fragment_size) {
|
||||||
lfsr_bid_t bid_;
|
lfsr_bid_t bid;
|
||||||
lfsr_tag_t tag_;
|
lfsr_tag_t tag;
|
||||||
lfsr_bid_t weight_;
|
lfsr_bid_t weight;
|
||||||
lfsr_bptr_t bptr_;
|
lfsr_bptr_t bptr;
|
||||||
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
int err = lfsr_ftree_lookupnext(lfs, mdir, ftree,
|
||||||
fragment_end,
|
fragment_end,
|
||||||
&bid_, &tag_, &weight_, &bptr_, NULL);
|
&bid, &tag, &weight, &bptr, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// can we coalesce?
|
// can we coalesce?
|
||||||
if (fragment_end < bid_-(weight_-1)
|
if (fragment_end < bid-(weight-1)
|
||||||
+ lfsr_data_size(&bptr_.data)
|
+ lfsr_data_size(&bptr.data)
|
||||||
&& bid_-(weight_-1) + lfsr_data_size(&bptr_.data)
|
&& bid-(weight-1) + lfsr_data_size(&bptr.data)
|
||||||
- fragment_start
|
- fragment_start
|
||||||
<= lfs->cfg->fragment_size) {
|
<= lfs->cfg->fragment_size) {
|
||||||
datas[data_count++] = lfsr_data_fruncate(bptr_.data,
|
datas[data_count++] = lfsr_data_fruncate(bptr.data,
|
||||||
bid_-(weight_-1) + lfsr_data_size(&bptr_.data)
|
bid-(weight-1) + lfsr_data_size(&bptr.data)
|
||||||
- fragment_end);
|
- fragment_end);
|
||||||
data = lfsr_data_fromcat(datas, data_count);
|
data = lfsr_data_fromcat(datas, data_count);
|
||||||
|
|
||||||
@@ -10155,10 +10152,11 @@ append:;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// to next fragment
|
// to next fragment
|
||||||
lfs_ssize_t d = fragment_end - pos_;
|
lfs_ssize_t d = fragment_end - pos;
|
||||||
pos_ += d;
|
pos += d;
|
||||||
buffer += lfs_min32(d, size);
|
buffer += lfs_min32(d, size);
|
||||||
size -= lfs_min32(d, size);
|
size -= lfs_min32(d, size);
|
||||||
|
aligned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user