diff --git a/lfs.c b/lfs.c index f566c1f3..ee9b1717 100644 --- a/lfs.c +++ b/lfs.c @@ -5386,18 +5386,9 @@ static int lfsr_mdir_compact_(lfs_t *lfs, lfsr_mdir_t *mdir, // - mid = wl => only alloc if mdir is tired (wear-leveling) // - otherwise => always alloc, use this mid (new mdir) - // consume gstate on original rbyd, we need this even if we drop - // our mdir to avoid losing info - // - // if succesful, this should get immediately appended to our new commit - int err = lfsr_fs_consumegdelta(lfs, msource); - if (err) { - return err; - } - // first thing we need to do is read our current revision count uint32_t rev; - err = lfsr_bd_read(lfs, msource->rbyd.block, 0, sizeof(uint32_t), + int err = lfsr_bd_read(lfs, msource->rbyd.block, 0, sizeof(uint32_t), &rev, sizeof(uint32_t)); if (err && err != LFS_ERR_CORRUPT) { return err; @@ -5430,6 +5421,19 @@ static int lfsr_mdir_compact_(lfs_t *lfs, lfsr_mdir_t *mdir, rev = (err != LFS_ERR_CORRUPT ? lfs_fromle32_(&rev) : 0); } + // only consume gstate here during normal compacts + // TODO avoid duplicate conditions somehow? + if (mid == LFSR_MID_WL) { + // consume gstate on original rbyd, we need this even if we drop + // our mdir to avoid losing info + // + // if succesful, this should get immediately appended to our new commit + int err = lfsr_fs_consumegdelta(lfs, msource); + if (err) { + return err; + } + } + // swap our rbyds lfs_swap32(&mdir->rbyd.block, &mdir->redund_block); // update our revision count @@ -7509,6 +7513,11 @@ static int lfsr_fs_preparemutation(lfs_t *lfs) { LFS_DEBUG("Fixing grm (%"PRId32".%"PRId32")", lfs->grm_.mid, lfs->grm_.rid); + + // checkpoint the allocator in case fixing the grm causes mtree + // manipulation + lfs_alloc_ack(lfs); + int err = lfsr_fs_fixgrm(lfs); if (err) { return err; diff --git a/runners/test_runner.c b/runners/test_runner.c index 174e780e..98ff7706 100644 --- a/runners/test_runner.c +++ b/runners/test_runner.c @@ -478,6 +478,7 @@ extern size_t test_geometry_count; extern const test_powerloss_t *test_powerlosses; extern size_t test_powerloss_count; +bool test_pl = false; const test_id_t *test_ids = (const test_id_t[]) { {NULL, NULL, 0, NULL, 0}, @@ -606,7 +607,6 @@ void test_trace(const char *fmt, ...) { } } - // test prng uint32_t test_prng(uint32_t *state) { // A simple xorshift32 generator, easily reproducible. Keep in mind @@ -771,6 +771,7 @@ static void case_forperm( // explicit powerloss cycles? if (cycles) { + test_pl = true; cb(data, suite, case_, &(test_powerloss_t){ .run=run_powerloss_cycles, .cycles=cycles, @@ -778,8 +779,8 @@ static void case_forperm( } else { for (size_t p = 0; p < test_powerloss_count; p++) { // skip non-reentrant tests when powerloss testing - if (test_powerlosses[p].run != run_powerloss_none - && !(case_->flags & TEST_REENTRANT)) { + test_pl = test_powerlosses[p].run != run_powerloss_none; + if (test_pl && !(case_->flags & TEST_REENTRANT)) { continue; } @@ -820,6 +821,7 @@ static void case_forperm( } if (cycles) { + test_pl = true; cb(data, suite, case_, &(test_powerloss_t){ .run=run_powerloss_cycles, .cycles=cycles, @@ -827,8 +829,8 @@ static void case_forperm( } else { for (size_t p = 0; p < test_powerloss_count; p++) { // skip non-reentrant tests when powerloss testing - if (test_powerlosses[p].run != run_powerloss_none - && !(case_->flags & TEST_REENTRANT)) { + test_pl = test_powerlosses[p].run != run_powerloss_none; + if (test_pl && !(case_->flags & TEST_REENTRANT)) { continue; } diff --git a/runners/test_runner.h b/runners/test_runner.h index 5894cf9b..c22df338 100644 --- a/runners/test_runner.h +++ b/runners/test_runner.h @@ -69,6 +69,11 @@ struct test_suite { }; +// this is defined as true when powerloss-testing +extern bool test_pl; + +#define TEST_PL test_pl + // deterministic prng for pseudo-randomness in testes uint32_t test_prng(uint32_t *state); diff --git a/scripts/dbgbtree.py b/scripts/dbgbtree.py index 0f28cb5b..e5ba101c 100755 --- a/scripts/dbgbtree.py +++ b/scripts/dbgbtree.py @@ -511,7 +511,8 @@ def main(disk, roots=None, *, btree.addr(), btree.rev, btree.weight)) # look up an id, while keeping track of the search path - def btree_lookup(bid, depth=None): + def btree_lookup(bid, *, + depth=None): rbyd = btree rid = bid depth_ = 1 diff --git a/scripts/dbglfs.py b/scripts/dbglfs.py index 6c5d6df9..c555e35c 100755 --- a/scripts/dbglfs.py +++ b/scripts/dbglfs.py @@ -396,7 +396,8 @@ class Rbyd: yield id, tag, w, j, d, data # btree lookup with this rbyd as the root - def btree_lookup(self, f, block_size, bid, depth=None): + def btree_lookup(self, f, block_size, bid, *, + depth=None): rbyd = self rid = bid depth_ = 1 @@ -558,13 +559,13 @@ class Rbyd: mtree = Rbyd.fetch(f, block_size, block, trunk) # corrupted? if not mtree: - return False, 0, b'', -1, None, -1, 0, 0 + return False, -1, None, -1, 0, 0 # lookup our name in the mtree mid, tag_, w, data = mtree.btree_namelookup( f, block_size, did, name) if tag_ != TAG_MDIR: - return False, 0, b'', -1, None, -1, 0, 0 + return False, -1, None, -1, 0, 0 # fetch the mdir blocks = frommdir(data) @@ -588,12 +589,32 @@ class Rbyd: return found, mid, mdir, rid, tag, w # iterate through a directory assuming this is the mtree root - def mtree_dir(self, f, block_size, did): + def mtree_dir(self, f, block_size, did, *, + all=False): + all_, all = all, __builtins__.all + # lookup the dstart found, mid, mdir, rid, tag, w = self.mtree_namelookup( f, block_size, did, b'') # iterate through all files until the next dstart while found: + # lookup each rid + done, rid, tag, w, j, d, data, _ = mdir.lookup(rid, TAG_NAME) + if done: + break + + # parse out each name + did_, d_ = fromleb128(data) + name_ = data[d_:] + + # end if we see another did + if did_ != did: + break + + # skip dstarts unless all entries are requested + if tag != TAG_DSTART or all_: + yield name_, mid, mdir, rid, tag, w + rid += w if rid >= mdir.weight: rid -= mdir.weight @@ -603,17 +624,6 @@ class Rbyd: if not mdir: break - # lookup each rid - done, rid, tag, w, j, d, data, _ = mdir.lookup(rid, TAG_NAME) - if done or tag == TAG_DSTART: - break - - # parse out each name - did_, d_ = fromleb128(data) - name_ = data[d_:] - - yield did_, name_, mid, mdir, rid, tag, w - # read the superconfig def superconfig(mroot): @@ -679,7 +689,15 @@ def grepr(tag, data): return 'gstate 0x%02x %d' % (tag, len(data)) def frepr(mdir, rid, tag): - if tag == TAG_DIR: + if tag == TAG_DSTART: + # read the did + did = '?' + done, rid_, tag_, w_, j, d, data, _ = mdir.lookup(rid, TAG_DSTART) + if not done and rid_ == rid and tag_ == TAG_DSTART: + did, _ = fromleb128(data) + did = '0x%x' % did + return 'dstart %s' % did + elif tag == TAG_DIR: # read the did did = '?' done, rid_, tag_, w_, j, d, data, _ = mdir.lookup(rid, TAG_DID) @@ -815,8 +833,9 @@ def main(disk, mroots=None, *, def rec_f_width(did, depth): depth_ = 0 width_ = 0 - for did, name, mid, mdir, rid, tag, w in mroot.mtree_dir( - f, block_size, did): + for name, mid, mdir, rid, tag, w in mroot.mtree_dir( + f, block_size, did, + all=args.get('all')): width_ = max(width_, len(name)) # recurse? if tag == TAG_DIR and depth > 1: @@ -928,14 +947,16 @@ def main(disk, mroots=None, *, # print gdeltas? if args.get('gdelta'): for mid, mdir, j, d, data in gstate.gdelta[tag]: - print('{%s}: %*s %-22s %s' % ( + print('%s{%s}: %*s %-22s %s%s' % ( + '\x1b[90m' if color else '', ','.join('%04x' % block for block in it.chain([mdir.block], mdir.redund_blocks)), w_width, mid, tagrepr(tag, 0, len(data)), next(xxd(data, 8), '') - if not args.get('no_truncate') else '')) + if not args.get('no_truncate') else '', + '\x1b[m' if color else '')) # show in-device representation if args.get('device'): @@ -976,9 +997,11 @@ def main(disk, mroots=None, *, def rec_dir(did, depth, prefixes=('', '', '', '')): nonlocal pmid # collect all entries first so we know when the dir ends - dir = list(mroot.mtree_dir(f, block_size, did)) - for i, (did, name, mid, mdir, rid, tag, w) in enumerate(dir): - print('%12s %*s %-*s %s' % ( + dir = list(mroot.mtree_dir(f, block_size, did, + all=args.get('all'))) + for i, (name, mid, mdir, rid, tag, w) in enumerate(dir): + print('%s%12s %*s %-*s %s%s' % ( + '\x1b[90m' if color and tag == TAG_DSTART else '', '{%s}:' % ','.join('%04x' % block for block in it.chain([mdir.block], mdir.redund_blocks)) @@ -989,7 +1012,8 @@ def main(disk, mroots=None, *, f_width, '%s%s' % ( prefixes[0+(i==len(dir)-1)], name.decode('utf8')), - frepr(mdir, rid, tag))) + frepr(mdir, rid, tag), + '\x1b[m' if color and tag == TAG_DSTART else '')) pmid = mid # print attrs associated with this file? @@ -1107,7 +1131,7 @@ if __name__ == "__main__": parser.add_argument( '-a', '--all', action='store_true', - help="Show all files including grmed files.") + help="Show all files including dstarts and grmed files.") parser.add_argument( '-r', '--raw', action='store_true', diff --git a/scripts/dbgmtree.py b/scripts/dbgmtree.py index a3598410..dfa3490c 100755 --- a/scripts/dbgmtree.py +++ b/scripts/dbgmtree.py @@ -488,7 +488,8 @@ class Rbyd: return tree, t_depth # btree lookup with this rbyd as the root - def btree_lookup(self, f, block_size, bid, depth=None): + def btree_lookup(self, f, block_size, bid, *, + depth=None): rbyd = self rid = bid depth_ = 1 @@ -543,7 +544,8 @@ class Rbyd: return not tags, bid + (rid_-rid), w, rbyd, rid_, tags, path # btree rbyd-tree generation for debugging - def btree_tree(self, f, block_size, depth=None, *, + def btree_tree(self, f, block_size, *, + depth=None, inner=False): # find the max depth of each layer to nicely align trees bdepths = {} @@ -671,7 +673,8 @@ class Rbyd: return tree, max((branch.d+1 for branch in tree), default=0) # btree B-tree generation for debugging - def btree_btree(self, f, block_size, depth=None, *, + def btree_btree(self, f, block_size, *, + depth=None, inner=False): # find all branches tree = set() diff --git a/tests/t5_dirs.toml b/tests/t5_dirs.toml index 724d51b8..48c45bbd 100644 --- a/tests/t5_dirs.toml +++ b/tests/t5_dirs.toml @@ -2,13 +2,19 @@ [cases.t5_dirs_mkdir] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make a directory - lfsr_mkdir(&lfs, "ardvark") => 0; + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -44,13 +50,19 @@ code = ''' # test that noent errors work [cases.t5_dirs_noent] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make a directory - lfsr_mkdir(&lfs, "ardvark") => 0; + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // try to read a nonsense path struct lfs_info info; @@ -90,13 +102,19 @@ code = ''' # test that creating the same directory twice errors [cases.t5_dirs_mkdir_exists] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make a directory - lfsr_mkdir(&lfs, "ardvark") => 0; + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // make the same directory, should error lfsr_mkdir(&lfs, "ardvark") => LFS_ERR_EXIST; @@ -134,13 +152,19 @@ code = ''' # test that creating a directory with an invalid path errors [cases.t5_dirs_mkdir_noent] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make a directory - lfsr_mkdir(&lfs, "ardvark") => 0; + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // make a nonsense directory, should error lfsr_mkdir(&lfs, "no/hmm") => LFS_ERR_NOENT; @@ -180,15 +204,23 @@ code = ''' [cases.t5_dirs_mkdir_siblings] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make some directories - lfsr_mkdir(&lfs, "ardvark") => 0; - lfsr_mkdir(&lfs, "batman") => 0; - lfsr_mkdir(&lfs, "cantaloupe") => 0; + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "batman"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "cantaloupe"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -234,15 +266,23 @@ code = ''' [cases.t5_dirs_mkdir_children] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make some directories - lfsr_mkdir(&lfs, "ardvark") => 0; - lfsr_mkdir(&lfs, "ardvark/batman") => 0; - lfsr_mkdir(&lfs, "ardvark/batman/cantaloupe") => 0; + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "ardvark/batman"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "ardvark/batman/cantaloupe"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -307,16 +347,22 @@ code = ''' [cases.t5_dirs_mkdir_many] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); - lfsr_mkdir(&lfs, name) => 0; + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -359,23 +405,30 @@ code = ''' ''' [cases.t5_dirs_mkdir_many_2layers] -defines.N = [1, 2, 4, 8, 16, 32] +defines.N = [1, 2, 4, 8, 16] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); - lfsr_mkdir(&lfs, name) => 0; + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); - lfsr_mkdir(&lfs, name) => 0; + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -449,28 +502,36 @@ code = ''' ''' [cases.t5_dirs_mkdir_many_3layers] -defines.N = [1, 2, 4, 8] +defines.N = [1, 2, 4] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); - lfsr_mkdir(&lfs, name) => 0; + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); - lfsr_mkdir(&lfs, name) => 0; + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t k = 0; k < N; k++) { sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); - lfsr_mkdir(&lfs, name) => 0; + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -577,17 +638,23 @@ code = ''' [cases.t5_dirs_mkdir_many_linkedlist] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } // create this many directory in a sort of linked-list by nesting char name[4096]; memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); - lfsr_mkdir(&lfs, name) => 0; + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -738,10 +805,15 @@ code = ''' # test that did collisions don't cause issues [cases.t5_dirs_did_collisions] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } assert(lfs_crc32c(0, "a_SNmwMTHH", 10) == 0x12345678); assert(lfs_crc32c(0, "b_skvjpWJH", 10) == 0x12345678); @@ -751,12 +823,18 @@ code = ''' assert(lfs_crc32c(0, "f_lUoVuhJH", 10) == 0x12345678); // make directories - lfsr_mkdir(&lfs, "a_SNmwMTHH") => 0; - lfsr_mkdir(&lfs, "b_skvjpWJH") => 0; - lfsr_mkdir(&lfs, "c_OnOQhVPH") => 0; - lfsr_mkdir(&lfs, "d_puMpPjRH") => 0; - lfsr_mkdir(&lfs, "e_LptKHkHH") => 0; - lfsr_mkdir(&lfs, "f_lUoVuhJH") => 0; + err = lfsr_mkdir(&lfs, "a_SNmwMTHH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "b_skvjpWJH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "c_OnOQhVPH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "d_puMpPjRH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "e_LptKHkHH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "f_lUoVuhJH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -821,10 +899,15 @@ code = ''' # these will also collide with the root [cases.t5_dirs_did_zero] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); assert(lfs_crc32c(0, "b_iUwOsqRH", 10) == 0x00000000); @@ -833,21 +916,19 @@ code = ''' assert(lfs_crc32c(0, "e_VNunKMPH", 10) == 0x00000000); assert(lfs_crc32c(0, "f_vknsvNRH", 10) == 0x00000000); - // remount? - if (REMOUNT) { - lfsr_unmount(&lfs) => 0; - lfsr_mount(&lfs, cfg) => 0; - // grm should be zero here - assert(lfs.grm[0] == 0); - } - // make directories - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "b_iUwOsqRH") => 0; - lfsr_mkdir(&lfs, "c_UPNtkpHH") => 0; - lfsr_mkdir(&lfs, "d_jKLUSLJH") => 0; - lfsr_mkdir(&lfs, "e_VNunKMPH") => 0; - lfsr_mkdir(&lfs, "f_vknsvNRH") => 0; + err = lfsr_mkdir(&lfs, "a_IplRNrPH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "b_iUwOsqRH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "c_UPNtkpHH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "d_jKLUSLJH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "e_VNunKMPH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "f_vknsvNRH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -914,10 +995,15 @@ code = ''' # note this is true even if you truncate [cases.t5_dirs_did_ones] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } assert(lfs_crc32c(0, "a_iomlVKPH", 10) == 0xffffffff); assert(lfs_crc32c(0, "b_IJvqkHRH", 10) == 0xffffffff); @@ -927,12 +1013,18 @@ code = ''' assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); // make directories - lfsr_mkdir(&lfs, "a_iomlVKPH") => 0; - lfsr_mkdir(&lfs, "b_IJvqkHRH") => 0; - lfsr_mkdir(&lfs, "c_uOOJsIHH") => 0; - lfsr_mkdir(&lfs, "d_JTMkKuJH") => 0; - lfsr_mkdir(&lfs, "e_vQtPStPH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + err = lfsr_mkdir(&lfs, "a_iomlVKPH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "b_IJvqkHRH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "c_uOOJsIHH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "d_JTMkKuJH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "e_vQtPStPH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "f_VtoMnwRH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -999,10 +1091,15 @@ code = ''' # issues [cases.t5_dirs_did_leb128_boundaries] defines.REMOUNT = [false, true] +reentrant = true code = ''' + // format once per test lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; + int err = lfsr_mount(&lfs, cfg); + if (err) { + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + } assert(lfs_crc32c(0, "a_IOtUptRH", 10) == 0x0000007f); assert(lfs_crc32c(0, "b_nquQsKHH", 10) == 0x00000080); @@ -1012,12 +1109,18 @@ code = ''' assert(lfs_crc32c(0, "f_pNtQTPJH", 10) == 0x00004001); // make directories - lfsr_mkdir(&lfs, "a_IOtUptRH") => 0; - lfsr_mkdir(&lfs, "b_nquQsKHH") => 0; - lfsr_mkdir(&lfs, "c_vwQtKjHH") => 0; - lfsr_mkdir(&lfs, "d_sVrvrWHH") => 0; - lfsr_mkdir(&lfs, "e_thrRIsRH") => 0; - lfsr_mkdir(&lfs, "f_pNtQTPJH") => 0; + err = lfsr_mkdir(&lfs, "a_IOtUptRH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "b_nquQsKHH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "c_vwQtKjHH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "d_sVrvrWHH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "e_thrRIsRH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + err = lfsr_mkdir(&lfs, "f_pNtQTPJH"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // remount? if (REMOUNT) { @@ -1079,58 +1182,6 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.t5_dirs_mkdir_many_pl] -defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] -reentrant = true -code = ''' - // format once per test - lfs_t lfs; - int err = lfsr_mount(&lfs, cfg); - if (err) { - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; - } - - // make this many directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - int err = lfsr_mkdir(&lfs, name); - assert(!err || err == LFS_ERR_EXIST); - } - - // check that our mkdir worked - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - struct lfs_info info; - lfsr_stat(&lfs, name, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - lfsr_unmount(&lfs) => 0; -''' - - #[cases.test_dirs_root]