From 30a9a6262073dcaa16be92a04ffb070f5e9e90cc Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 24 Nov 2023 22:24:14 -0600 Subject: [PATCH] Heavily reworked lfsr_mdir_commit, split into more mid-level functions Originally, the intention of this rework was to make it possible to shrub the mtree, i.e. allow an mshrub, i.e. inline the root rbyd of the mtree to be inlined in the mroot. This would allow small mtrees, 2, 3, etc mdirs, to save a block that would be needed for the mtree's root. But as the mshrub was progressing, minor problems kept unfolding, and ultimately I've decided to shelve the idea of mshrubs for now. They add quite a bit of complexity for relatively little gain: - bshrubs are just complicated to update. They require a call to lfsr_mdir_commit to update the inlined-root, which is a bit of a problem when your mshrub needs to be updated inside lfsr_mdir_commit, and your system disallows recursion... Recursion _can_ be avoided by separate bshrub commit variants that go through either lfsr_mdir_commit or lfsr_mdir_commit_, but this complicates things and requires some code duplication, weakening the value of reusing the bshrub data-structure. - It's not always possible to compact the mshrub's backing mroot when we need to modify the mshrub. If an mroot becomes full and needs to split, for example, we need to allocate the new mdirs, update the (new) mshrub, and then commit everything into the mroot when we compact. But the "update the (new) mshrub" step can't be done until after we compact, because the mroot is by definition full. This _can_ also be worked around, by building an attr list containing all of the mshrub changes, and committing the mshrub/mroot changes in the same transaction, but this complicates things and increases the stack cost for the current hot-path. - Every shrub needs a configurable shrub size, and the mshrub is no exception. This adds another config option and complicates shared shrub eviction code. - The value for mshrubs is not actually that great. Unlike file bshrubs, there's only one mshrub in the filesystem, and I'm not sure there's a situation where a filesystem has >1 mdirs and the exact number of allocated blocks is critical. And this complexity is reflected in code cost and robustness, not to mention developer time. I think for littlefs this is just not worth doing. At least not now. We can always introduce mshrubs in a backwards compatible manner if needed. --- But this rework did lead to better code organization around mdir commits and how they update the mtree/mroot, so I'm keeping those changes. In general lfsr_mdir_commit has been broken up into mtree/mroot specific functions that _do_ propagate in-device changes. Any commit to the mroot changes the on-disk state of the filesystem anyways, so the mroot commit _must_ be the last thing lfsr_mdir_commit does. This leads to some duplicated updates, but that's not really a problem. Here's the new call graph inside lfsr_mdir_commit: lfsr_mdir_commit .---------' | | | '-----------------. v | | '-----------------. | lfsr_mtree_commit | '--------. | | '---------. | | | | v v | | | lfsr_mroot_commit | | | | '--------. | | | | v v | | | lfsr_mdir_commit_ | | | .--------' '--------. | | | | .-----------------|-' | v v v v v lfsr_mdir_commit__ lfsr_mdir_compact__ This rework didn't really impact code/stack that much. It added a bit of code, but saved a bit of RAM. The real value is that the narrower-scoped functions contain more focused logic: code stack before: 30780 2504 after: 31096 (+1.0%) 2480 (-1.0%) --- lfs.c | 883 ++++++++++++++++++++++++------------------ tests/test_mtree.toml | 140 +++---- 2 files changed, 568 insertions(+), 455 deletions(-) diff --git a/lfs.c b/lfs.c index d8e0cda0..f3cb4994 100644 --- a/lfs.c +++ b/lfs.c @@ -4634,6 +4634,9 @@ typedef struct lfsr_binfo { static int lfsr_btree_traverse(lfs_t *lfs, const lfsr_btree_t *btree, lfsr_btraversal_t *btraversal, lfsr_binfo_t *binfo) { + // this shouldn't happen + LFS_ASSERT(btree->trunk != 0); + while (true) { // in range? if (btraversal->bid >= (lfsr_bid_t)btree->weight @@ -4836,10 +4839,13 @@ static int lfsr_bshrub_commit(lfs_t *lfs, // parents, splits, etc // if (attr_count > 0) { - // set bshrub to the mdir's block in case this is a new bshrub - LFS_ASSERT(bshrub->rbyd.trunk == 0 - || bshrub->rbyd.block == mdir->u.rbyd.block); - bshrub->rbyd.block = mdir->u.rbyd.block; + // new bshrub? + if (bshrub->rbyd.trunk == 0) { + err = lfsr_bshrub_alloc(lfs, mdir, bshrub); + if (err) { + return err; + } + } // we need to prevent our shrub from overflowing our mdir somehow // @@ -4935,16 +4941,6 @@ evict:; return 0; } -static lfs_scmp_t lfsr_bshrub_namelookup(lfs_t *lfs, - const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub, - lfsr_did_t did, const char *name, lfs_size_t name_size, - lfsr_bid_t *bid_, - lfsr_tag_t *tag_, lfsr_bid_t *weight_, lfsr_data_t *data_) { - (void)mdir; - return lfsr_btree_namelookup(lfs, &bshrub->rbyd, did, name, name_size, - bid_, tag_, weight_, data_); -} - static int lfsr_bshrub_traverse(lfs_t *lfs, const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub, lfsr_btraversal_t *btraversal, @@ -5182,24 +5178,30 @@ static int lfsr_fs_consumegdelta(lfs_t *lfs, const lfsr_mdir_t *mdir) { // mtree is the core tree of mdirs in littlefs -#define LFSR_MTREE_MPTR 0x80000000 +// TODO should other flags have IS* prefix? +#define LFSR_MTREE_ISMPTR 0x80000000 -#define LFSR_MTREE_NULL ((lfsr_mtree_t){.u.weight=(LFSR_MTREE_MPTR | 0)}) +#define LFSR_MTREE_NULL ((lfsr_mtree_t){ \ + .u.weight=(LFSR_MTREE_ISMPTR | 0)}) + +#define LFSR_MTREE_MPTR(_mptr, _weight) ((lfsr_mtree_t){ \ + .u.mptr.weight=(LFSR_MTREE_ISMPTR | (_weight)), \ + .u.mptr.mptr=_mptr}) static inline bool lfsr_mtree_isnull(const lfsr_mtree_t *mtree) { - return (lfsr_mid_t)mtree->u.weight == (LFSR_MTREE_MPTR | 0); + return (lfsr_mid_t)mtree->u.weight == (LFSR_MTREE_ISMPTR | 0); } static inline bool lfsr_mtree_ismptr(const lfsr_mtree_t *mtree) { - return mtree->u.weight & LFSR_MTREE_MPTR; + return mtree->u.weight & LFSR_MTREE_ISMPTR; } static inline bool lfsr_mtree_isbtree(const lfsr_mtree_t *mtree) { - return !(mtree->u.weight & LFSR_MTREE_MPTR); + return !(mtree->u.weight & LFSR_MTREE_ISMPTR); } static inline lfsr_mid_t lfsr_mtree_weight(const lfsr_mtree_t *mtree) { - return mtree->u.weight & ~LFSR_MTREE_MPTR; + return mtree->u.weight & ~LFSR_MTREE_ISMPTR; } static inline int lfsr_mtree_cmp( @@ -5216,12 +5218,6 @@ static inline int lfsr_mtree_cmp( } } -// make sure this can fit both a direct mdir and indirect mtree -#define LFSR_MTREE_DSIZE ( \ - LFSR_MPTR_DSIZE > LFSR_BTREE_DSIZE \ - ? LFSR_MPTR_DSIZE \ - : LFSR_BTREE_DSIZE) - static int lfsr_mtree_lookup(lfs_t *lfs, const lfsr_mtree_t *mtree, lfsr_smid_t mid, lfsr_mdir_t *mdir_) { // looking up mroot? @@ -5267,43 +5263,6 @@ static int lfsr_mtree_lookup(lfs_t *lfs, const lfsr_mtree_t *mtree, } } -static int lfsr_mroot_parent(lfs_t *lfs, const lfsr_mptr_t *mptr, - lfsr_mdir_t *mparent_) { - // we only call this when we actually have parents - LFS_ASSERT(!lfsr_mptr_ismrootanchor(mptr)); - - // scan list of mroots for our requested pair - lfsr_mptr_t mptr_ = LFSR_MPTR_MROOTANCHOR(); - while (true) { - // fetch next possible superblock - lfsr_mdir_t mdir; - int err = lfsr_mdir_fetch(lfs, &mdir, -1, &mptr_); - if (err) { - return err; - } - - // lookup next mroot - lfsr_data_t data; - err = lfsr_mdir_lookup(lfs, &mdir, -1, LFSR_TAG_MROOT, NULL, &data); - if (err) { - LFS_ASSERT(err != LFS_ERR_NOENT); - return err; - } - - // decode mdir - err = lfsr_data_readmptr(lfs, &data, &mptr_); - if (err) { - return err; - } - - // found our child? - if (lfsr_mptr_cmp(&mptr_, mptr) == 0) { - *mparent_ = mdir; - return 0; - } - } -} - static int lfsr_mtree_seek(lfs_t *lfs, const lfsr_mtree_t *mtree, lfsr_mdir_t *mdir, lfs_off_t off) { // upper layers should handle removed mdirs @@ -5447,7 +5406,7 @@ static int lfsr_mdir_swap(lfs_t *lfs, lfsr_mdir_t *mdir_, // needed in lfsr_mdir_commit and friends -static inline bool lfsr_file_isnull(const lfsr_file_t *file); +static inline bool lfsr_file_isbnull(const lfsr_file_t *file); static inline bool lfsr_file_isbsprout(const lfsr_file_t *file); static inline bool lfsr_file_isbptr(const lfsr_file_t *file); static inline bool lfsr_file_isbshrub(const lfsr_file_t *file); @@ -5683,7 +5642,7 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_, opened; opened = opened->next) { lfsr_file_t *file = (lfsr_file_t*)opened; - if (lfsr_file_isbsprout(file) && lfsr_file_uweight(file) > 0 + if (lfsr_file_isbsprout(file) && file->u.bsprout.data.u.disk.block == data.u.disk.block && file->u.bsprout.data.u.disk.off @@ -5777,13 +5736,12 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_, lfsr_file_t *file = (lfsr_file_t*)opened; // belongs to our mdir? if (lfsr_file_isunsynced(file) - && (file->m.mdir.mid & lfsr_midbmask(lfs)) - == (mdir->mid & lfsr_midbmask(lfs)) + && lfsr_mdir_cmp(&file->m.mdir, mdir) == 0 && (file->m.mdir.mid & lfsr_midrmask(lfs)) >= start_rid && (lfs_size_t)(file->m.mdir.mid & lfsr_midrmask(lfs)) < (lfs_size_t)end_rid) { // inlined sprout? - if (lfsr_file_isbsprout(file) && lfsr_file_uweight(file) > 0) { + if (lfsr_file_isbsprout(file)) { // write the data as a shrub tag err = lfsr_rbyd_appendcompactattr(lfs, &mdir_->u.rbyd, LFSR_TAG_SHRUB(DATA), 0, file->u.bsprout.data); @@ -5897,11 +5855,9 @@ static lfs_ssize_t lfsr_mdir_estimate_(lfs_t *lfs, const lfsr_mdir_t *mdir, lfsr_file_t *file = (lfsr_file_t*)opened; // belongs to our mdir? if (lfsr_file_isunsynced(file) - && (file->m.mdir.mid & lfsr_midbmask(lfs)) - == (mdir->mid & lfsr_midbmask(lfs)) - && (file->m.mdir.mid & lfsr_midrmask(lfs)) == rid) { + && lfsr_mdir_cmp(&file->m.mdir, mdir) == 0) { // inlined sprout? - if (lfsr_file_isbsprout(file) && lfsr_file_uweight(file) > 0) { + if (lfsr_file_isbsprout(file)) { dsize += LFSR_TAG_DSIZE + lfsr_data_size(&file->u.bsprout.data); @@ -6041,18 +5997,277 @@ compact:; return 0; } +static int lfsr_mroot_parent(lfs_t *lfs, const lfsr_mptr_t *mptr, + lfsr_mdir_t *mparent_) { + // we only call this when we actually have parents + LFS_ASSERT(!lfsr_mptr_ismrootanchor(mptr)); + + // scan list of mroots for our requested pair + lfsr_mptr_t mptr_ = LFSR_MPTR_MROOTANCHOR(); + while (true) { + // fetch next possible superblock + lfsr_mdir_t mdir; + int err = lfsr_mdir_fetch(lfs, &mdir, -1, &mptr_); + if (err) { + return err; + } + + // lookup next mroot + lfsr_data_t data; + err = lfsr_mdir_lookup(lfs, &mdir, -1, LFSR_TAG_MROOT, NULL, &data); + if (err) { + LFS_ASSERT(err != LFS_ERR_NOENT); + return err; + } + + // decode mdir + err = lfsr_data_readmptr(lfs, &data, &mptr_); + if (err) { + return err; + } + + // found our child? + if (lfsr_mptr_cmp(&mptr_, mptr) == 0) { + *mparent_ = mdir; + return 0; + } + } +} + +// mid-level mroot commit +// +// this is atomic and propagates any mroot changes up the mroot chain +// +// note! this does not handle uninlining/gstate/etc! actual commits +// to the mroot should go through lfsr_mdir_commit with lfs->mroot as +// a target +// +static int lfsr_mroot_commit_(lfs_t *lfs, + lfsr_srid_t start_rid, lfsr_srid_t end_rid, + lfsr_srid_t *split_rid_, + const lfsr_attr_t *attrs, lfs_size_t attr_count) { + // create a copy + lfsr_mdir_t mroot_ = lfs->mroot; + + // mark any copies of our mroot as unerased + lfsr_mdir_unerase(&lfs->mroot); + + for (int type = LFS_TYPE_REG; type < LFS_TYPE_REG+3; type++) { + for (lfsr_openedmdir_t *opened = lfs->opened[type-LFS_TYPE_REG]; + opened; + opened = opened->next) { + if (lfsr_mdir_cmp(&opened->mdir, &lfs->mroot) == 0) { + lfsr_mdir_unerase(&opened->mdir); + } + } + } + + // try to commit to the mroot + int err = lfsr_mdir_commit_(lfs, &mroot_, + start_rid, end_rid, split_rid_, + attrs, attr_count); + if (err) { + return err; + } + + // need to update mroot chain? tail recurse, updating mroots until a + // commit sticks + lfsr_mdir_t mrootchild = lfs->mroot; + lfsr_mdir_t mrootchild_ = mroot_; + while (lfsr_mdir_cmp(&mrootchild_, &mrootchild) != 0 + && !lfsr_mdir_ismrootanchor(&mrootchild)) { + // find the mroot's parent + lfsr_mdir_t mrootparent_; + err = lfsr_mroot_parent(lfs, lfsr_mdir_mptr(&mrootchild), + &mrootparent_); + if (err) { + LFS_ASSERT(err != LFS_ERR_NOENT); + return err; + } + + LFS_DEBUG("Relocating mroot 0x{%"PRIx32",%"PRIx32"} " + "-> 0x{%"PRIx32",%"PRIx32"}", + mrootchild.u.m.blocks[0], mrootchild.u.m.blocks[1], + mrootchild_.u.m.blocks[0], mrootchild_.u.m.blocks[1]); + + mrootchild = mrootparent_; + + // commit mrootchild + uint8_t mrootchild_buf[LFSR_MPTR_DSIZE]; + err = lfsr_mdir_commit_(lfs, &mrootparent_, -1, -1, NULL, LFSR_ATTRS( + LFSR_ATTR(-1, + MROOT, 0, + FROMMPTR(lfsr_mdir_mptr(&mrootchild_), mrootchild_buf)))); + if (err) { + LFS_ASSERT(err != LFS_ERR_RANGE); + LFS_ASSERT(err != LFS_ERR_NOENT); + return err; + } + + mrootchild_ = mrootparent_; + } + + // uh oh, we ran out of mroot parents, need to extend mroot chain + if (lfsr_mdir_cmp(&mrootchild_, &mrootchild) != 0) { + // mrootchild should be our previous mroot anchor at this point + LFS_ASSERT(lfsr_mdir_ismrootanchor(&mrootchild)); + LFS_DEBUG("Extending mroot 0x{%"PRIx32",%"PRIx32"}" + " -> 0x{%"PRIx32",%"PRIx32"}" + ", 0x{%"PRIx32",%"PRIx32"}", + mrootchild.u.m.blocks[0], mrootchild.u.m.blocks[1], + mrootchild.u.m.blocks[0], mrootchild.u.m.blocks[1], + mrootchild_.u.m.blocks[0], mrootchild_.u.m.blocks[1]); + + // compact into the new mroot anchor + lfsr_mdir_t mrootanchor_; + err = lfsr_mdir_swap(lfs, &mrootanchor_, &mrootchild, -1); + if (err) { + return err; + } + + // copy only the config over + lfsr_tag_t tag = 0; + while (true) { + lfsr_srid_t rid; + lfsr_rid_t weight; + lfsr_data_t data; + err = lfsr_rbyd_lookupnext(lfs, &mrootchild.u.rbyd, + -1, tag+1, + &rid, &tag, &weight, &data); + if (err) { + if (err == LFS_ERR_NOENT) { + break; + } + return err; + } + if (rid != -1 || lfsr_tag_suptype(tag) != LFSR_TAG_CONFIG) { + break; + } + + // write the tag + err = lfsr_rbyd_appendcompactattr(lfs, &mrootanchor_.u.rbyd, + tag, weight, data); + if (err) { + LFS_ASSERT(err != LFS_ERR_RANGE); + return err; + } + } + + err = lfsr_rbyd_compact(lfs, &mrootanchor_.u.rbyd, false, + sizeof(uint32_t)); + if (err) { + LFS_ASSERT(err != LFS_ERR_RANGE); + return err; + } + + // and commit our new mroot + uint8_t mrootchild_buf[LFSR_MPTR_DSIZE]; + err = lfsr_mdir_commit__(lfs, &mrootanchor_, -1, -1, LFSR_ATTRS( + LFSR_ATTR(-1, + WIDE(MROOT), 0, + FROMMPTR(lfsr_mdir_mptr(&mrootchild_), mrootchild_buf)))); + if (err) { + LFS_ASSERT(err != LFS_ERR_RANGE); + LFS_ASSERT(err != LFS_ERR_NOENT); + return err; + } + } + + // success? update in-device state, we must not error at this point + + for (int type = LFS_TYPE_REG; type < LFS_TYPE_REG+3; type++) { + for (lfsr_openedmdir_t *opened = lfs->opened[type-LFS_TYPE_REG]; + opened; + opened = opened->next) { + if (lfsr_mdir_cmp(&opened->mdir, &lfs->mroot) == 0) { + // update any bsprouts/bshrubs, note this must happen + // before we update the mdir + if (type == LFS_TYPE_REG) { + lfsr_file_t *file = (lfsr_file_t*)opened; + if (lfsr_file_isbsprout(file)) { + file->u.bsprout.data = file->u.bsprout.data_; + } else if (lfsr_file_isbshrub(file)) { + file->u.bshrub.rbyd = file->u.bshrub.rbyd_; + } + } + + // update any opened mdirs in our mroot + opened->mdir.u.m = mroot_.u.m; + } + } + } + + // and save our new mroot + lfs->mroot = mroot_; + return 0; +} + +// high-level mtree commit +// +// this is atomic and propagates any mroot changes up the mroot chain +// +// TODO remove mtree param? +// +static int lfsr_mtree_commit(lfs_t *lfs, lfsr_mtree_t *mtree, + const lfsr_attr_t *attrs, lfs_size_t attr_count) { + lfsr_btree_t mtree_; + // new mtree? + if (lfsr_mtree_ismptr(mtree)) { + int err = lfsr_btree_alloc(lfs, &mtree_); + if (err) { + return err; + } + + } else { + // create a copy + mtree_ = mtree->u.btree; + + // mark as unerased in case of failure + lfsr_btree_unerase(&mtree->u.btree); + } + + // commit to mtree + int err = lfsr_btree_commit(lfs, &mtree_, attrs, attr_count); + if (err) { + return err; + } + + // mtree should never go to zero since we will always have a + // root bookmark + LFS_ASSERT(mtree_.weight > 0); + + // commit new mtree into our mroot + // + // Note if we every have an mtree, mroot should have no files, + // so we set end_rid=0 here which will delete any files. Above + // layers rely on this. + // + uint8_t mtree_buf[LFSR_BTREE_DSIZE]; + err = lfsr_mroot_commit_(lfs, -1, 0, NULL, LFSR_ATTRS( + LFSR_ATTR(-1, + WIDE(MTREE), 0, FROMBTREE(&mtree_, mtree_buf)))); + if (err) { + LFS_ASSERT(err != LFS_ERR_RANGE); + return err; + } + + // success? update in-device state, we must not error at this point + + // save our new mtree + mtree->u.btree = mtree_; + return 0; +} // high-level mdir commit // -// this is also responsible for updating any opened mdirs, lfs_t, gstate, etc +// this is atomic and updates any opened mdirs, lfs_t, gstate, etc // static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, const lfsr_attr_t *attrs, lfs_size_t attr_count) { - const lfsr_smid_t mid = mdir->mid; - LFS_ASSERT(mid == -1 + LFS_ASSERT(mdir->mid == -1 || lfsr_mtree_isnull(&lfs->mtree) || mdir->u.m.weight > 0); - LFS_ASSERT(mid == -1 + LFS_ASSERT(mdir->mid == -1 || (mdir->mid & lfsr_midrmask(lfs)) <= mdir->u.m.weight); // parse out any pending gstate, these will get automatically xored @@ -6073,64 +6288,78 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } } + // stage any bsprouts/bshrubs + // create a copy lfsr_mdir_t mdir_ = *mdir; - // mark the mdir as unerased in case we fail - lfsr_mdir_unerase(mdir); - // and all related copies flying around - if (mid == -1 || lfsr_mtree_isnull(&lfs->mtree)) { - lfsr_mdir_unerase(&lfs->mroot); - } + for (int type = LFS_TYPE_REG; type < LFS_TYPE_REG+3; type++) { for (lfsr_openedmdir_t *opened = lfs->opened[type-LFS_TYPE_REG]; opened; opened = opened->next) { - if ((opened->mdir.mid & lfsr_midbmask(lfs)) - == (lfs_smax32(mid, 0) & lfsr_midbmask(lfs))) { + // mark any copies of our mdir as unerased in case we fail + // + // note we need to not mark the mroot as unerased, because that + // would force the mroot to always compact + // + if (lfsr_mdir_cmp(&opened->mdir, mdir) == 0) { lfsr_mdir_unerase(&opened->mdir); } - } - } - // stage all bsprouts/bshrubs - // - // TODO merge with above? - for (lfsr_openedmdir_t *opened = lfs->opened[LFS_TYPE_REG-LFS_TYPE_REG]; - opened; - opened = opened->next) { - lfsr_file_t *file = (lfsr_file_t*)opened; - if (lfsr_file_isbsprout(file)) { - file->u.bsprout.data_ = file->u.bsprout.data; - } else if (lfsr_file_isbshrub(file)) { - file->u.bshrub.rbyd_ = file->u.bshrub.rbyd; + // stage all bsprouts/bshrubs + if (type == LFS_TYPE_REG) { + lfsr_file_t *file = (lfsr_file_t*)opened; + if (lfsr_file_isbsprout(file)) { + file->u.bsprout.data_ = file->u.bsprout.data; + } else if (lfsr_file_isbshrub(file)) { + file->u.bshrub.rbyd_ = file->u.bshrub.rbyd; + } + } } } // attempt to commit/compact the mdir normally lfsr_srid_t split_rid; - int err = lfsr_mdir_commit_(lfs, &mdir_, -1, -1, &split_rid, - attrs, attr_count); - if (err && err != LFS_ERR_RANGE && err != LFS_ERR_NOENT) { - return err; + int err; + // mroot? we need special handling to propagate up the mroot chain + if (lfsr_mdir_cmp(&mdir_, &lfs->mroot) == 0) { + err = lfsr_mroot_commit_(lfs, -1, -1, &split_rid, + attrs, attr_count); + if (err && err != LFS_ERR_RANGE + && err != LFS_ERR_NOENT) { + return err; + } + + // keep mdir_ in sync with mroot + mdir_.u.m = lfs->mroot.u.m; + + // otherwise commit normally + } else { + // mark our mdir as unerased in case we fail + lfsr_mdir_unerase(mdir); + + err = lfsr_mdir_commit_(lfs, &mdir_, -1, -1, &split_rid, + attrs, attr_count); + if (err && err != LFS_ERR_RANGE + && err != LFS_ERR_NOENT) { + return err; + } } // handle possible mtree updates, this gets a bit messy - lfsr_mdir_t msibling_ = {.u.m.weight=0}; - lfsr_mdir_t mroot_ = (mid == -1 || lfsr_mtree_isnull(&lfs->mtree) - ? mdir_ - : lfs->mroot); - lfsr_mtree_t mtree_ = lfs->mtree; + lfsr_mdir_t msibling_; + lfsr_smid_t mdelta = 0; // need to split? if (err == LFS_ERR_RANGE) { // this should not happen unless we can't fit our mroot's metadata - LFS_ASSERT(mid != -1 || lfsr_mtree_isnull(&lfs->mtree)); + LFS_ASSERT(mdir->mid != -1 || lfsr_mtree_isnull(&lfs->mtree)); // if we're not the mroot, we need to consume the gstate so // we don't lose any info during the split // // we do this here so we don't have to worry about corner cases // with dropping mdirs during a split - if (!lfsr_mtree_isnull(&mtree_)) { + if (!lfsr_mtree_isnull(&lfs->mtree)) { err = lfsr_fs_consumegdelta(lfs, mdir); if (err) { return err; @@ -6139,7 +6368,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // compact into new mdir tags < split_rid err = lfsr_mdir_alloc(lfs, &mdir_, - lfs_smax32(mid, 0)); + lfs_smax32(mdir->mid, 0)); if (err) { return err; } @@ -6159,7 +6388,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // compact into new mdir tags >= split_rid err = lfsr_mdir_alloc(lfs, &msibling_, - lfs_smax32(mid, 0)); + lfs_smax32(mdir->mid, 0)); if (err) { return err; } @@ -6184,7 +6413,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, "0x{%"PRIx32",%"PRIx32"} " "-> 0x{%"PRIx32",%"PRIx32"}, " "0x{%"PRIx32",%"PRIx32"}", - mid >> lfs->mleaf_bits, + mdir->mid >> lfs->mleaf_bits, mdir->u.m.blocks[0], mdir->u.m.blocks[1], mdir_.u.m.blocks[0], mdir_.u.m.blocks[1], msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]); @@ -6219,11 +6448,53 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, mdir_.mid >> lfs->mleaf_bits, mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]); mdir_.u.m = msibling_.u.m; - msibling_.u.m.weight = 0; goto relocate; } // no siblings reduced to zero, update our mtree + mdelta = +lfsr_mleafweight(lfs); + + // fix any pending grms + for (lfs_size_t i = 0; i < attr_count; i++) { + if (attrs[i].tag == LFSR_TAG_GRM) { + // Assuming we already xored our gdelta with the grm, we first + // need to xor the grm out of the gdelta. We can't just zero + // the gdelta because we may have picked up extra gdelta from + // split/dropped mdirs + // + // gd' = gd xor (grm' xor grm) + // + lfsr_grm_t *grm = (lfsr_grm_t*)attrs[i].data.u.buf.buffer; + uint8_t grm_buf[LFSR_GRM_DSIZE]; + err = lfsr_grm_xor(lfs, lfs->dgrm, + lfsr_data_fromgrm(grm, grm_buf)); + if (err) { + return err; + } + + // fix our grm + for (int j = 0; j < 2; j++) { + if ((grm->rms[j] & lfsr_midbmask(lfs)) + == (lfs_smax32(mdir->mid, 0) + & lfsr_midbmask(lfs))) { + if ((grm->rms[j] & lfsr_midrmask(lfs)) + >= mdir_.u.m.weight) { + grm->rms[j] += lfsr_mleafweight(lfs) + - mdir_.u.m.weight; + } + } else if (grm->rms[j] > mdir->mid) { + grm->rms[j] += mdelta; + } + } + + // xor our fix into our gdelta + err = lfsr_grm_xor(lfs, lfs->dgrm, + lfsr_data_fromgrm(grm, grm_buf)); + if (err) { + return err; + } + } + } // lookup first name in sibling to use as the split name // @@ -6238,15 +6509,10 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } // new mtree? - if (lfsr_mtree_ismptr(&mtree_)) { - err = lfsr_btree_alloc(lfs, &mtree_.u.btree); - if (err) { - return err; - } - + if (lfsr_mtree_ismptr(&lfs->mtree)) { uint8_t mdir_buf[LFSR_MPTR_DSIZE]; uint8_t msibling_buf[LFSR_MPTR_DSIZE]; - err = lfsr_btree_commit(lfs, &mtree_.u.btree, LFSR_ATTRS( + err = lfsr_mtree_commit(lfs, &lfs->mtree, LFSR_ATTRS( LFSR_ATTR(0, MDIR, +lfsr_mleafweight(lfs), FROMMPTR(lfsr_mdir_mptr(&mdir_), mdir_buf)), @@ -6261,12 +6527,9 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // update our mtree } else { - // mark as unerased in case of failure - lfsr_btree_unerase(&lfs->mtree.u.btree); - uint8_t mdir_buf[LFSR_MPTR_DSIZE]; uint8_t msibling_buf[LFSR_MPTR_DSIZE]; - err = lfsr_btree_commit(lfs, &mtree_.u.btree, LFSR_ATTRS( + err = lfsr_mtree_commit(lfs, &lfs->mtree, LFSR_ATTRS( LFSR_ATTR(mdir_.mid | lfsr_midrmask(lfs), MDIR, 0, FROMMPTR(lfsr_mdir_mptr(&mdir_), mdir_buf)), LFSR_ATTR((mdir_.mid | lfsr_midrmask(lfs))+1, @@ -6283,7 +6546,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } else if (err == LFS_ERR_NOENT) { LFS_DEBUG("Dropping mdir %"PRId32" " "0x{%"PRIx32",%"PRIx32"}", - mid >> lfs->mleaf_bits, + mdir->mid >> lfs->mleaf_bits, mdir->u.m.blocks[0], mdir->u.m.blocks[1]); // consume gstate so we don't lose any info @@ -6293,16 +6556,56 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } drop:; - // new mtree? - if (lfsr_mtree_ismptr(&mtree_)) { - mtree_ = LFSR_MTREE_NULL; + mdelta = -lfsr_mleafweight(lfs); + + // fix any pending grms + for (lfs_size_t i = 0; i < attr_count; i++) { + if (attrs[i].tag == LFSR_TAG_GRM) { + // Assuming we already xored our gdelta with the grm, we first + // need to xor the grm out of the gdelta. We can't just zero + // the gdelta because we may have picked up extra gdelta from + // split/dropped mdirs + // + // gd' = gd xor (grm' xor grm) + // + lfsr_grm_t *grm = (lfsr_grm_t*)attrs[i].data.u.buf.buffer; + uint8_t grm_buf[LFSR_GRM_DSIZE]; + err = lfsr_grm_xor(lfs, lfs->dgrm, + lfsr_data_fromgrm(grm, grm_buf)); + if (err) { + return err; + } + + // fix our grm + for (int j = 0; j < 2; j++) { + if (grm->rms[j] > mdir->mid) { + grm->rms[j] += mdelta; + } + } + + // xor our fix into our gdelta + err = lfsr_grm_xor(lfs, lfs->dgrm, + lfsr_data_fromgrm(grm, grm_buf)); + if (err) { + return err; + } + } + } + + // direct mdir? + if (lfsr_mtree_ismptr(&lfs->mtree)) { + err = lfsr_mroot_commit_(lfs, -1, 0, NULL, LFSR_ATTRS( + LFSR_ATTR(-1, + RM(WIDE(STRUCT)), 0, NULL))); + if (err) { + return err; + } + + lfs->mtree = LFSR_MTREE_NULL; // update our mtree } else { - // mark as unerased in case of failure - lfsr_btree_unerase(&lfs->mtree.u.btree); - - err = lfsr_btree_commit(lfs, &mtree_.u.btree, LFSR_ATTRS( + err = lfsr_mtree_commit(lfs, &lfs->mtree, LFSR_ATTRS( LFSR_ATTR(mdir_.mid | lfsr_midrmask(lfs), RM, -lfsr_mleafweight(lfs), NULL))); if (err) { @@ -6312,26 +6615,33 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // need to relocate? } else if (lfsr_mdir_cmp(mdir, &mdir_) != 0 - && !(mid == -1 || lfsr_mtree_isnull(&lfs->mtree))) { + && !(mdir->mid == -1 || lfsr_mtree_isnull(&lfs->mtree))) { LFS_DEBUG("Relocating mdir %"PRId32" " "0x{%"PRIx32",%"PRIx32"} -> 0x{%"PRIx32",%"PRIx32"}", - mid >> lfs->mleaf_bits, + mdir->mid >> lfs->mleaf_bits, mdir->u.m.blocks[0], mdir->u.m.blocks[1], mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]); relocate:; // new mtree? - if (lfsr_mtree_ismptr(&mtree_)) { - mtree_.u.mptr.weight = LFSR_MTREE_MPTR | lfsr_mleafweight(lfs); - mtree_.u.mptr.mptr = *lfsr_mdir_mptr(&mdir_); + if (lfsr_mtree_ismptr(&lfs->mtree)) { + uint8_t mdir_buf[LFSR_MPTR_DSIZE]; + err = lfsr_mroot_commit_(lfs, -1, 0, NULL, LFSR_ATTRS( + LFSR_ATTR(-1, + WIDE(MDIR), 0, + FROMMPTR(lfsr_mdir_mptr(&mdir_), mdir_buf)))); + if (err) { + return err; + } + + lfs->mtree = LFSR_MTREE_MPTR( + *lfsr_mdir_mptr(&mdir_), + lfsr_mleafweight(lfs)); } else { - // mark as unerased in case of failure - lfsr_btree_unerase(&lfs->mtree.u.btree); - // update our mtree uint8_t mdir_buf[LFSR_MPTR_DSIZE]; - err = lfsr_btree_commit(lfs, &mtree_.u.btree, LFSR_ATTRS( + err = lfsr_mtree_commit(lfs, &lfs->mtree, LFSR_ATTRS( LFSR_ATTR(mdir_.mid | lfsr_midrmask(lfs), MDIR, 0, FROMMPTR(lfsr_mdir_mptr(&mdir_), mdir_buf)))); if (err) { @@ -6340,191 +6650,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } } - // before we continue we need to update our grm in case of splits/drops - // - // this gets pretty ugly - // - for (lfs_size_t i = 0; i < attr_count; i++) { - if (attrs[i].tag == LFSR_TAG_GRM) { - // Assuming we already xored our gdelta with the grm, we first - // need to xor the grm out of the gdelta. We can't just zero - // the gdelta because we may have picked up extra gdelta from - // split/dropped mdirs - // - // gd' = gd xor (grm' xor grm) - // - lfsr_grm_t *grm = (lfsr_grm_t*)attrs[i].data.u.buf.buffer; - uint8_t grm_buf[LFSR_GRM_DSIZE]; - err = lfsr_grm_xor(lfs, lfs->dgrm, - lfsr_data_fromgrm(grm, grm_buf)); - if (err) { - return err; - } - - // fix our grm - for (int j = 0; j < 2; j++) { - if ((grm->rms[j] & lfsr_midbmask(lfs)) - == (lfs_smax32(mid, 0) & lfsr_midbmask(lfs))) { - if ((grm->rms[j] & lfsr_midrmask(lfs)) - >= mdir_.u.m.weight) { - grm->rms[j] += lfsr_mleafweight(lfs) - - mdir_.u.m.weight; - } - // update mid if we had a split or drop - } else if (grm->rms[j] > mid - && lfsr_mtree_weight(&mtree_) - != lfsr_mtree_weight(&lfs->mtree)) { - grm->rms[j] += lfsr_mtree_weight(&mtree_) - - lfsr_mtree_weight(&lfs->mtree); - } - } - - // xor our fix into our gdelta - err = lfsr_grm_xor(lfs, lfs->dgrm, - lfsr_data_fromgrm(grm, grm_buf)); - if (err) { - return err; - } - } - } - - // need to update mtree? uninlined mdir? - if (mdir_.mid != mid || lfsr_mtree_cmp(&lfs->mtree, &mtree_) != 0) { - // mtree should never go to zero since we will always have a - // root bookmark - LFS_ASSERT(lfsr_mtree_isnull(&mtree_) - || lfsr_mtree_weight(&mtree_) > 0); - - // mark mroot as unerased in case of failure - lfsr_mdir_unerase(&lfs->mroot); - - // commit mtree - lfsr_tag_t mtree_tag; - uint8_t mtree_buf[LFSR_MTREE_DSIZE]; - lfsr_data_t mtree_data; - if (lfsr_mtree_isnull(&mtree_)) { - mtree_tag = LFSR_TAG_RM(WIDE(STRUCT)); - mtree_data = LFSR_DATA_NULL; - } else if (lfsr_mtree_ismptr(&mtree_)) { - mtree_tag = LFSR_TAG_WIDE(MDIR); - mtree_data = lfsr_data_frommptr(&mtree_.u.mptr.mptr, mtree_buf); - } else { - mtree_tag = LFSR_TAG_WIDE(MTREE); - mtree_data = lfsr_data_frombtree(&mtree_.u.btree, mtree_buf); - } - - err = lfsr_mdir_commit_(lfs, &mroot_, -1, 0, NULL, LFSR_ATTRS( - LFSR_ATTR(-1, TAG(mtree_tag), 0, DATA(mtree_data)))); - if (err) { - LFS_ASSERT(err != LFS_ERR_RANGE); - LFS_ASSERT(err != LFS_ERR_NOENT); - return err; - } - } - - // need to update mroot chain? tail recurse, updating mroots until a - // commit sticks - lfsr_mdir_t mrootchild = lfs->mroot; - lfsr_mdir_t mrootchild_ = mroot_; - while (lfsr_mdir_cmp(&mrootchild_, &mrootchild) != 0 - && !lfsr_mdir_ismrootanchor(&mrootchild)) { - // find the mroot's parent - lfsr_mdir_t mrootparent_; - err = lfsr_mroot_parent(lfs, lfsr_mdir_mptr(&mrootchild), - &mrootparent_); - if (err) { - LFS_ASSERT(err != LFS_ERR_NOENT); - return err; - } - - LFS_DEBUG("Relocating mroot 0x{%"PRIx32",%"PRIx32"} " - "-> 0x{%"PRIx32",%"PRIx32"}", - mrootchild.u.m.blocks[0], mrootchild.u.m.blocks[1], - mrootchild_.u.m.blocks[0], mrootchild_.u.m.blocks[1]); - - mrootchild = mrootparent_; - - // commit mrootchild - uint8_t mrootchild_buf[LFSR_MPTR_DSIZE]; - err = lfsr_mdir_commit_(lfs, &mrootparent_, -1, -1, NULL, LFSR_ATTRS( - LFSR_ATTR(-1, - MROOT, 0, - FROMMPTR(lfsr_mdir_mptr(&mrootchild_), mrootchild_buf)))); - if (err) { - LFS_ASSERT(err != LFS_ERR_RANGE); - LFS_ASSERT(err != LFS_ERR_NOENT); - return err; - } - - mrootchild_ = mrootparent_; - } - - // uh oh, we ran out of mrootparents, need to extend mroot chain - if (lfsr_mdir_cmp(&mrootchild_, &mrootchild) != 0) { - // mrootchild should be our initial mroot at this point - LFS_ASSERT(lfsr_mdir_ismrootanchor(&mrootchild)); - LFS_DEBUG("Extending mroot 0x{%"PRIx32",%"PRIx32"}" - " -> 0x{%"PRIx32",%"PRIx32"}" - ", 0x{%"PRIx32",%"PRIx32"}", - mrootchild.u.m.blocks[0], mrootchild.u.m.blocks[1], - mrootchild.u.m.blocks[0], mrootchild.u.m.blocks[1], - mrootchild_.u.m.blocks[0], mrootchild_.u.m.blocks[1]); - - // compact into mrootparent_, this should stay our mroot anchor - lfsr_mdir_t mrootparent_; - err = lfsr_mdir_swap(lfs, &mrootparent_, &mrootchild, -1); - if (err) { - return err; - } - - // copy only the config over - lfsr_tag_t tag = 0; - while (true) { - lfsr_srid_t rid; - lfsr_rid_t weight; - lfsr_data_t data; - err = lfsr_rbyd_lookupnext(lfs, &mrootchild.u.rbyd, - -1, tag+1, - &rid, &tag, &weight, &data); - if (err) { - if (err == LFS_ERR_NOENT) { - break; - } - return err; - } - if (rid != -1 || lfsr_tag_suptype(tag) != LFSR_TAG_CONFIG) { - break; - } - - // write the tag - err = lfsr_rbyd_appendcompactattr(lfs, &mrootparent_.u.rbyd, - tag, weight, data); - if (err) { - LFS_ASSERT(err != LFS_ERR_RANGE); - return err; - } - } - - err = lfsr_rbyd_compact(lfs, &mrootparent_.u.rbyd, false, - sizeof(uint32_t)); - if (err) { - LFS_ASSERT(err != LFS_ERR_RANGE); - return err; - } - - // and commit our new mroot - uint8_t mrootchild_buf[LFSR_MPTR_DSIZE]; - err = lfsr_mdir_commit__(lfs, &mrootparent_, -1, -1, LFSR_ATTRS( - LFSR_ATTR(-1, - WIDE(MROOT), 0, - FROMMPTR(lfsr_mdir_mptr(&mrootchild_), mrootchild_buf)))); - if (err) { - LFS_ASSERT(err != LFS_ERR_NOENT); - return err; - } - } - - // success?? update in-device state + // success? update in-device state, we must not error at this point // gstate must have been committed by a lower-level function at this point LFS_ASSERT(lfsr_grm_iszero(lfs->dgrm)); @@ -6539,31 +6665,23 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } } - // update any staged bsprout/bshrub changes, note the order here - // matters since issprout/isbshrub depends on file mdir - // - // TODO merge with below? maybe? - for (lfsr_openedmdir_t *opened = lfs->opened[LFS_TYPE_REG-LFS_TYPE_REG]; - opened; - opened = opened->next) { - lfsr_file_t *file = (lfsr_file_t*)opened; - if (lfsr_file_isbsprout(file)) { - file->u.bsprout.data = file->u.bsprout.data_; - } else if (lfsr_file_isbshrub(file)) { - file->u.bshrub.rbyd = file->u.bshrub.rbyd_; - } - } - - // update any opened mdirs for (int type = LFS_TYPE_REG; type < LFS_TYPE_REG+3; type++) { for (lfsr_openedmdir_t *opened = lfs->opened[type-LFS_TYPE_REG]; opened; opened = opened->next) { - // TODO we should just remove dropped mdirs from the opened list... - // - // avoid double updating current mdir, and avoid updating - // dropped mdirs - if (&opened->mdir == mdir || opened->mdir.mid == -1) { + // update any bsprouts/bshrubs, note this must happen + // before we update the mdir + if (type == LFS_TYPE_REG) { + lfsr_file_t *file = (lfsr_file_t*)opened; + if (lfsr_file_isbsprout(file)) { + file->u.bsprout.data = file->u.bsprout.data_; + } else if (lfsr_file_isbshrub(file)) { + file->u.bshrub.rbyd = file->u.bshrub.rbyd_; + } + } + + // avoid double updating current mdir + if (&opened->mdir == mdir) { continue; } @@ -6571,7 +6689,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, for (lfs_size_t i = 0; i < attr_count; i++) { // adjust opened mdirs? if ((opened->mdir.mid & lfsr_midbmask(lfs)) - == (lfs_smax32(mid, 0) & lfsr_midbmask(lfs)) + == (lfs_smax32(mdir->mid, 0) & lfsr_midbmask(lfs)) && opened->mdir.mid >= attrs[i].rid) { // removed? if (opened->mdir.mid < attrs[i].rid - attrs[i].delta) { @@ -6591,7 +6709,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, ((lfsr_dir_t*)opened)->pos += attrs[i].delta; } } - } else if (opened->mdir.mid > mid) { + } else if (opened->mdir.mid > mdir->mid) { // adjust dir position? if (type == LFS_TYPE_DIR) { ((lfsr_dir_t*)opened)->pos += attrs[i].delta; @@ -6600,22 +6718,18 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } // update any opened mdirs if we had a split or drop - if ((opened->mdir.mid & lfsr_midbmask(lfs)) - == (lfs_smax32(mid, 0) & lfsr_midbmask(lfs))) { - if (msibling_.u.m.weight > 0 + if (lfsr_mdir_cmp(&opened->mdir, mdir) == 0) { + if (mdelta > 0 && (opened->mdir.mid & lfsr_midrmask(lfs)) >= mdir_.u.m.weight) { - LFS_ASSERT(lfsr_mtree_weight(&mtree_) - != lfsr_mtree_weight(&lfs->mtree)); opened->mdir.mid += lfsr_mleafweight(lfs) - mdir_.u.m.weight; opened->mdir.u.m = msibling_.u.m; } else { opened->mdir.u.m = mdir_.u.m; } - } else if (opened->mdir.mid > mid) { - opened->mdir.mid += lfsr_mtree_weight(&mtree_) - - lfsr_mtree_weight(&lfs->mtree); + } else if (opened->mdir.mid > mdir->mid) { + opened->mdir.mid += mdelta; } if (type == LFS_TYPE_DIR) { @@ -6626,7 +6740,8 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // TODO clean this up a bit? // adjust opened mdirs? if ((dir->bookmark & lfsr_midbmask(lfs)) - == (lfs_smax32(mid, 0) & lfsr_midbmask(lfs)) + == (lfs_smax32(mdir->mid, 0) + & lfsr_midbmask(lfs)) && dir->bookmark >= attrs[i].rid) { // removed? if (dir->bookmark < attrs[i].rid - attrs[i].delta) { @@ -6639,25 +6754,22 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // adjust dir position? dir->pos -= attrs[i].delta; } - } else if (dir->bookmark > mid) { + } else if (dir->bookmark > mdir->mid) { // adjust dir position? dir->pos -= attrs[i].delta; } } if ((dir->bookmark & lfsr_midbmask(lfs)) - == (lfs_smax32(mid, 0) & lfsr_midbmask(lfs))) { - if (msibling_.u.m.weight > 0 + == (lfs_smax32(mdir->mid, 0) & lfsr_midbmask(lfs))) { + if (mdelta > 0 && (dir->bookmark & lfsr_midrmask(lfs)) >= mdir_.u.m.weight) { - LFS_ASSERT(lfsr_mtree_weight(&mtree_) - != lfsr_mtree_weight(&lfs->mtree)); dir->bookmark += lfsr_mleafweight(lfs) - mdir_.u.m.weight; } - } else if (dir->bookmark > mid) { - dir->bookmark += lfsr_mtree_weight(&mtree_) - - lfsr_mtree_weight(&lfs->mtree); + } else if (dir->bookmark > mdir->mid) { + dir->bookmark += mdelta; } } next:; @@ -6665,21 +6777,16 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } // update mdir to follow requested rid - if (mid != -1 - && msibling_.u.m.weight > 0 - && (mid & lfsr_midrmask(lfs)) >= mdir_.u.m.weight) { - LFS_ASSERT(lfsr_mtree_weight(&mtree_) - != lfsr_mtree_weight(&lfs->mtree)); + if (mdir->mid == -1) { + mdir->u.m = lfs->mroot.u.m; + } else if (mdelta > 0 + && (mdir->mid & lfsr_midrmask(lfs)) >= mdir_.u.m.weight) { mdir->mid += lfsr_mleafweight(lfs) - mdir_.u.m.weight; mdir->u.m = msibling_.u.m; } else { mdir->u.m = mdir_.u.m; } - // update our mroot and mtree - lfs->mroot.u.m = mroot_.u.m; - lfs->mtree = mtree_; - return 0; } @@ -7932,9 +8039,9 @@ static int lfsr_mountinited(lfs_t *lfs) { } else { // found a direct mdir? keep track of this as our "mtree" if (lfsr_mtree_isnull(&lfs->mtree)) { - lfs->mtree.u.mptr.weight - = LFSR_MTREE_MPTR | lfsr_mleafweight(lfs); - lfs->mtree.u.mptr.mptr = *lfsr_mdir_mptr(&tinfo.u.mdir); + lfs->mtree = LFSR_MTREE_MPTR( + *lfsr_mdir_mptr(&tinfo.u.mdir), + lfsr_mleafweight(lfs)); } } @@ -8932,19 +9039,23 @@ int lfsr_dir_rewind(lfs_t *lfs, lfsr_dir_t *dir) { #define LFSR_FILE_BSPROUT 0x80000000 #define LFSR_BSPROUT_NULL ((lfsr_bsprout_t){.data=LFSR_DATA_DISK(0, 0, 0)}) -static inline bool lfsr_file_isnull(const lfsr_file_t *file) { +static inline bool lfsr_file_isbnull(const lfsr_file_t *file) { return (lfs_size_t)file->u.bsprout.data.u.disk.size == (LFSR_FILE_BSPROUT | 0); } static inline bool lfsr_file_isbsprout(const lfsr_file_t *file) { - return (file->u.bsprout.data.u.disk.size & LFSR_FILE_BSPROUT) - && file->u.bsprout.data.u.disk.block == file->m.mdir.u.m.blocks[0]; + return (lfs_size_t)file->u.bsprout.data.u.disk.size + > (LFSR_FILE_BSPROUT | 0) + && file->u.bsprout.data.u.disk.block + == file->m.mdir.u.m.blocks[0]; } static inline bool lfsr_file_isbptr(const lfsr_file_t *file) { - return (file->u.bsprout.data.u.disk.size & LFSR_FILE_BSPROUT) - && file->u.bsprout.data.u.disk.block != file->m.mdir.u.m.blocks[0]; + return (lfs_size_t)file->u.bsprout.data.u.disk.size + > (LFSR_FILE_BSPROUT | 0) + && file->u.bsprout.data.u.disk.block + != file->m.mdir.u.m.blocks[0]; } static inline bool lfsr_file_isbshrub(const lfsr_file_t *file) { @@ -9207,6 +9318,8 @@ static int lfsr_file_ulookupnext(lfs_t *lfs, const lfsr_file_t *file, if (pos > lfsr_file_uweight(file)) { return LFS_ERR_NOENT; } + // the uweight check should make this impossible + LFS_ASSERT(!lfsr_file_isbnull(file)); // inlined sprout? if (lfsr_file_isbsprout(file)) { @@ -9436,13 +9549,13 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file, lfsr_data_t data; uint8_t bptr_buf[LFSR_BPTR_DSIZE]; // have data? - if (lfsr_file_isbsprout(file) && lfsr_file_uweight(file) > 0) { + if (lfsr_file_isbsprout(file)) { tag = LFSR_TAG_DATA; weight = lfsr_data_size(&file->u.bsprout.data); data = file->u.bsprout.data; // have bptr? - } else if (lfsr_file_isbptr(file) && lfsr_file_uweight(file) > 0) { + } else if (lfsr_file_isbptr(file)) { tag = LFSR_TAG_BLOCK; weight = lfsr_bptr_size(&file->u.bptr); data = lfsr_data_frombptr(&file->u.bptr, bptr_buf); @@ -10286,7 +10399,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) { ? LFSR_BPTR_DSIZE : LFSR_BTREE_DSIZE]; err = lfsr_mdir_commit(lfs, &file->m.mdir, LFSR_ATTRS( - (lfsr_file_isnull(file)) + (lfsr_file_isbnull(file)) ? LFSR_ATTR(file->m.mdir.mid, WIDE(RM(STRUCT)), 0, NULL) : (lfsr_file_isbsprout(file)) diff --git a/tests/test_mtree.toml b/tests/test_mtree.toml index 54d411e2..aebb2710 100644 --- a/tests/test_mtree.toml +++ b/tests/test_mtree.toml @@ -81,7 +81,7 @@ code = ''' for (lfs_size_t i = 0; i < N; i++) { // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(i), 0, BUF(&alphas[i % 26], 1)))) => 0; @@ -178,7 +178,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -251,7 +251,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdirs were unininlined and split @@ -324,7 +324,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -342,7 +342,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; // assert mdir was split correctly @@ -633,7 +633,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -702,7 +702,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -716,7 +716,7 @@ code = ''' assert(mdir.u.m.weight == 1); // force mdir to compact while we're removing - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(0, RM, -1, NULL))) => 0; @@ -774,7 +774,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; // remove the entry as we compact, forcing the mdir to be dropped lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( @@ -833,7 +833,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; // remove the left entry as we compact, forcing the left // mdir to be dropped @@ -900,7 +900,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; // remove the right entry as we compact, forcing the right mdir // to be dropped @@ -967,7 +967,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; // remove both entries as we compact, forcing both mdirs to be dropped lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( @@ -1017,7 +1017,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -1035,7 +1035,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; // remove the left entry as we compact, forcing the left // mdir to be dropped @@ -1112,7 +1112,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -1130,7 +1130,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; // remove the right entry as we compact, forcing the right // mdir to be dropped @@ -1206,7 +1206,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -1224,7 +1224,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; // remove both entries as we compact, forcing both mdirs to be dropped lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( @@ -1667,7 +1667,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mtree has one mdir @@ -1682,9 +1682,9 @@ code = ''' lfsr_mdir_t old_mdir = mdir; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; memset(buffer, 'c', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(mdir.mid, REG, 0, BUF(buffer, SIZE)))) => 0; @@ -1761,7 +1761,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdirs were unininlined and split @@ -1776,9 +1776,9 @@ code = ''' lfsr_mdir_t old_mdir = mdir; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; memset(buffer, 'c', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(mdir.mid, REG, 0, BUF(buffer, SIZE)))) => 0; @@ -1855,7 +1855,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdirs were unininlined and split @@ -1870,9 +1870,9 @@ code = ''' lfsr_mdir_t old_mdir = mdir; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; memset(buffer, 'c', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(mdir.mid, REG, 0, BUF(buffer, SIZE)))) => 0; @@ -1947,9 +1947,9 @@ code = ''' // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(1), 0, BUF(buffer, SIZE)))) => 0; @@ -2007,10 +2007,10 @@ code = ''' lfsr_mdir_t old_mroot = lfs.mroot; for (int i = 0; i < 4; i++) { - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; } - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(1), 0, BUF(buffer, SIZE)))) => 0; @@ -2064,9 +2064,9 @@ code = ''' // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert we relocated @@ -2075,9 +2075,9 @@ code = ''' // force mroot to compact twice again, this should relocate the mroot old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(1), 0, BUF(buffer, SIZE)))) => 0; @@ -2134,7 +2134,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mtree has one mdir @@ -2144,7 +2144,7 @@ code = ''' // setup mroot to need to compact, this should trigger a relocation when // we relocate the mdir below - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_t old_mroot = lfs.mroot; // force mdir to compact twice, this should relocate @@ -2154,9 +2154,9 @@ code = ''' lfsr_mdir_t old_mdir = mdir; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; memset(buffer, 'c', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(mdir.mid, REG, 0, BUF(buffer, SIZE)))) => 0; @@ -2239,7 +2239,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -2249,7 +2249,7 @@ code = ''' // setup mroot to need to compact, this should trigger a relocation when // we relocate the mdir below - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_t old_mroot = lfs.mroot; // now add another large entry to the mdir, forcing a split @@ -2262,7 +2262,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; // assert mdir was split correctly @@ -2352,7 +2352,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -2362,7 +2362,7 @@ code = ''' // setup mroot to need to compact, this should trigger a relocation when // we relocate the mdir below - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_t old_mroot = lfs.mroot; // remove the entry, forcing the mdir to be dropped @@ -2425,7 +2425,7 @@ code = ''' // force mroot to compact once, so the second compact below will trigger // a relocation - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // prepare mroot with a large attr so the next entry can not fit @@ -2441,7 +2441,7 @@ code = ''' // force mroot to compact, this should trigger a relocation lfsr_mdir_t old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -2513,7 +2513,7 @@ code = ''' // force mroot to compact once, so the second compact below will trigger // a relocation - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // create 2 large entries that needs to be uninlined and split @@ -2528,7 +2528,7 @@ code = ''' // force mroot to compact, this should trigger a relocation lfsr_mdir_t old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdirs were unininlined and split @@ -2913,7 +2913,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -2992,7 +2992,7 @@ code = ''' LFSR_ATTR(2, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdirs were unininlined and split @@ -3053,7 +3053,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -3090,7 +3090,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; // assert mdir was split correctly @@ -3169,9 +3169,9 @@ code = ''' // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(1), 0, BUF(buffer, SIZE)))) => 0; @@ -3223,7 +3223,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -3256,9 +3256,9 @@ code = ''' // force mdir to compact twice, this should relocate lfsr_mdir_t old_mdir = mdir; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; memset(buffer, 'e', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(1, REG, 0, BUF(buffer, SIZE)))) => 0; @@ -3317,7 +3317,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // we should now have 2 mdirs @@ -3332,7 +3332,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; // we should now have 3 mdirs @@ -3363,7 +3363,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; // we should now have 4 mdirs @@ -3410,7 +3410,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // we should now have 2 mdirs @@ -3425,7 +3425,7 @@ code = ''' LFSR_ATTR(mdir.mid, REG, +1, BUF(buffer, SIZE)))) => 0; // force mdir to compact - mdir.u.rbyd.eoff = BLOCK_SIZE; + mdir.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0; // we should now have 3 mdirs @@ -3591,7 +3591,7 @@ code = ''' LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly @@ -3715,7 +3715,7 @@ code = ''' LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdirs were unininlined and split @@ -3842,9 +3842,9 @@ code = ''' // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(1), 0, BUF(buffer, SIZE)))) => 0; @@ -4325,9 +4325,9 @@ code = ''' // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(1), 0, BUF(buffer, SIZE)))) => 0; @@ -4380,10 +4380,10 @@ code = ''' lfsr_mdir_t old_mroot = lfs.mroot; for (int i = 0; i < 4; i++) { - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; } - lfs.mroot.u.rbyd.eoff = BLOCK_SIZE; + lfs.mroot.u.rbyd.eoff = -1; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(-1, UATTR(1), 0, BUF(buffer, SIZE)))) => 0;