diff --git a/lfs.c b/lfs.c index 3d342d34..9f771ced 100644 --- a/lfs.c +++ b/lfs.c @@ -5208,11 +5208,37 @@ static bool lfsr_mid_isopen(lfs_t *lfs, lfsr_smid_t mid) { return false; } -// needed in lfsr_opened_clobber -static void lfsr_traversal_clobber(lfs_t *lfs, lfsr_traversal_t *t); +//static void lfsr_opened_clobber(lfs_t *lfs, lfsr_omdir_t *o) { +// for (lfsr_omdir_t *o_ = lfs->opened; o_; o_ = o_->next) { +// if (o_->type == LFS_TYPE_TRAVERSAL +// && ((lfsr_traversal_t*)o_)->mt.ot == &o->next) { +// lfsr_traversal_t *t = (lfsr_traversal_t*)o_; +// // move to next omdir +// t->mt.ot = &o->next->next; +// +// // and clear any pending blocks +// t->blocks[0] = -1; +// t->blocks[1] = -1; +// } +// } +//} +//// find any traversals that reference our opened mdir and move them +//// to the next unsync file +//static void lfsr_opened_clobber(lfs_t *lfs, lfsr_omdir_t *o) { +// for (lfsr_omdir_t *o_ = lfs->opened; o_; o_ = o_->next) { +// if (o_->type == LFS_TYPE_TRAVERSAL +// && ((lfsr_traversal_t*)o)->mt.ot == &o->next) { +// +// } +// } +//} +// // TODO // +//// needed in lfsr_opened_clobber +//static void lfsr_traversal_clobber(lfs_t *lfs, lfsr_traversal_t *t); +// //// clobber any traversals that match our mid, or all traversals if mid=-1 //static void lfsr_opened_clobber(lfs_t *lfs, lfsr_smid_t mid, bool dirty) { // for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { @@ -5453,8 +5479,7 @@ static int lfsr_shrub_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_, // this should include our current bshrub for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { lfsr_file_t *file_ = (lfsr_file_t*)o; - if ((file_->o.type == LFS_TYPE_REG - || file_->o.type == LFS_TYPE_TRAVERSAL) + if (file_->o.type == LFS_TYPE_REG && lfsr_bshrub_isbshrub(&file_->o.mdir, &file_->bshrub) && lfsr_shrub_cmp(&file_->bshrub.u.bshrub, shrub) == 0) { file_->bshrub_.u.bshrub.blocks[0] = rbyd_->blocks[0]; @@ -6829,6 +6854,9 @@ static int lfsr_mroot_parent(lfs_t *lfs, const lfsr_mptr_t *mptr, } } +// needed in lfsr_mdir_commit +static void lfsr_traversal_clobber(lfs_t *lfs, lfsr_traversal_t *t); + // high-level mdir commit // // this is atomic and updates any opened mdirs, lfs_t, etc @@ -6895,8 +6923,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, } // stage any bsprouts/bshrubs - if (o->type == LFS_TYPE_REG - || o->type == LFS_TYPE_TRAVERSAL) { + if (o->type == LFS_TYPE_REG) { lfsr_file_t *file = (lfsr_file_t*)o; file->bshrub_ = file->bshrub; } @@ -7391,13 +7418,35 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // update any staged bsprouts/bshrubs for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { - if (o->type == LFS_TYPE_REG - || o->type == LFS_TYPE_TRAVERSAL) { + if (o->type == LFS_TYPE_REG) { lfsr_file_t *file = (lfsr_file_t*)o; file->bshrub = file->bshrub_; } } + for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { + if (o->type == LFS_TYPE_TRAVERSAL) { + // mark all traversals as dirty + o->flags |= LFS_F_DIRTY; + + // clobber any related traversals + if (lfsr_mdir_cmp(&o->mdir, mdir) == 0) { + lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); + } + } + } + + // if mroot/mtree changed, clobber any related traversals + if (lfsr_mdir_cmp(&mroot_, &lfs->mroot) != 0 + || lfsr_mtree_cmp(&mtree_, &lfs->mtree) != 0) { + for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { + if (o->type == LFS_TYPE_TRAVERSAL + && o->mdir.mid == -1) { + lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); + } + } + } + // update internal mdir state for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { // avoid double updating the current mdir @@ -7431,20 +7480,6 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, mdir->rbyd = mdir_[0].rbyd; } - // mark all traversals as dirty - for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { - if (o->type == LFS_TYPE_TRAVERSAL) { - o->flags |= LFS_F_DIRTY; - - // clobber any mroot/mtree traversals - if (o->mdir.mid == -1 - && (lfsr_mdir_cmp(&mroot_, &lfs->mroot) != 0 - || lfsr_mtree_cmp(&mtree_, &lfs->mtree) != 0)) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); - } - } - } - // update mroot and mtree lfs->mroot = mroot_; lfs->mtree = mtree_; @@ -7844,22 +7879,55 @@ static void lfsr_fs_traverserewind(lfs_t *lfs, lfsr_mtraversal_t *mt) { } static void lfsr_fs_traverseclobber(lfs_t *lfs, lfsr_mtraversal_t *mt) { - (void)lfs; // increment the mid (to make progress) and reset to the mtree mt->o.state = LFSR_TSTATE_MTREE; - mt->o.mdir.mid = lfs_min( - mt->o.mdir.mid + 1, - lfsr_fs_weight(lfs)); + mt->o.mdir.mid = lfsr_mid_bid(lfs, mt->o.mdir.mid) + + (1 << lfs->mdir_bits); +// TODO +// mt->o.mdir.mid = lfs_min( +// mt->o.mdir.mid + 1, +// lfsr_fs_weight(lfs)); // TODO do something different with this maybe? mt->ot = NULL; } +// needed in lfsr_fs_traverseclobberopen +static inline bool lfsr_f_isunsync(uint32_t flags); + +static void lfsr_fs_traverseclobberopen(lfs_t *lfs, lfsr_mtraversal_t *mt) { + (void)lfs; + // TODO really this is the best we can do? + // move to next unsync opened file + while (true) { + lfsr_omdir_t *o = *mt->ot; + if (!o) { + mt->o.mdir.mid += 1; + mt->o.state = LFSR_TSTATE_MDIR; + break; + } + + if (o->mdir.mid != mt->o.mdir.mid + || o->type != LFS_TYPE_REG + || !lfsr_f_isunsync(o->flags)) { + mt->ot = &o->next; + continue; + } + + // TODO don't do all of this... + const lfsr_file_t *file = (const lfsr_file_t*)o; + mt->bshrub = file->bshrub; + mt->u.bt = LFSR_BTRAVERSAL(0); + mt->ot = &o->next; + mt->o.state = LFSR_TSTATE_BTREE; + break; + } +} + // alias mtinfo=btinfo typedef lfsr_btinfo_t lfsr_mtinfo_t; // needed in lfsr_fs_traverse_ -static inline bool lfsr_f_isunsync(uint32_t flags); static int lfsr_bshrub_traverse(lfs_t *lfs, const lfsr_file_t *file, lfsr_btraversal_t *bt, lfsr_bid_t *bid_, lfsr_btinfo_t *btinfo); @@ -9365,6 +9433,15 @@ static void lfsr_traversal_clobber(lfs_t *lfs, lfsr_traversal_t *t) { t->blocks[1] = -1; } +static void lfsr_traversal_clobberopen(lfs_t *lfs, lfsr_traversal_t *t) { + // clobber the low-level traversal + lfsr_fs_traverseclobberopen(lfs, &t->mt); + + // and clear any pending blocks + t->blocks[0] = -1; + t->blocks[1] = -1; +} + // needed in lfsr_traversal_open static int lfsr_traversal_rewind_(lfs_t *lfs, lfsr_traversal_t *t); @@ -9794,11 +9871,6 @@ int lfsr_remove(lfs_t *lfs, const char *path) { } else { ((lfsr_dir_t*)o)->pos -= 1; } - - // clobber any problematic traversals - } else if (o->type == LFS_TYPE_TRAVERSAL - && o->mdir.mid == mdir.mid) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); } } @@ -9979,12 +10051,6 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) { ((lfsr_dir_t*)o)->pos -= 1; } } - - // clobber any problematic traversals - } else if (o->type == LFS_TYPE_TRAVERSAL - && ((exists && o->mdir.mid == new_mdir.mid) - || o->mdir.mid == lfs->grm.mids[0])) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); } } @@ -10640,7 +10706,7 @@ int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file) { for (lfsr_omdir_t *o = lfs->opened; o; o = o->next) { if (o->type == LFS_TYPE_TRAVERSAL) { if (((lfsr_traversal_t*)o)->mt.ot == &file->o.next) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); + lfsr_traversal_clobberopen(lfs, (lfsr_traversal_t*)o); } } } @@ -11971,7 +12037,7 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file, if (o->type == LFS_TYPE_TRAVERSAL) { o->flags |= LFS_F_DIRTY; if (((lfsr_traversal_t*)o)->mt.ot == &file->o.next) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); + lfsr_traversal_clobberopen(lfs, (lfsr_traversal_t*)o); } } } @@ -12138,7 +12204,7 @@ int lfsr_file_flush(lfs_t *lfs, lfsr_file_t *file) { if (o->type == LFS_TYPE_TRAVERSAL) { o->flags |= LFS_F_DIRTY; if (((lfsr_traversal_t*)o)->mt.ot == &file->o.next) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); + lfsr_traversal_clobberopen(lfs, (lfsr_traversal_t*)o); } } } @@ -12315,11 +12381,6 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) { file->buffer.size); file_->buffer.size = file->buffer.size; } - - // clobber any problematic traversals - } else if (o->type == LFS_TYPE_TRAVERSAL - && o->mdir.mid == file->o.mdir.mid) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); } } @@ -12411,7 +12472,7 @@ int lfsr_file_truncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) { if (o->type == LFS_TYPE_TRAVERSAL) { o->flags |= LFS_F_DIRTY; if (((lfsr_traversal_t*)o)->mt.ot == &file->o.next) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); + lfsr_traversal_clobberopen(lfs, (lfsr_traversal_t*)o); } } } @@ -12524,7 +12585,7 @@ int lfsr_file_fruncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) { if (o->type == LFS_TYPE_TRAVERSAL) { o->flags |= LFS_F_DIRTY; if (((lfsr_traversal_t*)o)->mt.ot == &file->o.next) { - lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); + lfsr_traversal_clobberopen(lfs, (lfsr_traversal_t*)o); } } } diff --git a/lfs.h b/lfs.h index 36881658..3187f77b 100644 --- a/lfs.h +++ b/lfs.h @@ -610,7 +610,6 @@ typedef struct lfsr_mtraversal { // so only store the relevant bits, is this a hack? yes const struct lfs_file_config *cfg; lfsr_bshrub_t bshrub; - lfsr_bshrub_t bshrub_; // opened file state, we use an indirect pointer here so we // always point to data associated with the current mid diff --git a/tests/test_traversal.toml b/tests/test_traversal.toml index de0ce0c5..9e769f09 100644 --- a/tests/test_traversal.toml +++ b/tests/test_traversal.toml @@ -1690,6 +1690,11 @@ code = ''' lfsr_file_open(&lfs, &file, "spider", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfsr_file_close(&lfs, &file) => 0; + + // read should immediately error + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; + lfsr_traversal_close(&lfs, &t) => 0; + goto done; } lfsr_traversal_read(&lfs, &t, &tinfo) => 0; @@ -1707,6 +1712,7 @@ code = ''' lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; lfsr_traversal_close(&lfs, &t) => 0; +done:; lfsr_unmount(&lfs) => 0; ''' @@ -1816,12 +1822,10 @@ code = ''' if (WHEN == 1) { lfsr_mkdir(&lfs, "spider") => 0; - if (EXCL) { - // read should immediately error - struct lfs_tinfo tinfo; - lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; - goto done; - } + // read should immediately error + struct lfs_tinfo tinfo; + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; + goto done; } lfsr_traversal_read(&lfs, &t, &tinfo) => 0; @@ -1891,12 +1895,10 @@ code = ''' if (WHEN == 1) { lfsr_remove(&lfs, "spider") => 0; - if (EXCL) { - // read should immediately error - struct lfs_tinfo tinfo; - lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; - goto done; - } + // read should immediately error + struct lfs_tinfo tinfo; + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; + goto done; } lfsr_traversal_read(&lfs, &t, &tinfo) => 0; @@ -1966,12 +1968,10 @@ code = ''' if (WHEN == 1) { lfsr_rename(&lfs, "spider", "scorpion") => 0; - if (EXCL) { - // read should immediately error - struct lfs_tinfo tinfo; - lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; - goto done; - } + // read should immediately error + struct lfs_tinfo tinfo; + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; + goto done; } lfsr_traversal_read(&lfs, &t, &tinfo) => 0; @@ -2297,14 +2297,6 @@ code = ''' lfsr_file_write(&lfs, &file, wbuf1, SIZE) => SIZE; lfsr_file_close(&lfs, &file) => 0; - // traverse btree - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_BTREE); - // traverse two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); // we should be at end of traversal now lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; lfsr_traversal_close(&lfs, &t) => 0; @@ -2386,11 +2378,6 @@ code = ''' lfsr_file_write(&lfs, &file, wbuf1, SIZE) => SIZE; lfsr_file_close(&lfs, &file) => 0; - // traverse two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); // we should be at end of traversal now lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; lfsr_traversal_close(&lfs, &t) => 0; @@ -2636,11 +2623,6 @@ code = ''' } lfsr_file_write(&lfs, &file1, wbuf1, SIZE) => SIZE; - // traverse two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); // we should be at end of traversal now lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; lfsr_traversal_close(&lfs, &t) => 0; @@ -2807,17 +2789,21 @@ code = ''' } lfsr_file_close(&lfs, &file1) => 0; - // traverse btree - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_BTREE); - // traverse two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - // we should be at end of traversal now - lfsr_traversal_read(&lfs, &t, &tinfo) - => (DESYNC) ? LFS_ERR_NOENT : LFS_ERR_BUSY; + if (DESYNC) { + // traverse btree + lfsr_traversal_read(&lfs, &t, &tinfo) => 0; + assert(tinfo.btype == LFS_BTYPE_BTREE); + // traverse two data blocks + lfsr_traversal_read(&lfs, &t, &tinfo) => 0; + assert(tinfo.btype == LFS_BTYPE_DATA); + lfsr_traversal_read(&lfs, &t, &tinfo) => 0; + assert(tinfo.btype == LFS_BTYPE_DATA); + // we should be at end of traversal now + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT; + } else { + // we should be at end of traversal now + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; + } lfsr_traversal_close(&lfs, &t) => 0; lfsr_file_close(&lfs, &file2) => 0; @@ -2900,14 +2886,18 @@ code = ''' } lfsr_file_close(&lfs, &file1) => 0; - // traverse two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - // we should be at end of traversal now - lfsr_traversal_read(&lfs, &t, &tinfo) - => (DESYNC) ? LFS_ERR_NOENT : LFS_ERR_BUSY; + if (DESYNC) { + // traverse two data blocks + lfsr_traversal_read(&lfs, &t, &tinfo) => 0; + assert(tinfo.btype == LFS_BTYPE_DATA); + lfsr_traversal_read(&lfs, &t, &tinfo) => 0; + assert(tinfo.btype == LFS_BTYPE_DATA); + // we should be at end of traversal now + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT; + } else { + // we should be at end of traversal now + lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; + } lfsr_traversal_close(&lfs, &t) => 0; lfsr_file_close(&lfs, &file2) => 0; @@ -2989,26 +2979,6 @@ code = ''' i += 1; } - // traverse one mdir - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - // and two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - // and another mdir - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - // and another two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); // we should be at end of traversal now lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; lfsr_traversal_close(&lfs, &t) => 0; @@ -3099,26 +3069,6 @@ code = ''' i += 1; } - // traverse one mdir - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - // traverse two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - // and another mdir - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - // and another two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); // we should be at end of traversal now lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; lfsr_traversal_close(&lfs, &t) => 0; @@ -3219,16 +3169,6 @@ code = ''' i += 1; } - // and another mdir - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_MDIR); - // and another two data blocks - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - assert(tinfo.btype == LFS_BTYPE_DATA); // we should be at end of traversal now lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_BUSY; lfsr_traversal_close(&lfs, &t) => 0; @@ -3245,7 +3185,7 @@ code = ''' assert(memcmp(rbuf, wbuf2, SIZE) == 0); lfsr_file_close(&lfs, &file) => 0; - lfsr_file_open(&lfs, &file, "zoldarion", LFS_O_RDONLY) => 0; + lfsr_file_open(&lfs, &file, "zodarion", LFS_O_RDONLY) => 0; lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; assert(memcmp(rbuf, wbuf3, SIZE) == 0); lfsr_file_close(&lfs, &file) => 0;