Fixed mroot chain commits not working

Maybe the subject line should say "Implemented", because these never
worked in the first place. Unfortunately our tests missed this due to a
couple reasons:

- Mroot chains are difficult to create due to the required exponential
  growth.

- The only thing that actually commits to chain mroots is mdir
  compaction. Though this functionality will be useful for future block
  eviction/error correction.

- Previous revision count issues were making relocations in our
  compaction tests unlikely.

Fortunately, now that revision count behavior is more correct, our tests
are correctly highlighting that this is broken.

---

Implementing chain mroot commits was a bit intimidating, but fortunately
it just required a bit of teasing to get lfs3_mdir_commit_ to trigger
the tail-recursive mroot chain update when the mdir is a non-active
mroot.

The gcksum is also doing a great job here with identifying bugs. Without
it this bug would have been difficult to notice, since compactions
otherwise have no observable effect on the system.

Code changes:

                    code          stack          ctx
  before:          35164           2136          660
  after:           35224 (+0.2%)   2136 (+0.0%)  660 (+0.0%)

                    code          stack          ctx
  gbmap before:    38400           2144          776
  gbmap after:     38464 (+0.2%)   2144 (+0.0%)  776 (+0.0%)

                    code          stack          ctx
  preerase before: 38940           2168          796
  preerase after:  39008 (+0.2%)   2168 (+0.0%)  796 (+0.0%)
This commit is contained in:
Christopher Haster
2025-12-31 13:26:59 -06:00
parent 9c7f2d788f
commit 5fb3600d90
2 changed files with 190 additions and 20 deletions
+18 -8
View File
@@ -9140,7 +9140,8 @@ static int lfs3_mdir_commit_(lfs3_t *lfs3, lfs3_mdir_t *mdir,
// need to relocate?
} else if (lfs3_mdir_cmp(&mdir_[0], mdir) != 0
&& lfs3_mdir_cmp(mdir, &lfs3->mroot) != 0) {
&& lfs3_mdir_cmp(mdir, &lfs3->mroot) != 0
&& mdir->mid > -1) {
LFS3_INFO("Relocating mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"} "
"-> 0x{%"PRIx32",%"PRIx32"}",
lfs3_dbgmbid(lfs3, mdir->mid),
@@ -9230,10 +9231,18 @@ static int lfs3_mdir_commit_(lfs3_t *lfs3, lfs3_mdir_t *mdir,
}
// need to update mroot chain?
if (lfs3_mdir_cmp(&mroot_, &lfs3->mroot) != 0) {
if (lfs3_mdir_cmp(&mroot_, &lfs3->mroot) != 0
|| (mdelta == 0 && mdir->mid <= -1)) {
// tail recurse, updating mroots until a commit sticks
lfs3_mdir_t mrootchild = lfs3->mroot;
lfs3_mdir_t mrootchild_ = mroot_;
lfs3_mdir_t mrootchild;
lfs3_mdir_t mrootchild_;
if (lfs3_mdir_cmp(&mroot_, &lfs3->mroot) != 0) {
mrootchild = lfs3->mroot;
mrootchild_ = mroot_;
} else {
mrootchild = *mdir;
mrootchild_ = mdir_[0];
}
while (lfs3_mdir_cmp(&mrootchild_, &mrootchild) != 0
&& !lfs3_mdir_ismrootanchor(&mrootchild)) {
// find the mroot's parent
@@ -9370,8 +9379,12 @@ static int lfs3_mdir_commit_(lfs3_t *lfs3, lfs3_mdir_t *mdir,
continue;
}
// update any mroots, this clobbers chain mroots but that's
// better than letting them point to garbage
if (h->mdir.mid <= -1) {
lfs3_mdir_sync(&h->mdir, &mroot_);
// update any splits/drops
if (lfs3_mdir_cmp(&h->mdir, mdir) == 0) {
} else if (lfs3_mdir_cmp(&h->mdir, mdir) == 0) {
if (mdelta > 0
&& lfs3_mrid(lfs3, h->mdir.mid)
>= (lfs3_srid_t)mdir_[0].r.weight) {
@@ -9382,9 +9395,6 @@ static int lfs3_mdir_commit_(lfs3_t *lfs3, lfs3_mdir_t *mdir,
}
} else if (h->mdir.mid > mdir->mid) {
h->mdir.mid += mdelta;
// and any mroot updates, though this clobbers chain mroots
} else if (h->mdir.mid <= -1) {
lfs3_mdir_sync(&h->mdir, &mroot_);
}
}