Changed all dir tests to be reentrant
To help with this, added TEST_PL, which is set to true when powerloss testing. This way tests can check for stronger conditions (no EEXIST) when not powerloss testing. With TEST_PL, there's really no reason every test in t5_dirs shouldn't be reentrant, and this gives us a huge improvement of test coverage very cheaply. --- The increased test coverage caught a bug, which is that gstate wasn't being consumed properly when mtree uninlining. Humorously, this went unnoticed because the most common form of mtree uninlining, mdir splitting, ended up incorrectly consuming the gstate twice, which canceled itself out since the consume operation is basically just xor. Also added support for printing dstarts to dbglfs.py, to help debugging.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+49
-25
@@ -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',
|
||||
|
||||
+6
-3
@@ -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()
|
||||
|
||||
+182
-131
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user