diff --git a/lfs.c b/lfs.c index e1c41de..40744c9 100644 --- a/lfs.c +++ b/lfs.c @@ -451,31 +451,32 @@ static inline void lfs_global_zero(lfs_global_t *a) { } static inline void lfs_global_fromle32(lfs_global_t *a) { - lfs_pair_fromle32(a->s.movepair); - a->s.moveid = lfs_fromle16(a->s.moveid); + lfs_pair_fromle32(a->l.movepair); + a->l.moveid = lfs_fromle16(a->l.moveid); } static inline void lfs_global_tole32(lfs_global_t *a) { - lfs_pair_tole32(a->s.movepair); - a->s.moveid = lfs_tole16(a->s.moveid); + lfs_pair_tole32(a->l.movepair); + a->l.moveid = lfs_tole16(a->l.moveid); } static inline void lfs_global_move(lfs_t *lfs, const lfs_block_t pair[2], uint16_t id) { lfs_global_t diff; lfs_global_zero(&diff); - diff.s.movepair[0] ^= lfs->globals.s.movepair[0] ^ pair[0]; - diff.s.movepair[1] ^= lfs->globals.s.movepair[1] ^ pair[1]; - diff.s.moveid ^= lfs->globals.s.moveid ^ id; + diff.l.movepair[0] ^= lfs->globals.g.movepair[0] ^ pair[0]; + diff.l.movepair[1] ^= lfs->globals.g.movepair[1] ^ pair[1]; + diff.l.moveid ^= lfs->globals.g.moveid ^ id; lfs_global_fromle32(&lfs->locals); lfs_global_xor(&lfs->locals, &diff); lfs_global_tole32(&lfs->locals); lfs_global_xor(&lfs->globals, &diff); } -static inline void lfs_global_deorphaned(lfs_t *lfs, bool deorphaned) { - lfs->locals.s.deorphaned ^= lfs->globals.s.deorphaned ^ deorphaned; - lfs->globals.s.deorphaned ^= lfs->globals.s.deorphaned ^ deorphaned; +static inline void lfs_global_orphans(lfs_t *lfs, int8_t orphans) { + lfs->locals.l.deorphaned ^= (lfs->globals.g.orphans == 0); + lfs->locals.l.deorphaned ^= (lfs->globals.g.orphans + orphans == 0); + lfs->globals.g.orphans += orphans; } @@ -688,7 +689,7 @@ static int lfs_commit_globals(lfs_t *lfs, struct lfs_commit *commit, lfs_global_xor(locals, &lfs->locals); int err = lfs_commit_attr(lfs, commit, - LFS_MKTAG(LFS_TYPE_GLOBALS + locals->s.deorphaned, 0x3ff, 10), + LFS_MKTAG(LFS_TYPE_GLOBALS + locals->l.deorphaned, 0x3ff, 10), locals); lfs_global_xor(locals, &lfs->locals); return err; @@ -907,7 +908,7 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs, } lfs_pair_fromle32(temptail); } else if (lfs_tag_subtype(tag) == LFS_TYPE_GLOBALS) { - templocals.s.deorphaned = (lfs_tag_type(tag) & 1); + templocals.l.deorphaned = (lfs_tag_type(tag) & 1); err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag), &templocals, 10); if (err) { @@ -973,11 +974,11 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs, // consider what we have good enough if (dir->off > 0) { // synthetic move - if (lfs_pair_cmp(dir->pair, lfs->globals.s.movepair) == 0) { - if (lfs->globals.s.moveid == lfs_tag_id(foundtag)) { + if (lfs_pair_cmp(dir->pair, lfs->globals.g.movepair) == 0) { + if (lfs->globals.g.moveid == lfs_tag_id(foundtag)) { foundtag = LFS_ERR_NOENT; } else if (lfs_tag_isvalid(foundtag) && - lfs->globals.s.moveid < lfs_tag_id(foundtag)) { + lfs->globals.g.moveid < lfs_tag_id(foundtag)) { foundtag -= LFS_MKTAG(0, 1, 0); } } @@ -1026,8 +1027,8 @@ static int32_t lfs_dir_find(lfs_t *lfs, static int32_t lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir, uint32_t getmask, uint32_t gettag, void *buffer) { int32_t getdiff = 0; - if (lfs_pair_cmp(dir->pair, lfs->globals.s.movepair) == 0 && - lfs_tag_id(gettag) <= lfs->globals.s.moveid) { + if (lfs_pair_cmp(dir->pair, lfs->globals.g.movepair) == 0 && + lfs_tag_id(gettag) <= lfs->globals.g.moveid) { // synthetic moves getdiff = LFS_MKTAG(0, 1, 0); } @@ -1270,17 +1271,17 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattr_t cancelattr; lfs_global_t canceldiff; lfs_global_zero(&canceldiff); - if (lfs_pair_cmp(dir->pair, lfs->globals.s.movepair) == 0) { + if (lfs_pair_cmp(dir->pair, lfs->globals.g.movepair) == 0) { // Wait, we have the move? Just cancel this out here // We need to, or else the move can become outdated - canceldiff.s.movepair[0] ^= lfs->globals.s.movepair[0] ^ 0xffffffff; - canceldiff.s.movepair[1] ^= lfs->globals.s.movepair[1] ^ 0xffffffff; - canceldiff.s.moveid ^= lfs->globals.s.moveid ^ 0x3ff; + canceldiff.l.movepair[0] ^= lfs->globals.g.movepair[0] ^ 0xffffffff; + canceldiff.l.movepair[1] ^= lfs->globals.g.movepair[1] ^ 0xffffffff; + canceldiff.l.moveid ^= lfs->globals.g.moveid ^ 0x3ff; lfs_global_fromle32(&lfs->locals); lfs_global_xor(&lfs->locals, &canceldiff); lfs_global_tole32(&lfs->locals); - cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.s.moveid, 0); + cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.l.moveid, 0); cancelattr.next = attrs; attrs = &cancelattr; } @@ -2636,7 +2637,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { } // mark fs as orphaned - lfs_global_deorphaned(lfs, false); + lfs_global_orphans(lfs, +1); } // delete the entry @@ -2648,14 +2649,14 @@ int lfs_remove(lfs_t *lfs, const char *path) { } if (lfs_tag_type(tag) == LFS_TYPE_DIR) { + // fix orphan + lfs_global_orphans(lfs, -1); + err = lfs_fs_pred(lfs, dir.pair, &cwd); if (err) { return err; } - // fix orphan - lfs_global_deorphaned(lfs, true); - // steal state cwd.tail[0] = dir.tail[0]; cwd.tail[1] = dir.tail[1]; @@ -2696,36 +2697,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { uint16_t newid = lfs_tag_id(prevtag); lfs_mdir_t prevdir; - if (prevtag != LFS_ERR_NOENT) { - // check that we have same type - if (lfs_tag_type(prevtag) != lfs_tag_type(oldtag)) { - return LFS_ERR_ISDIR; - } - - if (lfs_tag_type(prevtag) == LFS_TYPE_DIR) { - // must be empty before removal - lfs_block_t prevpair[2]; - int32_t res = lfs_dir_get(lfs, &newcwd, 0x7c3ff000, - LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair); - if (res < 0) { - return res; - } - lfs_pair_fromle32(prevpair); - - // must be empty before removal - err = lfs_dir_fetch(lfs, &prevdir, prevpair); - if (err) { - return err; - } - - if (prevdir.count > 0 || prevdir.split) { - return LFS_ERR_NOTEMPTY; - } - - // mark fs as orphaned - lfs_global_deorphaned(lfs, false); - } - } else { + if (prevtag == LFS_ERR_NOENT) { // check that name fits lfs_size_t nlen = strlen(newpath); if (nlen > lfs->name_max) { @@ -2734,6 +2706,30 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { // get next id newid = newcwd.count; + } else if (lfs_tag_type(prevtag) != lfs_tag_type(oldtag)) { + return LFS_ERR_ISDIR; + } else if (lfs_tag_type(prevtag) == LFS_TYPE_DIR) { + // must be empty before removal + lfs_block_t prevpair[2]; + int32_t res = lfs_dir_get(lfs, &newcwd, 0x7c3ff000, + LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair); + if (res < 0) { + return res; + } + lfs_pair_fromle32(prevpair); + + // must be empty before removal + err = lfs_dir_fetch(lfs, &prevdir, prevpair); + if (err) { + return err; + } + + if (prevdir.count > 0 || prevdir.split) { + return LFS_ERR_NOTEMPTY; + } + + // mark fs as orphaned + lfs_global_orphans(lfs, +1); } // create move to fix later @@ -2758,14 +2754,14 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { } if (prevtag != LFS_ERR_NOENT && lfs_tag_type(prevtag) == LFS_TYPE_DIR) { + // fix orphan + lfs_global_orphans(lfs, -1); + err = lfs_fs_pred(lfs, prevdir.pair, &newcwd); if (err) { return err; } - // fix orphan - lfs_global_deorphaned(lfs, true); - // steal state newcwd.tail[0] = prevdir.tail[0]; newcwd.tail[1] = prevdir.tail[1]; @@ -2917,10 +2913,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { lfs->root[1] = 0xffffffff; lfs->mlist = NULL; lfs->seed = 0; - lfs->globals.s.movepair[0] = 0xffffffff; - lfs->globals.s.movepair[1] = 0xffffffff; - lfs->globals.s.moveid = 0x3ff; - lfs->globals.s.deorphaned = true; + lfs->globals.g.movepair[0] = 0xffffffff; + lfs->globals.g.movepair[1] = 0xffffffff; + lfs->globals.g.moveid = 0x3ff; + lfs->globals.g.orphans = 0; lfs_global_zero(&lfs->locals); return 0; @@ -3089,11 +3085,11 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs_global_fromle32(&lfs->locals); lfs_global_xor(&lfs->globals, &lfs->locals); lfs_global_zero(&lfs->locals); - if (!lfs_pair_isnull(lfs->globals.s.movepair)) { + if (!lfs_pair_isnull(lfs->globals.g.movepair)) { LFS_DEBUG("Found move %"PRIu32" %"PRIu32" %"PRIu32, - lfs->globals.s.movepair[0], - lfs->globals.s.movepair[1], - lfs->globals.s.moveid); + lfs->globals.g.movepair[0], + lfs->globals.g.movepair[1], + lfs->globals.g.moveid); } // setup free lookahead @@ -3254,7 +3250,8 @@ static int lfs_fs_relocate(lfs_t *lfs, if (tag != LFS_ERR_NOENT) { // update disk, this creates a desync - lfs_global_deorphaned(lfs, false); + lfs_global_orphans(lfs, +1); + lfs_pair_tole32(newpair); int err = lfs_dir_commit(lfs, &parent, &(lfs_mattr_t){.tag=tag, .buffer=newpair}); @@ -3263,8 +3260,8 @@ static int lfs_fs_relocate(lfs_t *lfs, return err; } - // clean up bad block, which should now be a desync - return lfs_fs_deorphan(lfs); + // next step, clean up orphans + lfs_global_orphans(lfs, -1); } // find pred @@ -3275,7 +3272,7 @@ static int lfs_fs_relocate(lfs_t *lfs, // if we can't find dir, it must be new if (err != LFS_ERR_NOENT) { - // just replace bad pair, no desync can occur + // replace bad pair, either we clean up desync, or no desync occured parent.tail[0] = newpair[0]; parent.tail[1] = newpair[1]; err = lfs_dir_commit(lfs, &parent, @@ -3359,20 +3356,20 @@ static int lfs_fs_deorphan(lfs_t *lfs) { } // mark orphans as fixed - lfs_global_deorphaned(lfs, true); + lfs_global_orphans(lfs, -lfs->globals.g.orphans); return 0; } static int lfs_fs_demove(lfs_t *lfs) { // Fix bad moves LFS_DEBUG("Fixing move %"PRIu32" %"PRIu32" %"PRIu32, - lfs->globals.s.movepair[0], - lfs->globals.s.movepair[1], - lfs->globals.s.moveid); + lfs->globals.g.movepair[0], + lfs->globals.g.movepair[1], + lfs->globals.g.moveid); // fetch and delete the moved entry lfs_mdir_t movedir; - int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.s.movepair); + int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.g.movepair); if (err) { return err; } @@ -3387,14 +3384,14 @@ static int lfs_fs_demove(lfs_t *lfs) { } static int lfs_fs_forceconsistency(lfs_t *lfs) { - if (!lfs->globals.s.deorphaned) { + if (lfs->globals.g.orphans) { int err = lfs_fs_deorphan(lfs); if (err) { return err; } } - if (lfs->globals.s.moveid != 0x3ff) { + if (lfs->globals.g.moveid != 0x3ff) { int err = lfs_fs_demove(lfs); if (err) { return err; diff --git a/lfs.h b/lfs.h index e816515..839cf83 100644 --- a/lfs.h +++ b/lfs.h @@ -302,8 +302,13 @@ typedef union lfs_global { struct { lfs_block_t movepair[2]; uint16_t moveid; - bool deorphaned; - } s; + uint8_t deorphaned; + } l; + struct { + lfs_block_t movepair[2]; + uint16_t moveid; + uint8_t orphans; + } g; } lfs_global_t; typedef struct lfs_mdir {