From 21f7fd10327c3d7ca82aa3f116b63859483330ac Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 6 Jul 2023 00:44:55 -0500 Subject: [PATCH] Added more testing over mkdir, fixed issues dname changes introduced The main issues: - The addition of the root's dstart entry during lfsr_format throws off our mtree tests. It's a bit of a hack, but for now I am just manually deleting the root's dstart entry at the beginning of each tests. It might be possible to make the mtree tests work around the root's dstart, but it seems to cause problems for when exactly the mtree splits. - btree dnamelookup and mdir dnamelookup need different things from the rbyd dnamelookup when the dname is not found. The btree lookup needs the largest branch smaller than the dname, since this is the "bucket" containing our dname, while the mdir dnamelookup needs the id that _follows_ the id smaller than the dname, since insertion causes all ids >= the inserting id to shift up. The solution here is to make rbyd dnamelookup behave as expected by btree dnamelookup. btree needs more info about the branch (weight mostly), so this avoids more issues. mdir dnamelookup adjusts the id as needed, which costs a bit of code, but makes things work. Fortunately, mdir dnamelookup can assume the weight is 1, which simplifies things a bit. --- lfs.c | 42 +++++- tests/t3_mtree.toml | 134 ++++++++++++++++- tests/t4_alloc.toml | 4 + tests/t5_dirs.toml | 341 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 511 insertions(+), 10 deletions(-) diff --git a/lfs.c b/lfs.c index 497551ef..34e6f4f3 100644 --- a/lfs.c +++ b/lfs.c @@ -3152,14 +3152,23 @@ static int lfsr_rbyd_dnamelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd, lfs_size_t did, const char *name, lfs_size_t name_size, lfs_ssize_t *id_, lfsr_tag_t *tag_, lfs_size_t *weight_, lfsr_data_t *data_) { + // if we have an empty mdir, default to id = -1 + if (id_) { + *id_ = -1; + } + if (tag_) { + *tag_ = 0; + } + if (weight_) { + *weight_ = 0; + } + if (data_) { + *data_ = LFSR_DATA_NULL; + } + // binary search for our name lfs_ssize_t lower = 0; lfs_ssize_t upper = rbyd->weight; - // if we have an empty mdir, default to id = 0 - if (id_) { - *id_ = 0; - } - while (lower < upper) { lfsr_tag_t tag__; lfs_ssize_t id__; @@ -3198,7 +3207,16 @@ static int lfsr_rbyd_dnamelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd, // keep track of best-matching id >= our target if (id_) { - *id_ = id__ + weight__; + *id_ = id__; + } + if (tag_) { + *tag_ = tag__; + } + if (weight_) { + *weight_ = weight__; + } + if (data_) { + *data_ = data__; } } else { @@ -5686,9 +5704,19 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_ssize_t *rid, static int lfsr_mdir_dnamelookup(lfs_t *lfs, const lfsr_mdir_t *mdir, lfs_size_t did, const char *name, lfs_size_t name_size, lfs_ssize_t *id_, lfsr_tag_t *tag_, lfsr_data_t *data_) { - return lfsr_rbyd_dnamelookup(lfs, &mdir->rbyd, + int err = lfsr_rbyd_dnamelookup(lfs, &mdir->rbyd, did, name, name_size, id_, tag_, NULL, data_); + + // When not found, lfsr_rbyd_dnamelookup returns the id smaller than our + // expected name. This is correct for btree lookups, but not correct for + // mdir insertions. For mdirs we need to adjust this by 1 so we insert + // _after_ the smaller id. + if (id_ && err == LFS_ERR_NOENT) { + *id_ += 1; + } + + return err; } // note if we fail, we at least leave mdir_/rid_ with the best place to insert diff --git a/tests/t3_mtree.toml b/tests/t3_mtree.toml index 1b24f9c9..3c8ec639 100644 --- a/tests/t3_mtree.toml +++ b/tests/t3_mtree.toml @@ -145,6 +145,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -217,6 +220,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -288,6 +294,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -387,6 +396,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create entries lfsr_mdir_t mdir; @@ -399,7 +411,7 @@ code = ''' mdir.rbyd.off = cfg->block_size; lfs.mroot.rbyd.off = cfg->block_size; } - + lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS( LFSR_ATTR(rid, INLINED, +1, &alphas[i % 26], 1))) => 0; @@ -481,6 +493,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -586,6 +601,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -653,6 +671,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -723,6 +744,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -780,6 +804,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an mdir that needs to be split uint8_t buffer[SIZE]; @@ -845,6 +872,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an mdir that needs to be split uint8_t buffer[SIZE]; @@ -910,6 +940,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an mdir that needs to be split uint8_t buffer[SIZE]; @@ -958,6 +991,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1050,6 +1086,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1142,6 +1181,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1221,6 +1263,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create entries lfsr_mdir_t mdir; @@ -1317,6 +1362,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; for (lfs_size_t cycle = 0; cycle < CYCLES; cycle++) { // create entries @@ -1412,6 +1460,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -1542,6 +1593,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -1635,6 +1689,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -1727,6 +1784,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -1819,6 +1879,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -1876,6 +1939,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -1932,6 +1998,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -1997,6 +2066,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -2101,6 +2173,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -2212,6 +2287,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -2292,6 +2370,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // force mroot to compact once, so the second compact below will trigger // a relocation @@ -2378,6 +2459,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // force mroot to compact once, so the second compact below will trigger // a relocation @@ -2475,6 +2559,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -2613,6 +2700,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2658,6 +2748,10 @@ code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; + lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2698,6 +2792,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2740,6 +2837,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2810,6 +2910,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2880,6 +2983,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2974,6 +3080,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -3036,6 +3145,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -3125,6 +3237,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // insert a new entry, this should update our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -3222,6 +3337,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -3352,6 +3470,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -3484,6 +3605,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -3595,6 +3719,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create entries lfsr_mdir_t mdir; @@ -3607,7 +3734,7 @@ code = ''' mdir.rbyd.off = cfg->block_size; lfs.mroot.rbyd.off = cfg->block_size; } - + lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS( LFSR_ATTR(rid, INLINED, +1, &alphas[i % 26], 1))) => 0; @@ -3746,6 +3873,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; diff --git a/tests/t4_alloc.toml b/tests/t4_alloc.toml index 2d18cd93..18c0acc1 100644 --- a/tests/t4_alloc.toml +++ b/tests/t4_alloc.toml @@ -102,6 +102,10 @@ code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; + lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, lfsr_mtree_weight(&lfs)-1, &mdir) => 0; diff --git a/tests/t5_dirs.toml b/tests/t5_dirs.toml index 9db61ac9..93dc0a03 100644 --- a/tests/t5_dirs.toml +++ b/tests/t5_dirs.toml @@ -27,6 +27,37 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +# test that creating the same directory twice errors +[cases.t5_dirs_mkdir_exists] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // make a directory + lfsr_mkdir(&lfs, "ardvark") => 0; + + // make the same directory, should error + lfsr_mkdir(&lfs, "ardvark") => LFS_ERR_EXIST; + + // cand check that this didn't interfere with our original directory + 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); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_unmount(&lfs) => 0; +''' + [cases.t5_dirs_mkdir_siblings] code = ''' lfs_t lfs; @@ -73,7 +104,7 @@ code = ''' lfsr_mkdir(&lfs, "ardvark/batman") => 0; lfsr_mkdir(&lfs, "ardvark/batman/cantaloupe") => 0; - // check that our mkdir worked + // check that our mkdirs worked lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; @@ -115,6 +146,314 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +[cases.t5_dirs_mkdir_many] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +code = ''' + lfs_t lfs; + 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; + } + + // check that our mkdir worked + 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.t5_dirs_mkdir_many_2layers] +defines.N = [1, 2, 4, 8, 16, 32] +code = ''' + lfs_t lfs; + 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; + + // 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; + } + } + + // check that our mkdirs worked + 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; + + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_open(&lfs, &dir, name) => 0; + 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 j = 0; j < N; j++) { + char name[256]; + sprintf(name, "child%04d", j); + 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.t5_dirs_mkdir_many_3layers] +defines.N = [1, 2, 4, 8] +code = ''' + lfs_t lfs; + 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; + + // 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; + + // 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; + } + } + } + + // check that our mkdirs worked + 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; + + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_open(&lfs, &dir, name) => 0; + 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 j = 0; j < N; j++) { + char name[256]; + sprintf(name, "child%04d", j); + 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; + + for (lfs_size_t j = 0; j < N; j++) { + char name[256]; + sprintf(name, "dir%04d/child%04d", i, j); + lfsr_dir_open(&lfs, &dir, name) => 0; + 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 k = 0; k < N; k++) { + char name[256]; + sprintf(name, "grandchild%04d", k); + 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.t5_dirs_mkdir_many_linkedlist] +defines.N = [1, 2, 4, 8, 16, 32, 64] +code = ''' + lfs_t lfs; + 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; + } + + // check that our mkdir worked + memset(name, 0, sizeof(name)); + for (lfs_size_t i = 0; i < N; i++) { + sprintf(&name[strlen(name)], "/dir%04d", i); + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, name) => 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); + if (i < N-1) { + char name2[256]; + sprintf(name2, "dir%04d", i+1); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name2) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + } + + lfsr_unmount(&lfs) => 0; +''' + +[cases.t5_dirs_mkdir_fuzz] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +defines.SAMPLES = 10 +# -1 => all pseudo-random seeds +# n => reproduce a specific seed +defines.SEED = -1 +code = ''' + // iterate through severals seeds that we can reproduce easily + for (uint32_t seed = (SEED == -1 ? 1 : SEED); + (SEED == -1 ? seed < SAMPLES+1 : seed == SEED); + seed++) { + printf("--- seed: %d ---\n", seed); + // reset lfs here each iteration + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // set up a simulation to compare against + lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); + lfs_size_t sim_size = 0; + + uint32_t prng = seed; + for (lfs_size_t i = 0; i < N; i++) { + // choose a pseudo-random number, truncate to 4 decimals + lfs_size_t x = TEST_PRNG(&prng) % 1000; + + // insert into our sim + for (lfs_size_t j = 0;; j++) { + if (j >= sim_size || sim[j] >= x) { + // already seen? skip + if (sim[j] == x) { + goto next; + } + + // insert + memmove(&sim[j+1], &sim[j], + (sim_size-j)*sizeof(lfs_size_t)); + sim_size += 1; + sim[j] = x; + break; + } + } + + // create a directory here + char name[256]; + sprintf(name, "dir%04d", x); + lfsr_mkdir(&lfs, name) => 0; + next:; + } + + // test that our directories match our simulation + 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 j = 0; j < sim_size; j++) { + char name[256]; + sprintf(name, "dir%04d", sim[j]); + 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; + + // clean up sim/lfs + free(sim); + lfsr_unmount(&lfs) => 0; + } +''' + +# TODO +# [cases.t5_dirs_did_collisions] +# [cases.t5_dirs_did_zero] +# [cases.t5_dirs_did_ones] +# [cases.t5_dirs_did_leb128_alignment] +