Dropped strict pcache asserts, cleaned up mdir/rbyd error handling

This assert in lfs_bd_prog, which detects if a pcache gets reused
without either a flush or drop, has been the source of quite a number of
debugging experiences, ensuring that pcaches are always in an intentioned,
managed state.

This serves to... make this assert happy.

Really, why did I keep this around for so long. It effectively forces a
sort of manual memory management on a resource that doesn't really need
to be managed. It's extra messy and tricky thanks to the number of
(poorly tested) routes errors can go through, making recovery after an
error a risky gamble with this assert enabled.

So this commit drops this strict pcache assert, instead detecting when
the targetted block changes and implicitly zeroing the cache in that
case.

This simplifies rbyd/mdir error handling, where internal errors, such as
RANGE on rbyd overflow, are common and part of normal operation.

---

This also cleans up mdir error handling a bit, and makes mdir drops a
NOENT error. mdir drops are a bit special in that they don't finish the
commit and can't be read from again (which has already led to a couple
bugs), so making the exceptional behavior of mdir drops more clear is
probably a good thing...
This commit is contained in:
Christopher Haster
2023-09-09 15:27:36 -05:00
parent 17400c5c34
commit 610d290797
+102 -145
View File
@@ -336,11 +336,8 @@ static int lfs_bd_prog(lfs_t *lfs,
continue; continue;
} }
// pcache must have been flushed, either by programming and
// entire block or manually flushing the pcache
LFS_ASSERT(pcache->block == LFS_BLOCK_NULL);
// prepare pcache, first condition can no longer fail // prepare pcache, first condition can no longer fail
lfs_cache_zero(lfs, pcache);
pcache->block = block; pcache->block = block;
pcache->off = lfs_aligndown(off, lfs->cfg->prog_size); pcache->off = lfs_aligndown(off, lfs->cfg->prog_size);
pcache->size = 0; pcache->size = 0;
@@ -2079,17 +2076,11 @@ static int lfsr_rbyd_appendrev(lfs_t *lfs, lfsr_rbyd_t *rbyd, uint32_t rev) {
int err = lfsr_bd_prog(lfs, rbyd->block, rbyd->eoff, int err = lfsr_bd_prog(lfs, rbyd->block, rbyd->eoff,
&rev_buf, sizeof(uint32_t), &rbyd->cksum); &rev_buf, sizeof(uint32_t), &rbyd->cksum);
if (err) { if (err) {
goto failed; return err;
} }
rbyd->eoff += sizeof(uint32_t); rbyd->eoff += sizeof(uint32_t);
return 0; return 0;
failed:
// if we fail mark the rbyd as unerased and release the pcache
lfs_cache_zero(lfs, &lfs->pcache);
rbyd->eoff = -1;
return err;
} }
// helper functions for managing the 3-element fifo used in // helper functions for managing the 3-element fifo used in
@@ -2211,10 +2202,8 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
LFS_ASSERT(!(tag & 0x80)); LFS_ASSERT(!(tag & 0x80));
// we can't do anything if we're not erased // we can't do anything if we're not erased
int err;
if (rbyd->eoff >= lfs->cfg->block_size) { if (rbyd->eoff >= lfs->cfg->block_size) {
err = LFS_ERR_RANGE; return LFS_ERR_RANGE;
goto failed;
} }
// ignore noops // ignore noops
@@ -2225,9 +2214,9 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// make sure every rbyd starts with a revision count // make sure every rbyd starts with a revision count
if (rbyd->eoff == 0) { if (rbyd->eoff == 0) {
err = lfsr_rbyd_appendrev(lfs, rbyd, 0); int err = lfsr_rbyd_appendrev(lfs, rbyd, 0);
if (err) { if (err) {
goto failed; return err;
} }
} }
@@ -2340,8 +2329,7 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
rbyd->block, branch, 0, rbyd->block, branch, 0,
&alt, &weight, &jump, NULL); &alt, &weight, &jump, NULL);
if (d < 0) { if (d < 0) {
err = d; return d;
goto failed;
} }
// found an alt? // found an alt?
@@ -2531,11 +2519,11 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
} }
// push alt onto our queue // push alt onto our queue
err = lfsr_rbyd_p_push(lfs, rbyd, int err = lfsr_rbyd_p_push(lfs, rbyd,
p_alts, p_weights, p_jumps, p_alts, p_weights, p_jumps,
alt, weight, jump); alt, weight, jump);
if (err) { if (err) {
goto failed; return err;
} }
// found end of tree? // found end of tree?
@@ -2657,11 +2645,11 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
} }
if (alt) { if (alt) {
err = lfsr_rbyd_p_push(lfs, rbyd, int err = lfsr_rbyd_p_push(lfs, rbyd,
p_alts, p_weights, p_jumps, p_alts, p_weights, p_jumps,
alt, weight, branch); alt, weight, branch);
if (err) { if (err) {
goto failed; return err;
} }
if (lfsr_tag_isred(p_alts[0])) { if (lfsr_tag_isred(p_alts[0])) {
@@ -2671,10 +2659,10 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
} }
// flush any pending alts // flush any pending alts
err = lfsr_rbyd_p_flush(lfs, rbyd, int err = lfsr_rbyd_p_flush(lfs, rbyd,
p_alts, p_weights, p_jumps, 3); p_alts, p_weights, p_jumps, 3);
if (err) { if (err) {
goto failed; return err;
} }
leaf:; leaf:;
@@ -2689,8 +2677,7 @@ leaf:;
lfsr_data_size(&data), lfsr_data_size(&data),
&rbyd->cksum); &rbyd->cksum);
if (d < 0) { if (d < 0) {
err = d; return d;
goto failed;
} }
rbyd->eoff += d; rbyd->eoff += d;
@@ -2698,16 +2685,11 @@ leaf:;
err = lfsr_bd_progdata(lfs, rbyd->block, rbyd->eoff, data, err = lfsr_bd_progdata(lfs, rbyd->block, rbyd->eoff, data,
&rbyd->cksum); &rbyd->cksum);
if (err) { if (err) {
goto failed; return err;
} }
rbyd->eoff += lfsr_data_size(&data); rbyd->eoff += lfsr_data_size(&data);
return 0; return 0;
failed:;
// if we failed release the pcache
lfs_cache_zero(lfs, &lfs->pcache);
return err;
} }
static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) { static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
@@ -2715,17 +2697,15 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
LFS_ASSERT(lfsr_rbyd_isfetched(rbyd)); LFS_ASSERT(lfsr_rbyd_isfetched(rbyd));
// we can't do anything if we're not erased // we can't do anything if we're not erased
int err;
if (rbyd->eoff >= lfs->cfg->block_size) { if (rbyd->eoff >= lfs->cfg->block_size) {
err = LFS_ERR_RANGE; return LFS_ERR_RANGE;
goto failed;
} }
// make sure every rbyd starts with its revision count // make sure every rbyd starts with its revision count
if (rbyd->eoff == 0) { if (rbyd->eoff == 0) {
err = lfsr_rbyd_appendrev(lfs, rbyd, 0); int err = lfsr_rbyd_appendrev(lfs, rbyd, 0);
if (err) { if (err) {
goto failed; return err;
} }
} }
@@ -2765,7 +2745,7 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
rbyd->block, aligned_eoff, lfs->cfg->prog_size, rbyd->block, aligned_eoff, lfs->cfg->prog_size,
&perturb, 1); &perturb, 1);
if (err && err != LFS_ERR_CORRUPT) { if (err && err != LFS_ERR_CORRUPT) {
goto failed; return err;
} }
// find the expected ecksum, don't bother avoiding a reread of the // find the expected ecksum, don't bother avoiding a reread of the
@@ -2775,7 +2755,7 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
lfs->cfg->prog_size, lfs->cfg->prog_size,
&ecksum.cksum); &ecksum.cksum);
if (err && err != LFS_ERR_CORRUPT) { if (err && err != LFS_ERR_CORRUPT) {
goto failed; return err;
} }
uint8_t ecksum_buf[LFSR_ECKSUM_DSIZE]; uint8_t ecksum_buf[LFSR_ECKSUM_DSIZE];
@@ -2784,15 +2764,14 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
LFSR_TAG_ECKSUM, 0, ecksum_dsize, LFSR_TAG_ECKSUM, 0, ecksum_dsize,
&rbyd->cksum); &rbyd->cksum);
if (d < 0) { if (d < 0) {
err = d; return d;
goto failed;
} }
rbyd->eoff += d; rbyd->eoff += d;
err = lfsr_bd_prog(lfs, rbyd->block, rbyd->eoff, err = lfsr_bd_prog(lfs, rbyd->block, rbyd->eoff,
ecksum_buf, ecksum_dsize, &rbyd->cksum); ecksum_buf, ecksum_dsize, &rbyd->cksum);
if (err) { if (err) {
goto failed; return err;
} }
rbyd->eoff += ecksum_dsize; rbyd->eoff += ecksum_dsize;
@@ -2803,8 +2782,7 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
// not even space for a cksum? we can't finish the commit // not even space for a cksum? we can't finish the commit
} else { } else {
err = LFS_ERR_RANGE; return LFS_ERR_RANGE;
goto failed;
} }
// build end-of-commit cksum // build end-of-commit cksum
@@ -2835,25 +2813,22 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
} }
lfs_tole32_(rbyd->cksum, &cksum_buf[2+1+5]); lfs_tole32_(rbyd->cksum, &cksum_buf[2+1+5]);
err = lfsr_bd_prog(lfs, rbyd->block, rbyd->eoff, cksum_buf, 2+1+5+4, NULL); int err = lfsr_bd_prog(lfs, rbyd->block, rbyd->eoff,
cksum_buf, 2+1+5+4,
NULL);
if (err) { if (err) {
goto failed; return err;
} }
rbyd->eoff += 2+1+5+4; rbyd->eoff += 2+1+5+4;
// flush our caches, finalizing the commit on-disk // flush our caches, finalizing the commit on-disk
err = lfsr_bd_sync(lfs); err = lfsr_bd_sync(lfs);
if (err) { if (err) {
goto failed; return err;
} }
rbyd->eoff = aligned_eoff; rbyd->eoff = aligned_eoff;
return 0; return 0;
failed:;
// if we failed release the pcache
lfs_cache_zero(lfs, &lfs->pcache);
return err;
} }
static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd, static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd,
@@ -2919,17 +2894,15 @@ static int lfsr_rbyd_appendcompactattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
LFS_ASSERT(lfsr_rbyd_isfetched(rbyd)); LFS_ASSERT(lfsr_rbyd_isfetched(rbyd));
// we can't do anything if we're not erased // we can't do anything if we're not erased
int err;
if (rbyd->eoff >= lfs->cfg->block_size) { if (rbyd->eoff >= lfs->cfg->block_size) {
err = LFS_ERR_RANGE; return LFS_ERR_RANGE;
goto failed;
} }
// make sure every rbyd starts with a revision count // make sure every rbyd starts with a revision count
if (rbyd->eoff == 0) { if (rbyd->eoff == 0) {
err = lfsr_rbyd_appendrev(lfs, rbyd, 0); int err = lfsr_rbyd_appendrev(lfs, rbyd, 0);
if (err) { if (err) {
goto failed; return err;
} }
} }
@@ -2938,16 +2911,15 @@ static int lfsr_rbyd_appendcompactattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
tag, weight, lfsr_data_size(&data), tag, weight, lfsr_data_size(&data),
&rbyd->cksum); &rbyd->cksum);
if (d < 0) { if (d < 0) {
err = d; return d;
goto failed;
} }
rbyd->eoff += d; rbyd->eoff += d;
// and the data // and the data
err = lfsr_bd_progdata(lfs, rbyd->block, rbyd->eoff, data, int err = lfsr_bd_progdata(lfs, rbyd->block, rbyd->eoff, data,
&rbyd->cksum); &rbyd->cksum);
if (err) { if (err) {
goto failed; return err;
} }
rbyd->eoff += lfsr_data_size(&data); rbyd->eoff += lfsr_data_size(&data);
@@ -2956,11 +2928,6 @@ static int lfsr_rbyd_appendcompactattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
rbyd->weight += weight; rbyd->weight += weight;
return 0; return 0;
failed:;
// if we failed release the pcache
lfs_cache_zero(lfs, &lfs->pcache);
return err;
} }
static int lfsr_rbyd_appendcompactrbyd(lfs_t *lfs, lfsr_rbyd_t *rbyd_, static int lfsr_rbyd_appendcompactrbyd(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
@@ -3013,7 +2980,6 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
// 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
int err;
while (true) { while (true) {
lfs_off_t layer_off_ = rbyd->eoff; lfs_off_t layer_off_ = rbyd->eoff;
lfs_off_t off = layer_off; lfs_off_t off = layer_off;
@@ -3031,8 +2997,7 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
rbyd->block, off, layer_off_ - off, rbyd->block, off, layer_off_ - off,
&tag, &weight, &size, NULL); &tag, &weight, &size, NULL);
if (d < 0) { if (d < 0) {
err = d; return d;
goto failed;
} }
off += d; off += d;
@@ -3068,8 +3033,7 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
rbyd->eoff - trunk_off, rbyd->eoff - trunk_off,
&rbyd->cksum); &rbyd->cksum);
if (d < 0) { if (d < 0) {
err = d; return d;
goto failed;
} }
rbyd->eoff += d; rbyd->eoff += d;
} }
@@ -3079,8 +3043,7 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
LFSR_TAG_NULL, 0, 0, LFSR_TAG_NULL, 0, 0,
&rbyd->cksum); &rbyd->cksum);
if (d < 0) { if (d < 0) {
err = d; return d;
goto failed;
} }
rbyd->eoff += d; rbyd->eoff += d;
} }
@@ -3094,11 +3057,6 @@ done:;
rbyd->trunk = layer_off; rbyd->trunk = layer_off;
return 0; return 0;
failed:;
// if we failed release the pcache
lfs_cache_zero(lfs, &lfs->pcache);
return err;
} }
// append and consume any pending gstate // append and consume any pending gstate
@@ -4951,13 +4909,9 @@ static int lfsr_mdir_swap(lfs_t *lfs, lfsr_mdir_t *mdir_,
static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir, static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
lfs_ssize_t start_rid, lfs_ssize_t end_rid, lfs_ssize_t start_rid, lfs_ssize_t end_rid,
const lfsr_attr_t *attrs, lfs_size_t attr_count) { const lfsr_attr_t *attrs, lfs_size_t attr_count) {
// TODO do we need to copy here?
// try to append a commit // try to append a commit
lfsr_mdir_t mdir_ = *mdir; lfsr_mdir_t mdir_ = *mdir;
// TODO handle this differently? int err;
// TODO let the lower rbyd layer handle this somehow?
// mark mdir as unerased in case we fail
mdir->u.r.rbyd.eoff = lfs->cfg->block_size;
for (lfs_size_t i = 0; i < attr_count; i++) { for (lfs_size_t i = 0; i < attr_count; i++) {
// calculate adjusted rid // calculate adjusted rid
lfs_ssize_t rid = (attrs[i].rid == -1 lfs_ssize_t rid = (attrs[i].rid == -1
@@ -4980,18 +4934,18 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
} else if (lfsr_tag_suptype(attrs[i].tag) == LFSR_TAG_MOVE) { } else if (lfsr_tag_suptype(attrs[i].tag) == LFSR_TAG_MOVE) {
// weighted moves are not supported // weighted moves are not supported
LFS_ASSERT(attrs[i].delta == 0); LFS_ASSERT(attrs[i].delta == 0);
const lfsr_mdir_t *mdir const lfsr_mdir_t *mdir__
= (const lfsr_mdir_t*)attrs[i].data.u.b.buffer; = (const lfsr_mdir_t*)attrs[i].data.u.b.buffer;
// skip the name tag, this is always replaced by upper layers // skip the name tag, this is always replaced by upper layers
lfsr_tag_t tag = LFSR_TAG_STRUCT-1; lfsr_tag_t tag = LFSR_TAG_STRUCT-1;
while (true) { while (true) {
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_mdir_lookupnext(lfs, mdir, err = lfsr_mdir_lookupnext(lfs, mdir__,
mdir->mid, lfsr_tag_next(tag), mdir__->mid, lfsr_tag_next(tag),
&tag, &data); &tag, &data);
if (err && err != LFS_ERR_NOENT) { if (err && err != LFS_ERR_NOENT) {
return err; goto failed;
} }
if (err == LFS_ERR_NOENT) { if (err == LFS_ERR_NOENT) {
break; break;
@@ -5002,7 +4956,7 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
rid - lfs_smax32(start_rid, 0), rid - lfs_smax32(start_rid, 0),
tag, 0, data); tag, 0, data);
if (err) { if (err) {
return err; goto failed;
} }
} }
@@ -5010,11 +4964,11 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
} else { } else {
LFS_ASSERT(!lfsr_tag_isinternal(attrs[i].tag)); LFS_ASSERT(!lfsr_tag_isinternal(attrs[i].tag));
int err = lfsr_rbyd_appendattr(lfs, &mdir_.u.r.rbyd, err = lfsr_rbyd_appendattr(lfs, &mdir_.u.r.rbyd,
rid - lfs_smax32(start_rid, 0), rid - lfs_smax32(start_rid, 0),
attrs[i].tag, attrs[i].delta, attrs[i].data); attrs[i].tag, attrs[i].delta, attrs[i].data);
if (err) { if (err) {
return err; goto failed;
} }
} }
} }
@@ -5029,45 +4983,47 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
} }
// drop commit if weight goes to zero // don't finish the commit if our weight dropped to zero!
//
// If we finish the commit it becomes immediately visibile, but we really
// need to remove this mdir_ from the mtree. Leave the actual remove up to
// upper layers.
if (mdir_.u.m.weight == 0 if (mdir_.u.m.weight == 0
// unless we are an mroot // unless we are an mroot
&& !(mdir_.mid == -1 || lfsr_mtree_isinlined(lfs))) { && !(mdir_.mid == -1 || lfsr_mtree_isinlined(lfs))) {
// TODO move this up into lfsr_mdir_commit? // mark weight as zero, but note! we can not longer read from this mdir
// consume gstate so we don't lose any info // as our pcache may get clobbered
int err = lfsr_fs_consumegdelta(lfs, mdir); mdir->u.m.weight = 0;
err = LFS_ERR_NOENT;
goto failed;
}
// append any gstate?
if (start_rid == -1) {
err = lfsr_rbyd_appendgdelta(lfs, &mdir_.u.r.rbyd);
if (err) { if (err) {
return err; goto failed;
}
// TODO should we just make our pcache not assert?
// drop our pcache, we're not going to complete this commit
lfs_cache_zero(lfs, &lfs->pcache);
} else {
if (start_rid == -1) {
// only append gstate if we are not dropping
int err = lfsr_rbyd_appendgdelta(lfs, &mdir_.u.r.rbyd);
if (err) {
return err;
}
}
// finalize commit
int err = lfsr_rbyd_appendcksum(lfs, &mdir_.u.r.rbyd);
if (err) {
return err;
}
if (start_rid == -1) {
// success? gstate is committed
lfsr_fs_flushgdelta(lfs);
} }
} }
// update our mdir // finalize commit
*mdir = mdir_; err = lfsr_rbyd_appendcksum(lfs, &mdir_.u.r.rbyd);
if (err) {
goto failed;
}
// success? flush gstate?
if (start_rid == -1) {
lfsr_fs_flushgdelta(lfs);
}
mdir->u.m = mdir_.u.m;
return 0; return 0;
failed:;
// if we failed, mark our mdir as unerased
mdir->u.r.rbyd.eoff = -1;
return err;
} }
static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_, static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
@@ -5127,26 +5083,25 @@ compact:;
return err; return err;
} }
// compact our rbyd // compact our mdir
err = lfsr_mdir_compact__(lfs, &mdir_, start_rid, end_rid, mdir); err = lfsr_mdir_compact__(lfs, &mdir_, start_rid, end_rid, mdir);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
} }
// append any pending attrs // we've compacted, try to commit again
// //
// upper layers should make sure this can't fail by limiting the // upper layers should make sure this can't fail by limiting the
// maximum commit size // maximum commit size
err = lfsr_mdir_commit__(lfs, &mdir_, start_rid, end_rid, *mdir = mdir_;
err = lfsr_mdir_commit__(lfs, mdir, start_rid, end_rid,
attrs, attr_count); attrs, attr_count);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
} }
// update our mdir
*mdir = mdir_;
return 0; return 0;
} }
@@ -5190,7 +5145,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
lfs_size_t split_rid; lfs_size_t split_rid;
int err = lfsr_mdir_commit_(lfs, &mdir_, -1, -1, &split_rid, int err = lfsr_mdir_commit_(lfs, &mdir_, -1, -1, &split_rid,
attrs, attr_count); attrs, attr_count);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE && err != LFS_ERR_NOENT) {
return err; return err;
} }
@@ -5233,7 +5188,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// we do this here so we don't have to worry about corner cases // we do this here so we don't have to worry about corner cases
// with dropping mdirs during a split // with dropping mdirs during a split
} else { } else {
int err = lfsr_fs_consumegdelta(lfs, &mdir_); int err = lfsr_fs_consumegdelta(lfs, mdir);
if (err) { if (err) {
return err; return err;
} }
@@ -5254,7 +5209,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
err = lfsr_mdir_commit__(lfs, &mdir_, 0, split_rid, err = lfsr_mdir_commit__(lfs, &mdir_, 0, split_rid,
attrs, attr_count); attrs, attr_count);
if (err) { if (err && err != LFS_ERR_NOENT) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
} }
@@ -5274,11 +5229,14 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
err = lfsr_mdir_commit__(lfs, &msibling_, split_rid, -1, err = lfsr_mdir_commit__(lfs, &msibling_, split_rid, -1,
attrs, attr_count); attrs, attr_count);
if (err) { if (err && err != LFS_ERR_NOENT) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
} }
// adjust our sibling's mid after committing attrs
msibling_.mid += lfsr_mweight(lfs);
LFS_DEBUG("Splitting mdir %"PRId32".%"PRId32" " LFS_DEBUG("Splitting mdir %"PRId32".%"PRId32" "
"0x{%"PRIx32",%"PRIx32"} " "0x{%"PRIx32",%"PRIx32"} "
"-> 0x{%"PRIx32",%"PRIx32"}, " "-> 0x{%"PRIx32",%"PRIx32"}, "
@@ -5322,27 +5280,19 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
mdir_.mid & lfsr_mbidmask(lfs), mdir_.mid & lfsr_mbidmask(lfs),
mdir_.mid & lfsr_mridmask(lfs), mdir_.mid & lfsr_mridmask(lfs),
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]); mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
lfsr_mdir_t mdir__ = mdir_; mdir_.u.m = msibling_.u.m;
mdir_ = msibling_; msibling_.u.m.weight = 0;
msibling_ = mdir__;
goto relocate; goto relocate;
} }
// no siblings reduced to zero // no siblings reduced to zero, update our mtree
// adjust our sibling's mid, do this here in case other sibling
// was dropped
msibling_.mid += lfsr_mweight(lfs);
// update out mtree
// lookup first name in sibling to use as the split name // lookup first name in sibling to use as the split name
// //
// note we need to do this after playing out pending attrs in // note we need to do this after playing out pending attrs in
// case they introduce a new name! // case they introduce a new name!
lfsr_data_t split_data; lfsr_data_t split_data;
err = lfsr_mdir_lookup(lfs, &msibling_, err = lfsr_rbyd_lookup(lfs, &msibling_.u.r.rbyd, 0, LFSR_TAG_WIDE(NAME),
msibling_.mid & lfsr_mbidmask(lfs), LFSR_TAG_WIDE(NAME),
NULL, &split_data); NULL, &split_data);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -5376,15 +5326,19 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
dirtymtree = true; dirtymtree = true;
// mdir reduced to zero? need to drop? // mdir reduced to zero? need to drop?
} else if (mdir_.u.m.weight == 0 } else if (err == LFS_ERR_NOENT) {
// unless we are an mroot
&& !(mdir->mid == -1 || lfsr_mtree_isinlined(lfs))) {
LFS_DEBUG("Dropping mdir %"PRId32".%"PRId32" " LFS_DEBUG("Dropping mdir %"PRId32".%"PRId32" "
"0x{%"PRIx32",%"PRIx32"}", "0x{%"PRIx32",%"PRIx32"}",
mdir->mid & lfsr_mbidmask(lfs), mdir->mid & lfsr_mbidmask(lfs),
mdir->mid & lfsr_mridmask(lfs), mdir->mid & lfsr_mridmask(lfs),
mdir->u.m.blocks[0], mdir->u.m.blocks[1]); mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
// consume gstate so we don't lose any info
err = lfsr_fs_consumegdelta(lfs, mdir);
if (err) {
return err;
}
drop:; drop:;
// update our mtree // update our mtree
int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS( int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS(
@@ -5518,6 +5472,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
TAG(mtree_tag), 0, BUF(mtree_buf, mtree_dsize)))); TAG(mtree_tag), 0, BUF(mtree_buf, mtree_dsize))));
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
LFS_ASSERT(err != LFS_ERR_NOENT);
return err; return err;
} }
@@ -5557,6 +5512,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
MROOT, 0, BUF(mchildroot_buf, mchildroot_dsize)))); MROOT, 0, BUF(mchildroot_buf, mchildroot_dsize))));
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
LFS_ASSERT(err != LFS_ERR_NOENT);
return err; return err;
} }
@@ -5631,6 +5587,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
LFSR_ATTR(-1, LFSR_ATTR(-1,
WIDE(MROOT), 0, BUF(mchildroot_buf, mchildroot_dsize)))); WIDE(MROOT), 0, BUF(mchildroot_buf, mchildroot_dsize))));
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT);
return err; return err;
} }
} }