Added support for recursive removes in directories

"Recursion" here just refers to the ability to remove entries in a
directory while iterating over it. This is very useful when you just
want a directory gone, and can be extended to a "true" recursive remove
straightforwardly. This mainly tests that mid/rid updates in opened
mdirs are correct.

To make this work, we need to update opened dirs differently than files,
since opened dirs do not get marked as removed when its rid is removed
and contain an additional position in the dir that needs to be updated.

To keep track of the different types, littlefs now contains 2
linked-lists for opened mdirs. Maybe these should be correctly typed,
but by hiding the specific types behind an array of mdir linked-lists,
we can more efficiently iterate over both lists when necessary.

We should probably compare this approach to the type-tagged approach in
the previous littlefs implementation, but I think the idea of an array
of type-hidden linked-lists just didn't come to me then. There was also
a bit more room in the mdir structs to hide a 1-bit type field. The mdir
structs here are getting pretty squeezed since they are used everywhere.
This commit is contained in:
Christopher Haster
2023-07-20 15:22:43 -05:00
parent 0ddd851f6f
commit b1187595d6
4 changed files with 221 additions and 204 deletions
+69 -49
View File
@@ -5079,13 +5079,15 @@ static inline lfs_size_t lfsr_mdir_weight(const lfsr_mdir_t *mdir) {
} }
// track "opened" mdirs that may need to by updated // track "opened" mdirs that may need to by updated
static void lfsr_mdir_addopened(lfs_t *lfs, lfsr_openedmdir_t *opened) { static void lfsr_mdir_addopened(lfs_t *lfs,
opened->next = lfs->opened; uint8_t type, lfsr_openedmdir_t *opened) {
lfs->opened = opened; opened->next = lfs->opened[type];
lfs->opened[type] = opened;
} }
static void lfsr_mdir_removeopened(lfs_t *lfs, lfsr_openedmdir_t *opened) { static void lfsr_mdir_removeopened(lfs_t *lfs,
for (lfsr_openedmdir_t **p = &lfs->opened; *p; p = &(*p)->next) { uint8_t type, lfsr_openedmdir_t *opened) {
for (lfsr_openedmdir_t **p = &lfs->opened[type]; *p; p = &(*p)->next) {
if (*p == opened) { if (*p == opened) {
*p = (*p)->next; *p = (*p)->next;
break; break;
@@ -5093,8 +5095,9 @@ static void lfsr_mdir_removeopened(lfs_t *lfs, lfsr_openedmdir_t *opened) {
} }
} }
static bool lfsr_mdir_isopened(lfs_t *lfs, const lfsr_openedmdir_t *opened) { static bool lfsr_mdir_isopened(lfs_t *lfs,
for (lfsr_openedmdir_t *p = lfs->opened; p; p = p->next) { uint8_t type, const lfsr_openedmdir_t *opened) {
for (lfsr_openedmdir_t *p = lfs->opened[type]; p; p = p->next) {
if (p == opened) { if (p == opened) {
return true; return true;
} }
@@ -5669,6 +5672,7 @@ static int lfsr_mtree_split_(lfs_t *lfs, lfsr_btree_t *mtree_,
} else if (mdir_->rbyd.weight > 0) { } else if (mdir_->rbyd.weight > 0) {
LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}",
mdir_->rbyd.block, mdir_->redund_block); mdir_->rbyd.block, mdir_->redund_block);
mdir_->mid = LFSR_MID_RM;
// update our mtree // update our mtree
uint8_t buf[LFSR_MPTR_DSIZE]; uint8_t buf[LFSR_MPTR_DSIZE];
@@ -5687,6 +5691,7 @@ static int lfsr_mtree_split_(lfs_t *lfs, lfsr_btree_t *mtree_,
} else if (msibling_->rbyd.weight > 0) { } else if (msibling_->rbyd.weight > 0) {
LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}",
msibling_->rbyd.block, msibling_->redund_block); msibling_->rbyd.block, msibling_->redund_block);
msibling_->mid = LFSR_MID_RM;
// update our mtree // update our mtree
uint8_t buf[LFSR_MPTR_DSIZE]; uint8_t buf[LFSR_MPTR_DSIZE];
@@ -5707,6 +5712,8 @@ static int lfsr_mtree_split_(lfs_t *lfs, lfsr_btree_t *mtree_,
mdir_->rbyd.block, mdir_->redund_block); mdir_->rbyd.block, mdir_->redund_block);
LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}",
msibling_->rbyd.block, msibling_->redund_block); msibling_->rbyd.block, msibling_->redund_block);
mdir_->mid = LFSR_MID_RM;
msibling_->mid = LFSR_MID_RM;
// update our mtree // update our mtree
err = lfsr_btree_pop(lfs, mtree_, mid); err = lfsr_btree_pop(lfs, mtree_, mid);
@@ -5817,6 +5824,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_ssize_t *rid,
} else { } else {
LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}",
mdir_.rbyd.block, mdir_.redund_block); mdir_.rbyd.block, mdir_.redund_block);
mdir_.mid = LFSR_MID_RM;
// don't really need to update our mtree here // don't really need to update our mtree here
} }
@@ -5856,6 +5864,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_ssize_t *rid,
} else if (mdir->mid != LFSR_MID_MROOT && mdir_.rbyd.weight == 0) { } else if (mdir->mid != LFSR_MID_MROOT && mdir_.rbyd.weight == 0) {
LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir 0x{%"PRIx32",%"PRIx32"}",
mdir->rbyd.block, mdir->redund_block); mdir->rbyd.block, mdir->redund_block);
mdir_.mid = LFSR_MID_RM;
// update our mtree // update our mtree
err = lfsr_btree_pop(lfs, &mtree_, mdir->mid); err = lfsr_btree_pop(lfs, &mtree_, mdir->mid);
@@ -6116,48 +6125,58 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_ssize_t *rid,
} }
// update any opened mdirs // update any opened mdirs
for (lfsr_openedmdir_t *opened = lfs->opened; for (uint8_t type = 0; type < 2; type++) {
opened; for (lfsr_openedmdir_t *opened = lfs->opened[type];
opened = opened->next) { opened;
// avoid double-updating our current mdir opened = opened->next) {
if (&opened->mdir == mdir) { // avoid double-updating our current mdir
continue; if (&opened->mdir == mdir) {
} continue;
}
if (opened->mdir.mid == mdir->mid) {
LFS_ASSERT(opened->rid < (lfs_ssize_t)mdir->rbyd.weight);
// first play out any attrs that change our rid // first play out any attrs that change our rid
for (lfs_size_t i = 0; i < attr_count; i++) { for (lfs_size_t i = 0; i < attr_count; i++) {
if (opened->rid >= attrs[i].id) { if (opened->mdir.mid == mdir->mid
&& opened->rid >= attrs[i].id) {
LFS_ASSERT(opened->rid <= (lfs_ssize_t)mdir->rbyd.weight);
// removed? // removed?
if (opened->rid + attrs[i].delta < attrs[i].id) { if (type == LFS_TYPE_REG
opened->rid = -2; && opened->rid + attrs[i].delta < attrs[i].id) {
opened->mdir.mid = LFSR_MID_RM; opened->mdir.mid = LFSR_MID_RM;
} else { } else {
opened->rid += attrs[i].delta; opened->rid += attrs[i].delta;
} }
} }
// adjust dir positions if any delta changes
if (type == LFS_TYPE_DIR
&& (opened->mdir.mid > mdir->mid
|| (opened->mdir.mid == mdir->mid
&& opened->rid >= attrs[i].id))) {
((lfsr_dir_t*)opened)->pos += attrs[i].delta;
}
} }
// TODO wait shouldn't this be mid? // update mid if we had a split or drop
// update mdir to follow rid if (opened->mdir.mid == mdir->mid) {
if (opened->rid == -2) { if (opened->rid >= (lfs_ssize_t)mdir_.rbyd.weight) {
// skip removed mdirs LFS_ASSERT(lfsr_btree_weight(&mtree_)
} else if (opened->rid >= (lfs_ssize_t)mdir_.rbyd.weight) { != lfsr_mtree_weight(lfs));
LFS_ASSERT(lfsr_btree_weight(&mtree_) opened->rid = opened->rid - mdir_.rbyd.weight;
!= lfsr_mtree_weight(lfs)); opened->mdir = msibling_;
opened->rid = opened->rid - mdir_.rbyd.weight; } else {
opened->mdir = msibling_; opened->mdir = mdir_;
} else { // if dropped, rewind to previous mid, this is needed for
opened->mdir = mdir_; // dir read to find the next mdir correctly
if (type == LFS_TYPE_DIR && mdir_.mid == LFSR_MID_RM) {
opened->mdir.mid = mdir->mid - 1;
}
}
} else if (opened->mdir.mid > mdir->mid
&& lfsr_btree_weight(&mtree_) != lfsr_mtree_weight(lfs)) {
opened->mdir.mid += lfsr_btree_weight(&mtree_)
- lfsr_mtree_weight(lfs);
} }
// update mid if we had a split or drop
} else if (opened->mdir.mid > mdir->mid
&& lfsr_btree_weight(&mtree_) != lfsr_mtree_weight(lfs)) {
opened->mdir.mid += lfsr_btree_weight(&mtree_)
- lfsr_mtree_weight(lfs);
} }
} }
@@ -7300,7 +7319,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
// as "opened" temporarily // as "opened" temporarily
// TODO is this the best workaround for rid update issues? // TODO is this the best workaround for rid update issues?
parent.rid -= 1; parent.rid -= 1;
lfsr_mdir_addopened(lfs, &parent); lfsr_mdir_addopened(lfs, LFS_TYPE_REG, &parent);
// Conveniently, we just found where our dstart should go. The dstart // Conveniently, we just found where our dstart should go. The dstart
// tag is an empty entry that marks our directory as being allocated. // tag is an empty entry that marks our directory as being allocated.
@@ -7323,7 +7342,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
goto failed_with_parent; goto failed_with_parent;
} }
lfsr_mdir_removeopened(lfs, &parent); lfsr_mdir_removeopened(lfs, LFS_TYPE_REG, &parent);
parent.rid += 1; parent.rid += 1;
// commit our new directory into our parent, zeroing out our grm // commit our new directory into our parent, zeroing out our grm
@@ -7339,7 +7358,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
return 0; return 0;
failed_with_parent: failed_with_parent:
lfsr_mdir_removeopened(lfs, &parent); lfsr_mdir_removeopened(lfs, LFS_TYPE_REG, &parent);
return err; return err;
} }
@@ -7496,14 +7515,14 @@ int lfsr_dir_open(lfs_t *lfs, lfsr_dir_t *dir, const char *path) {
} }
// add to tracked mdirs // add to tracked mdirs
lfsr_mdir_addopened(lfs, &dir->mdir); lfsr_mdir_addopened(lfs, LFS_TYPE_DIR, &dir->mdir);
dir->off = 0; dir->pos = 0;
return 0; return 0;
} }
int lfsr_dir_close(lfs_t *lfs, lfsr_dir_t *dir) { int lfsr_dir_close(lfs_t *lfs, lfsr_dir_t *dir) {
// remove from tracked mdirs // remove from tracked mdirs
lfsr_mdir_removeopened(lfs, &dir->mdir); lfsr_mdir_removeopened(lfs, LFS_TYPE_DIR, &dir->mdir);
return 0; return 0;
} }
@@ -7539,15 +7558,15 @@ int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info) {
memset(info, 0, sizeof(struct lfs_info)); memset(info, 0, sizeof(struct lfs_info));
// handle "." and ".." specially // handle "." and ".." specially
if (dir->off == 0) { if (dir->pos == 0) {
info->type = LFS_TYPE_DIR; info->type = LFS_TYPE_DIR;
strcpy(info->name, "."); strcpy(info->name, ".");
dir->off += 1; dir->pos += 1;
return 0; return 0;
} else if (dir->off == 1) { } else if (dir->pos == 1) {
info->type = LFS_TYPE_DIR; info->type = LFS_TYPE_DIR;
strcpy(info->name, ".."); strcpy(info->name, "..");
dir->off += 1; dir->pos += 1;
return 0; return 0;
} }
@@ -11131,8 +11150,9 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
// TODO maybe reorganize this function? // TODO maybe reorganize this function?
// zero opened mdir list // zero linked-lists of opened mdirs
lfs->opened = NULL; lfs->opened[LFS_TYPE_REG] = NULL;
lfs->opened[LFS_TYPE_DIR] = NULL;
// zero gstate // zero gstate
memset(lfs->grm, 0, LFSR_GRM_DSIZE); memset(lfs->grm, 0, LFSR_GRM_DSIZE);
+4 -3
View File
@@ -420,7 +420,7 @@ typedef struct lfs_dir {
typedef struct lfsr_dir { typedef struct lfsr_dir {
lfsr_openedmdir_t mdir; lfsr_openedmdir_t mdir;
lfs_off_t off; lfs_off_t pos;
} lfsr_dir_t; } lfsr_dir_t;
// littlefs file type // littlefs file type
@@ -500,8 +500,9 @@ typedef struct lfs {
uint8_t grm[LFSR_GRM_DSIZE]; uint8_t grm[LFSR_GRM_DSIZE];
uint8_t grmd[LFSR_GRM_DSIZE]; uint8_t grmd[LFSR_GRM_DSIZE];
// linked-list of opened mdirs // linked-lists of opened mdirs, we keep a separate linked-list
lfsr_openedmdir_t *opened; // for each type since these need to be handled a bit differently
lfsr_openedmdir_t *opened[2];
#ifdef LFS_MIGRATE #ifdef LFS_MIGRATE
struct lfs1 *lfs1; struct lfs1 *lfs1;
+42 -44
View File
@@ -2680,8 +2680,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// insert a new entry, this should update our neighbors // insert a new entry, this should update our neighbors
lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS(
@@ -2703,8 +2703,8 @@ code = '''
assert(right_neighbor.mdir.mid == -1); assert(right_neighbor.mdir.mid == -1);
assert(memcmp(&right_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -2729,8 +2729,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// try removing our left entry // try removing our left entry
lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS(
@@ -2740,14 +2740,13 @@ code = '''
assert(lfs.mroot.rbyd.weight == 1); assert(lfs.mroot.rbyd.weight == 1);
// assert that our neighbors were updated correctly // assert that our neighbors were updated correctly
assert(left_neighbor.rid == -2); assert(left_neighbor.mdir.mid == LFSR_MID_RM);
assert(left_neighbor.mdir.mid == -2);
assert(right_neighbor.rid == 0); assert(right_neighbor.rid == 0);
assert(right_neighbor.mdir.mid == -1); assert(right_neighbor.mdir.mid == -1);
assert(memcmp(&right_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -2772,8 +2771,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// try removing our left entry // try removing our left entry
lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS(
@@ -2786,11 +2785,10 @@ code = '''
assert(left_neighbor.rid == 0); assert(left_neighbor.rid == 0);
assert(left_neighbor.mdir.mid == -1); assert(left_neighbor.mdir.mid == -1);
assert(memcmp(&left_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&left_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0);
assert(right_neighbor.rid == -2); assert(right_neighbor.mdir.mid == LFSR_MID_RM);
assert(right_neighbor.mdir.mid == -2);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -2817,8 +2815,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// prepare mroot with a large attr so the next entry can not fit // prepare mroot with a large attr so the next entry can not fit
uint8_t buffer[SIZE]; uint8_t buffer[SIZE];
@@ -2862,8 +2860,8 @@ code = '''
assert(right_neighbor.mdir.mid == 0); assert(right_neighbor.mdir.mid == 0);
assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -2890,8 +2888,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// create 2 large entries that needs to be uninlined and split // create 2 large entries that needs to be uninlined and split
uint8_t buffer[SIZE]; uint8_t buffer[SIZE];
@@ -2935,8 +2933,8 @@ code = '''
assert(right_neighbor.mdir.mid == 1); assert(right_neighbor.mdir.mid == 1);
assert(memcmp(&right_neighbor.mdir, &msibling, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &msibling, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -2963,8 +2961,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// create an uninlined mdir // create an uninlined mdir
uint8_t buffer[SIZE]; uint8_t buffer[SIZE];
@@ -3030,8 +3028,8 @@ code = '''
assert(right_neighbor.mdir.mid == 1); assert(right_neighbor.mdir.mid == 1);
assert(memcmp(&right_neighbor.mdir, &msibling, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &msibling, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -3060,8 +3058,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// prepare mroot with an attr // prepare mroot with an attr
uint8_t buffer[SIZE]; uint8_t buffer[SIZE];
@@ -3095,8 +3093,8 @@ code = '''
assert(right_neighbor.mdir.mid == -1); assert(right_neighbor.mdir.mid == -1);
assert(memcmp(&right_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &lfs.mroot, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -3125,8 +3123,8 @@ code = '''
lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot}; lfsr_openedmdir_t left_neighbor = {.rid=0, .mdir=lfs.mroot};
lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot}; lfsr_openedmdir_t right_neighbor = {.rid=1, .mdir=lfs.mroot};
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// prepare mroot with a large attr so the next entry can not fit // prepare mroot with a large attr so the next entry can not fit
uint8_t buffer[SIZE]; uint8_t buffer[SIZE];
@@ -3186,8 +3184,8 @@ code = '''
assert(right_neighbor.mdir.mid == 0); assert(right_neighbor.mdir.mid == 0);
assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -3254,8 +3252,8 @@ code = '''
assert(right_neighbor.mdir.rbyd.weight == 1); assert(right_neighbor.mdir.rbyd.weight == 1);
right_neighbor.rid = 0; right_neighbor.rid = 0;
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// cause middle mdir to split // cause middle mdir to split
lfsr_mtree_lookup(&lfs, 1, &mdir) => 0; lfsr_mtree_lookup(&lfs, 1, &mdir) => 0;
@@ -3282,8 +3280,8 @@ code = '''
lfsr_mtree_lookup(&lfs, 3, &mdir) => 0; lfsr_mtree_lookup(&lfs, 3, &mdir) => 0;
assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
@@ -3350,8 +3348,8 @@ code = '''
assert(right_neighbor.mdir.rbyd.weight == 1); assert(right_neighbor.mdir.rbyd.weight == 1);
right_neighbor.rid = 0; right_neighbor.rid = 0;
lfsr_mdir_addopened(&lfs, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_addopened(&lfs, &right_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_REG, &right_neighbor);
// cause middle mdir to drop // cause middle mdir to drop
lfsr_mtree_lookup(&lfs, 1, &mdir) => 0; lfsr_mtree_lookup(&lfs, 1, &mdir) => 0;
@@ -3373,8 +3371,8 @@ code = '''
lfsr_mtree_lookup(&lfs, 1, &mdir) => 0; lfsr_mtree_lookup(&lfs, 1, &mdir) => 0;
assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0); assert(memcmp(&right_neighbor.mdir, &mdir, sizeof(lfsr_mdir_t)) == 0);
lfsr_mdir_removeopened(&lfs, &left_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &left_neighbor);
lfsr_mdir_removeopened(&lfs, &right_neighbor); lfsr_mdir_removeopened(&lfs, LFS_TYPE_REG, &right_neighbor);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
+106 -108
View File
@@ -2803,115 +2803,113 @@ code = '''
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
# TODO this eventually # Recursive here just refers to deleting entries in a directory while
# iterating over the directory
# #
## Recursive here just refers to deleting entries in a directory while # This is a useful feature, but it's unintuitive that this should have
## iterating over the directory # well-defined behavior, so make sure to test for it
## [cases.t5_dirs_rm_many_recursive]
## This is a useful feature, but it's unintuitive that this should have defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
## well-defined behavior, so make sure to test for it defines.PARENT = [false, true]
#[cases.t5_dirs_rm_many_recursive] # this test sort of fights against itself when powerloss testing,
#defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] # limit it to a _very_ small number of entries for this reason
#defines.PARENT = [false, true] if = '!TEST_PL || N <= 32'
## this test sort of fights against itself when powerloss testing, reentrant = true
## limit it to a _very_ small number of entries for this reason code = '''
#if = '!TEST_PL || N <= 32' // format once per test
#reentrant = true lfs_t lfs;
#code = ''' int err = lfsr_mount(&lfs, cfg);
# // format once per test if (err) {
# lfs_t lfs; lfsr_format(&lfs, cfg) => 0;
# int err = lfsr_mount(&lfs, cfg); lfsr_mount(&lfs, cfg) => 0;
# if (err) { }
# lfsr_format(&lfs, cfg) => 0;
# lfsr_mount(&lfs, cfg) => 0; if (PARENT) {
# } err = lfsr_mkdir(&lfs, "pricklypear");
# assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
# if (PARENT) { }
# err = lfsr_mkdir(&lfs, "pricklypear");
# assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // make this many directories
# } for (lfs_size_t i = 0; i < N; i++) {
# char name[256];
# // make this many directories sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i);
# for (lfs_size_t i = 0; i < N; i++) { err = lfsr_mkdir(&lfs, name);
# char name[256]; assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
# sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); }
# err = lfsr_mkdir(&lfs, name);
# assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // check that our mkdir worked
# } for (lfs_size_t i = 0; i < N; i++) {
# char name[256];
# // check that our mkdir worked sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i);
# for (lfs_size_t i = 0; i < N; i++) { struct lfs_info info;
# char name[256]; lfsr_stat(&lfs, name, &info) => 0;
# sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); char name2[256];
# struct lfs_info info; sprintf(name2, "dir%04d", i);
# lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name2) == 0);
# char name2[256]; assert(info.type == LFS_TYPE_DIR);
# sprintf(name2, "dir%04d", i); }
# assert(strcmp(info.name, name2) == 0);
# assert(info.type == LFS_TYPE_DIR); lfsr_dir_t dir;
# } lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
# struct lfs_info info;
# lfsr_dir_t dir; lfsr_dir_read(&lfs, &dir, &info) => 0;
# lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; assert(strcmp(info.name, ".") == 0);
# struct lfs_info info; assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
# assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0; for (lfs_size_t i = 0; i < N; i++) {
# assert(strcmp(info.name, "..") == 0); char name[256];
# assert(info.type == LFS_TYPE_DIR); sprintf(name, "dir%04d", i);
# for (lfs_size_t i = 0; i < N; i++) { lfsr_dir_read(&lfs, &dir, &info) => 0;
# char name[256]; assert(strcmp(info.name, name) == 0);
# sprintf(name, "dir%04d", i); assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0; }
# assert(strcmp(info.name, name) == 0); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
# assert(info.type == LFS_TYPE_DIR); lfsr_dir_close(&lfs, &dir) => 0;
# }
# lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; // now remove directories recursively
# lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
# lfsr_dir_read(&lfs, &dir, &info) => 0;
# // now remove directories recursively assert(strcmp(info.name, ".") == 0);
# lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
# assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0; for (lfs_size_t i = 0; i < N; i++) {
# assert(strcmp(info.name, "..") == 0); char name[256];
# assert(info.type == LFS_TYPE_DIR); sprintf(name, "dir%04d", i);
# for (lfs_size_t i = 0; i < N; i++) { lfsr_dir_read(&lfs, &dir, &info) => 0;
# char name[256]; assert(strcmp(info.name, name) == 0);
# sprintf(name, "dir%04d", i); assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0;
# assert(strcmp(info.name, name) == 0); char path[1024];
# assert(info.type == LFS_TYPE_DIR); sprintf(path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name);
# lfsr_remove(&lfs, path) => 0;
# char path[1024]; }
# sprintf(path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
# lfsr_remove(&lfs, path) => 0; lfsr_dir_close(&lfs, &dir) => 0;
# }
# lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; // check that our removes worked
# lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) {
# char name[256];
# // check that our removes worked sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i);
# for (lfs_size_t i = 0; i < N; i++) { struct lfs_info info;
# char name[256]; lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
# sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); }
# struct lfs_info info;
# lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
# } lfsr_dir_read(&lfs, &dir, &info) => 0;
# assert(strcmp(info.name, ".") == 0);
# lfsr_dir_open(&lfs, &dir, "/") => 0; assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
# assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
# assert(strcmp(info.name, "..") == 0); lfsr_dir_close(&lfs, &dir) => 0;
# assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_unmount(&lfs) => 0;
# lfsr_dir_close(&lfs, &dir) => 0; '''
#
# lfsr_unmount(&lfs) => 0;
#'''
[cases.t5_dirs_rm_fuzz] [cases.t5_dirs_rm_fuzz]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]