From 34be5055b4742cf5d9be221847bfd539c51568fa Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 3 Mar 2024 13:25:46 -0600 Subject: [PATCH] Fixed mdir drop during compaction breaking fixorphan loop The core problem is that we weren't updating dropped mdirs with weight=0 if the mdir was compacted at the same time. This is hard to notice, because most operations that can drop don't care about the mdir afterwards, but in lfsr_fs_fixorphans this caused the fixorphan loop to think it might still have orphans it could remove. The implementation is very subtle here: - In lfsr_mdir_commit_, if an error occurs during lfsr_mdir_compact__, we need to revert to the original mdir state to allow fallback to mdir split. - In lfsr_mdir_commit_, if an error occurs during lfsr_mdir_commit__ (even after a compact), we need to update the mdir in case a drop reduced the mdir weight to zero. We also need to update the mdir for things like erased state, but this doesn't come into play in the compaction route. Fixed the bug by updating the mdir copy before lfsr_mdir_commit__. Also added asserts to all insert/delete operations in test_mtree.toml. We already had drop-during-compaction tests, but these didn't check that the mdir was updated correctly. The new asserts catch this bug and should prevent a regression. --- lfs.c | 14 ++++--- tests/test_mtree.toml | 88 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/lfs.c b/lfs.c index 5dca02ce..439b18ba 100644 --- a/lfs.c +++ b/lfs.c @@ -6300,18 +6300,20 @@ compact:; return err; } + // update mdir, we need to propagate mdir changes if commit fails + *mdir = mdir_; + // now try to commit again // // upper layers should make sure this can't fail by limiting the // maximum commit size - err = lfsr_mdir_commit__(lfs, &mdir_, start_rid, end_rid, + err = lfsr_mdir_commit__(lfs, mdir, start_rid, end_rid, mid, attrs, attr_count); if (err) { LFS_ASSERT(err != LFS_ERR_RANGE); return err; } - *mdir = mdir_; return 0; } @@ -8498,7 +8500,7 @@ static int lfsr_fs_preparemutation(lfs_t *lfs) { lfs_alloc_ckpoint(lfs); // fix pending grms - bool pl = false; + bool inconsistent = false; if (lfsr_grm_hasrm(&lfs->grm)) { if (lfsr_grm_count(&lfs->grm) == 2) { LFS_DEBUG("Fixing grm " @@ -8512,7 +8514,7 @@ static int lfsr_fs_preparemutation(lfs_t *lfs) { lfsr_mid_bid(lfs, lfs->grm.rms[0]) >> lfs->mleaf_bits, lfsr_mid_rid(lfs, lfs->grm.rms[0])); } - pl = true; + inconsistent = true; int err = lfsr_fs_fixgrm(lfs); if (err) { @@ -8531,7 +8533,7 @@ static int lfsr_fs_preparemutation(lfs_t *lfs) { // if (lfs->hasorphans) { LFS_DEBUG("Fixing orphans..."); - pl = true; + inconsistent = true; int err = lfsr_fs_fixorphans(lfs); if (err) { @@ -8543,7 +8545,7 @@ static int lfsr_fs_preparemutation(lfs_t *lfs) { lfs_alloc_ckpoint(lfs); } - if (pl) { + if (inconsistent) { LFS_DEBUG("littlefs is now consistent"); } return 0; diff --git a/tests/test_mtree.toml b/tests/test_mtree.toml index 455dfcc4..541c0f36 100644 --- a/tests/test_mtree.toml +++ b/tests/test_mtree.toml @@ -233,12 +233,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -307,12 +309,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -329,6 +333,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mdir to compact mdir.rbyd.eoff = -1; @@ -589,12 +594,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -611,6 +618,7 @@ code = ''' &mdir, NULL, NULL) => 0; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 0); // assert mdir was dropped assert(lfsr_mtree_weight(&lfs.mtree) == 1*lfsr_mleafweight(&lfs)); @@ -663,12 +671,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -687,6 +697,7 @@ code = ''' mdir.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 0); // assert mdir was dropped assert(lfsr_mtree_weight(&lfs.mtree) == 1*lfsr_mleafweight(&lfs)); @@ -739,12 +750,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // remove an entry, forcing the mdir to be dropped memset(buffer+1, 'b', SIZE-1); @@ -755,6 +768,7 @@ code = ''' mdir.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 2); // assert split/drop worked out assert(lfsr_mtree_weight(&lfs.mtree) == 1*lfsr_mleafweight(&lfs)); @@ -807,12 +821,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -829,6 +845,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // remove an entry, forcing the mdir to be dropped memset(buffer+1, 'b', SIZE-1); @@ -838,6 +855,7 @@ code = ''' mdir.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 1); // assert split/drop worked out assert(lfsr_mtree_weight(&lfs.mtree) == 2*lfsr_mleafweight(&lfs)); @@ -902,12 +920,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -924,6 +944,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // remove an entry, forcing the mdir to be dropped memset(buffer+1, 'c', SIZE-1); @@ -933,6 +954,7 @@ code = ''' mdir.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 1); // assert split/drop worked out assert(lfsr_mtree_weight(&lfs.mtree) == 2*lfsr_mleafweight(&lfs)); @@ -1217,12 +1239,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -1312,12 +1336,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -1407,6 +1433,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; @@ -1463,6 +1490,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; @@ -1530,6 +1558,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; @@ -1592,12 +1621,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -1692,12 +1723,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -1714,6 +1747,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // setup mroot to compact and relocate on next commit lfs.mroot.rbyd.eoff = -1; @@ -1808,12 +1842,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -1839,6 +1875,7 @@ code = ''' mdir.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 0); // assert mroot relocated assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0); @@ -1976,12 +2013,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact, this should both split and relocate lfsr_mdir_t old_mroot = lfs.mroot; @@ -2211,6 +2250,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2218,6 +2258,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0c", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // insert a new entry, this should update our neighbors @@ -2226,6 +2267,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0b", 2)))) => 0; + assert(mdir.rbyd.weight == 4); lfsr_data_t data; // assert our entry was created @@ -2267,6 +2309,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2274,6 +2317,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0b", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // try removing left neighbor @@ -2282,6 +2326,7 @@ code = ''' &mdir, NULL, NULL) => 0; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 2); // assert neighbor was removed lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, "a", 1, @@ -2314,6 +2359,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2321,6 +2367,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0b", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // try removing right neighbor @@ -2329,6 +2376,7 @@ code = ''' &mdir, NULL, NULL) => 0; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 2); // assert neighbor was removed lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, "b", 1, @@ -2363,6 +2411,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2370,6 +2419,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0d", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // create 2 large entries that needs to be uninlined and split @@ -2381,12 +2431,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); memset(buffer+1, 'c', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 5); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2432,6 +2484,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2439,6 +2492,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0e", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // create 2 large entries that needs to be uninlined and split @@ -2450,12 +2504,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); memset(buffer+1, 'd', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 5); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2467,6 +2523,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); // force mdir to compact mdir.rbyd.eoff = -1; @@ -2512,6 +2569,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2519,6 +2577,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0b", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // force mroot to compact twice, this should extend the mroot @@ -2568,6 +2627,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2575,6 +2635,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0d", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // create 2 large entries that needs to be uninlined and split @@ -2586,12 +2647,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); memset(buffer+1, 'c', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 5); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2653,6 +2716,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2660,6 +2724,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0d", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // create 2 large entries that needs to be uninlined and split @@ -2671,12 +2736,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); memset(buffer+1, 'c', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 5); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2736,6 +2803,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2743,6 +2811,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0f", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // create 2 large entries that needs to be uninlined and split @@ -2754,12 +2823,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); memset(buffer+1, 'e', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 5); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2771,6 +2842,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); // force mdir to compact mdir.rbyd.eoff = -1; @@ -2787,6 +2859,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mdir to compact mdir.rbyd.eoff = -1; @@ -2832,6 +2905,7 @@ code = ''' &left.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &left.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(left.mdir.rbyd.weight == 2); lfsr_opened_add(&lfs, &left); lfsr_opened_t right = {.type=0}; @@ -2839,6 +2913,7 @@ code = ''' &right.mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &right.mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0e", 2)))) => 0; + assert(right.mdir.rbyd.weight == 3); lfsr_opened_add(&lfs, &right); // create 2 large entries that needs to be uninlined and split @@ -2850,12 +2925,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); memset(buffer+1, 'd', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 5); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2867,6 +2944,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 4); // force mdir to compact mdir.rbyd.eoff = -1; @@ -2880,6 +2958,7 @@ code = ''' // now remove the middle entry, forcing a drop lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + assert(mdir.rbyd.weight == 0); // assert mdir was dropped correctly assert(lfsr_mtree_weight(&lfs.mtree) == 2*lfsr_mleafweight(&lfs)); @@ -2924,6 +3003,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(mdir.rbyd.weight == 2); // test that we can traverse the tree, keeping track of all blocks we see uint8_t *seen = malloc((BLOCK_COUNT+7)/8); @@ -3157,12 +3237,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -3295,12 +3377,14 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); memset(buffer+1, 'b', SIZE-1); lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1, &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 3); // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -3317,6 +3401,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mdir to compact mdir.rbyd.eoff = -1; @@ -3457,6 +3542,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF("\0a", 2)))) => 0; + assert(mdir.rbyd.weight == 2); // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; @@ -3935,6 +4021,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot; @@ -3991,6 +4078,7 @@ code = ''' &mdir, NULL, NULL) => LFS_ERR_NOENT; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(LFSR_TAG_REG, +1, LFSR_DATA_BUF(buffer, SIZE)))) => 0; + assert(mdir.rbyd.weight == 2); // force mroot to compact twice, this should extend the mroot lfsr_mdir_t old_mroot = lfs.mroot;