mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 08:48:31 +01:00
WIP Changed deorphan to only use one pass for pred fix
This commit is contained in:
125
lfs.c
125
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) {
|
static inline void lfs_global_fromle32(lfs_global_t *a) {
|
||||||
lfs_pair_fromle32(a->s.movepair);
|
lfs_pair_fromle32(a->l.movepair);
|
||||||
a->s.moveid = lfs_fromle16(a->s.moveid);
|
a->l.moveid = lfs_fromle16(a->l.moveid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lfs_global_tole32(lfs_global_t *a) {
|
static inline void lfs_global_tole32(lfs_global_t *a) {
|
||||||
lfs_pair_tole32(a->s.movepair);
|
lfs_pair_tole32(a->l.movepair);
|
||||||
a->s.moveid = lfs_tole16(a->s.moveid);
|
a->l.moveid = lfs_tole16(a->l.moveid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lfs_global_move(lfs_t *lfs,
|
static inline void lfs_global_move(lfs_t *lfs,
|
||||||
const lfs_block_t pair[2], uint16_t id) {
|
const lfs_block_t pair[2], uint16_t id) {
|
||||||
lfs_global_t diff;
|
lfs_global_t diff;
|
||||||
lfs_global_zero(&diff);
|
lfs_global_zero(&diff);
|
||||||
diff.s.movepair[0] ^= lfs->globals.s.movepair[0] ^ pair[0];
|
diff.l.movepair[0] ^= lfs->globals.g.movepair[0] ^ pair[0];
|
||||||
diff.s.movepair[1] ^= lfs->globals.s.movepair[1] ^ pair[1];
|
diff.l.movepair[1] ^= lfs->globals.g.movepair[1] ^ pair[1];
|
||||||
diff.s.moveid ^= lfs->globals.s.moveid ^ id;
|
diff.l.moveid ^= lfs->globals.g.moveid ^ id;
|
||||||
lfs_global_fromle32(&lfs->locals);
|
lfs_global_fromle32(&lfs->locals);
|
||||||
lfs_global_xor(&lfs->locals, &diff);
|
lfs_global_xor(&lfs->locals, &diff);
|
||||||
lfs_global_tole32(&lfs->locals);
|
lfs_global_tole32(&lfs->locals);
|
||||||
lfs_global_xor(&lfs->globals, &diff);
|
lfs_global_xor(&lfs->globals, &diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lfs_global_deorphaned(lfs_t *lfs, bool deorphaned) {
|
static inline void lfs_global_orphans(lfs_t *lfs, int8_t orphans) {
|
||||||
lfs->locals.s.deorphaned ^= lfs->globals.s.deorphaned ^ deorphaned;
|
lfs->locals.l.deorphaned ^= (lfs->globals.g.orphans == 0);
|
||||||
lfs->globals.s.deorphaned ^= lfs->globals.s.deorphaned ^ deorphaned;
|
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);
|
lfs_global_xor(locals, &lfs->locals);
|
||||||
int err = lfs_commit_attr(lfs, commit,
|
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);
|
locals);
|
||||||
lfs_global_xor(locals, &lfs->locals);
|
lfs_global_xor(locals, &lfs->locals);
|
||||||
return err;
|
return err;
|
||||||
@@ -907,7 +908,7 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
lfs_pair_fromle32(temptail);
|
lfs_pair_fromle32(temptail);
|
||||||
} else if (lfs_tag_subtype(tag) == LFS_TYPE_GLOBALS) {
|
} 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),
|
err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
|
||||||
&templocals, 10);
|
&templocals, 10);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -973,11 +974,11 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
|
|||||||
// consider what we have good enough
|
// consider what we have good enough
|
||||||
if (dir->off > 0) {
|
if (dir->off > 0) {
|
||||||
// synthetic move
|
// synthetic move
|
||||||
if (lfs_pair_cmp(dir->pair, lfs->globals.s.movepair) == 0) {
|
if (lfs_pair_cmp(dir->pair, lfs->globals.g.movepair) == 0) {
|
||||||
if (lfs->globals.s.moveid == lfs_tag_id(foundtag)) {
|
if (lfs->globals.g.moveid == lfs_tag_id(foundtag)) {
|
||||||
foundtag = LFS_ERR_NOENT;
|
foundtag = LFS_ERR_NOENT;
|
||||||
} else if (lfs_tag_isvalid(foundtag) &&
|
} 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);
|
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,
|
static int32_t lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir,
|
||||||
uint32_t getmask, uint32_t gettag, void *buffer) {
|
uint32_t getmask, uint32_t gettag, void *buffer) {
|
||||||
int32_t getdiff = 0;
|
int32_t getdiff = 0;
|
||||||
if (lfs_pair_cmp(dir->pair, lfs->globals.s.movepair) == 0 &&
|
if (lfs_pair_cmp(dir->pair, lfs->globals.g.movepair) == 0 &&
|
||||||
lfs_tag_id(gettag) <= lfs->globals.s.moveid) {
|
lfs_tag_id(gettag) <= lfs->globals.g.moveid) {
|
||||||
// synthetic moves
|
// synthetic moves
|
||||||
getdiff = LFS_MKTAG(0, 1, 0);
|
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_mattr_t cancelattr;
|
||||||
lfs_global_t canceldiff;
|
lfs_global_t canceldiff;
|
||||||
lfs_global_zero(&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
|
// Wait, we have the move? Just cancel this out here
|
||||||
// We need to, or else the move can become outdated
|
// We need to, or else the move can become outdated
|
||||||
canceldiff.s.movepair[0] ^= lfs->globals.s.movepair[0] ^ 0xffffffff;
|
canceldiff.l.movepair[0] ^= lfs->globals.g.movepair[0] ^ 0xffffffff;
|
||||||
canceldiff.s.movepair[1] ^= lfs->globals.s.movepair[1] ^ 0xffffffff;
|
canceldiff.l.movepair[1] ^= lfs->globals.g.movepair[1] ^ 0xffffffff;
|
||||||
canceldiff.s.moveid ^= lfs->globals.s.moveid ^ 0x3ff;
|
canceldiff.l.moveid ^= lfs->globals.g.moveid ^ 0x3ff;
|
||||||
lfs_global_fromle32(&lfs->locals);
|
lfs_global_fromle32(&lfs->locals);
|
||||||
lfs_global_xor(&lfs->locals, &canceldiff);
|
lfs_global_xor(&lfs->locals, &canceldiff);
|
||||||
lfs_global_tole32(&lfs->locals);
|
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;
|
cancelattr.next = attrs;
|
||||||
attrs = &cancelattr;
|
attrs = &cancelattr;
|
||||||
}
|
}
|
||||||
@@ -2636,7 +2637,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark fs as orphaned
|
// mark fs as orphaned
|
||||||
lfs_global_deorphaned(lfs, false);
|
lfs_global_orphans(lfs, +1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the entry
|
// delete the entry
|
||||||
@@ -2648,14 +2649,14 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lfs_tag_type(tag) == LFS_TYPE_DIR) {
|
if (lfs_tag_type(tag) == LFS_TYPE_DIR) {
|
||||||
|
// fix orphan
|
||||||
|
lfs_global_orphans(lfs, -1);
|
||||||
|
|
||||||
err = lfs_fs_pred(lfs, dir.pair, &cwd);
|
err = lfs_fs_pred(lfs, dir.pair, &cwd);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix orphan
|
|
||||||
lfs_global_deorphaned(lfs, true);
|
|
||||||
|
|
||||||
// steal state
|
// steal state
|
||||||
cwd.tail[0] = dir.tail[0];
|
cwd.tail[0] = dir.tail[0];
|
||||||
cwd.tail[1] = dir.tail[1];
|
cwd.tail[1] = dir.tail[1];
|
||||||
@@ -2696,13 +2697,18 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
uint16_t newid = lfs_tag_id(prevtag);
|
uint16_t newid = lfs_tag_id(prevtag);
|
||||||
|
|
||||||
lfs_mdir_t prevdir;
|
lfs_mdir_t prevdir;
|
||||||
if (prevtag != LFS_ERR_NOENT) {
|
if (prevtag == LFS_ERR_NOENT) {
|
||||||
// check that we have same type
|
// check that name fits
|
||||||
if (lfs_tag_type(prevtag) != lfs_tag_type(oldtag)) {
|
lfs_size_t nlen = strlen(newpath);
|
||||||
return LFS_ERR_ISDIR;
|
if (nlen > lfs->name_max) {
|
||||||
|
return LFS_ERR_NAMETOOLONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lfs_tag_type(prevtag) == LFS_TYPE_DIR) {
|
// 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
|
// must be empty before removal
|
||||||
lfs_block_t prevpair[2];
|
lfs_block_t prevpair[2];
|
||||||
int32_t res = lfs_dir_get(lfs, &newcwd, 0x7c3ff000,
|
int32_t res = lfs_dir_get(lfs, &newcwd, 0x7c3ff000,
|
||||||
@@ -2723,17 +2729,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark fs as orphaned
|
// mark fs as orphaned
|
||||||
lfs_global_deorphaned(lfs, false);
|
lfs_global_orphans(lfs, +1);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// check that name fits
|
|
||||||
lfs_size_t nlen = strlen(newpath);
|
|
||||||
if (nlen > lfs->name_max) {
|
|
||||||
return LFS_ERR_NAMETOOLONG;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get next id
|
|
||||||
newid = newcwd.count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create move to fix later
|
// 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) {
|
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);
|
err = lfs_fs_pred(lfs, prevdir.pair, &newcwd);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix orphan
|
|
||||||
lfs_global_deorphaned(lfs, true);
|
|
||||||
|
|
||||||
// steal state
|
// steal state
|
||||||
newcwd.tail[0] = prevdir.tail[0];
|
newcwd.tail[0] = prevdir.tail[0];
|
||||||
newcwd.tail[1] = prevdir.tail[1];
|
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->root[1] = 0xffffffff;
|
||||||
lfs->mlist = NULL;
|
lfs->mlist = NULL;
|
||||||
lfs->seed = 0;
|
lfs->seed = 0;
|
||||||
lfs->globals.s.movepair[0] = 0xffffffff;
|
lfs->globals.g.movepair[0] = 0xffffffff;
|
||||||
lfs->globals.s.movepair[1] = 0xffffffff;
|
lfs->globals.g.movepair[1] = 0xffffffff;
|
||||||
lfs->globals.s.moveid = 0x3ff;
|
lfs->globals.g.moveid = 0x3ff;
|
||||||
lfs->globals.s.deorphaned = true;
|
lfs->globals.g.orphans = 0;
|
||||||
lfs_global_zero(&lfs->locals);
|
lfs_global_zero(&lfs->locals);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3089,11 +3085,11 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
lfs_global_fromle32(&lfs->locals);
|
lfs_global_fromle32(&lfs->locals);
|
||||||
lfs_global_xor(&lfs->globals, &lfs->locals);
|
lfs_global_xor(&lfs->globals, &lfs->locals);
|
||||||
lfs_global_zero(&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_DEBUG("Found move %"PRIu32" %"PRIu32" %"PRIu32,
|
||||||
lfs->globals.s.movepair[0],
|
lfs->globals.g.movepair[0],
|
||||||
lfs->globals.s.movepair[1],
|
lfs->globals.g.movepair[1],
|
||||||
lfs->globals.s.moveid);
|
lfs->globals.g.moveid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup free lookahead
|
// setup free lookahead
|
||||||
@@ -3254,7 +3250,8 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|||||||
|
|
||||||
if (tag != LFS_ERR_NOENT) {
|
if (tag != LFS_ERR_NOENT) {
|
||||||
// update disk, this creates a desync
|
// update disk, this creates a desync
|
||||||
lfs_global_deorphaned(lfs, false);
|
lfs_global_orphans(lfs, +1);
|
||||||
|
|
||||||
lfs_pair_tole32(newpair);
|
lfs_pair_tole32(newpair);
|
||||||
int err = lfs_dir_commit(lfs, &parent,
|
int err = lfs_dir_commit(lfs, &parent,
|
||||||
&(lfs_mattr_t){.tag=tag, .buffer=newpair});
|
&(lfs_mattr_t){.tag=tag, .buffer=newpair});
|
||||||
@@ -3263,8 +3260,8 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up bad block, which should now be a desync
|
// next step, clean up orphans
|
||||||
return lfs_fs_deorphan(lfs);
|
lfs_global_orphans(lfs, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// find pred
|
// 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 we can't find dir, it must be new
|
||||||
if (err != LFS_ERR_NOENT) {
|
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[0] = newpair[0];
|
||||||
parent.tail[1] = newpair[1];
|
parent.tail[1] = newpair[1];
|
||||||
err = lfs_dir_commit(lfs, &parent,
|
err = lfs_dir_commit(lfs, &parent,
|
||||||
@@ -3359,20 +3356,20 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark orphans as fixed
|
// mark orphans as fixed
|
||||||
lfs_global_deorphaned(lfs, true);
|
lfs_global_orphans(lfs, -lfs->globals.g.orphans);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lfs_fs_demove(lfs_t *lfs) {
|
static int lfs_fs_demove(lfs_t *lfs) {
|
||||||
// Fix bad moves
|
// Fix bad moves
|
||||||
LFS_DEBUG("Fixing move %"PRIu32" %"PRIu32" %"PRIu32,
|
LFS_DEBUG("Fixing move %"PRIu32" %"PRIu32" %"PRIu32,
|
||||||
lfs->globals.s.movepair[0],
|
lfs->globals.g.movepair[0],
|
||||||
lfs->globals.s.movepair[1],
|
lfs->globals.g.movepair[1],
|
||||||
lfs->globals.s.moveid);
|
lfs->globals.g.moveid);
|
||||||
|
|
||||||
// fetch and delete the moved entry
|
// fetch and delete the moved entry
|
||||||
lfs_mdir_t movedir;
|
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) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -3387,14 +3384,14 @@ static int lfs_fs_demove(lfs_t *lfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int lfs_fs_forceconsistency(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);
|
int err = lfs_fs_deorphan(lfs);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lfs->globals.s.moveid != 0x3ff) {
|
if (lfs->globals.g.moveid != 0x3ff) {
|
||||||
int err = lfs_fs_demove(lfs);
|
int err = lfs_fs_demove(lfs);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
9
lfs.h
9
lfs.h
@@ -302,8 +302,13 @@ typedef union lfs_global {
|
|||||||
struct {
|
struct {
|
||||||
lfs_block_t movepair[2];
|
lfs_block_t movepair[2];
|
||||||
uint16_t moveid;
|
uint16_t moveid;
|
||||||
bool deorphaned;
|
uint8_t deorphaned;
|
||||||
} s;
|
} l;
|
||||||
|
struct {
|
||||||
|
lfs_block_t movepair[2];
|
||||||
|
uint16_t moveid;
|
||||||
|
uint8_t orphans;
|
||||||
|
} g;
|
||||||
} lfs_global_t;
|
} lfs_global_t;
|
||||||
|
|
||||||
typedef struct lfs_mdir {
|
typedef struct lfs_mdir {
|
||||||
|
|||||||
Reference in New Issue
Block a user