Fixed mroot commit conditions that relied on mdelta==0

This was broken. The good news is this was easily detected by our
test_mtree tests.

The problem is that mroot split + drop (resulting in an mtree with one
mdir) is indistinguishable from mroot relocation via mdelta. Both cases
have an mdelta of 0.

This also breaks the later mid-mdir update if we wanted to stay on the
current chain mroot.

The tricky part is we have several entangled cases:

- mdir=active mroot, mid>=0  - follow mdir_
- mdir=active mroot, mid<=-1 - follow mroot_, not mdir_!
- mdir=chain mroot, mid<=-1  - follow mdir_, not mroot_!

---

It's tempting to rely on mid<=-2 vs mid==-1 for chain mroots vs active
mroot, but this doesn't always work! During traversals mid is always
<=-2, in part because we don't actually know if the current mroot is the
active mroot until we try to lookup its child.

Fortunately, what _does_ work is just comparing against the mroot's
blocks, which we know.

Though the continued reliance and reliability of mptr comparisons makes
me wonder if it's possible to simplify said function...

Code changes:

                    code          stack          ctx
  before:          35224           2136          660
  after:           35260 (+0.1%)   2136 (+0.0%)  660 (+0.0%)

                    code          stack          ctx
  gbmap before:    38464           2144          776
  gbmap after:     38492 (+0.1%)   2144 (+0.0%)  776 (+0.0%)

                    code          stack          ctx
  preerase before: 39008           2168          796
  preerase after:  39036 (+0.1%)   2168 (+0.0%)  796 (+0.0%)
This commit is contained in:
Christopher Haster
2025-12-31 14:10:52 -06:00
parent 5fb3600d90
commit a9c18862c6
+2 -3
View File
@@ -9232,7 +9232,7 @@ static int lfs3_mdir_commit_(lfs3_t *lfs3, lfs3_mdir_t *mdir,
// need to update mroot chain? // 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)) { || (mdir->mid <= -1 && lfs3_mdir_cmp(mdir, &lfs3->mroot) != 0)) {
// tail recurse, updating mroots until a commit sticks // tail recurse, updating mroots until a commit sticks
lfs3_mdir_t mrootchild; lfs3_mdir_t mrootchild;
lfs3_mdir_t mrootchild_; lfs3_mdir_t mrootchild_;
@@ -9399,8 +9399,7 @@ static int lfs3_mdir_commit_(lfs3_t *lfs3, lfs3_mdir_t *mdir,
} }
// update mdir to follow requested rid // update mdir to follow requested rid
if (mdelta > 0 if (mdir->mid <= -1 && lfs3_mdir_cmp(mdir, &lfs3->mroot) == 0) {
&& mdir->mid <= -1) {
lfs3_mdir_sync(mdir, &mroot_); lfs3_mdir_sync(mdir, &mroot_);
} else if (mdelta > 0 } else if (mdelta > 0
&& lfs3_mrid(lfs3, mdir->mid) && lfs3_mrid(lfs3, mdir->mid)