WIP added deorphan bit to globals

This commit is contained in:
Christopher Haster
2018-07-31 08:07:36 -05:00
parent 10f063571a
commit a703859615
2 changed files with 221 additions and 173 deletions

365
lfs.c
View File

@@ -267,7 +267,7 @@ static int lfs_relocate(lfs_t *lfs,
const lfs_block_t oldpair[2], const lfs_block_t newpair[2]); const lfs_block_t oldpair[2], const lfs_block_t newpair[2]);
int lfs_scan(lfs_t *lfs); int lfs_scan(lfs_t *lfs);
int lfs_fixmove(lfs_t *lfs); int lfs_fixmove(lfs_t *lfs);
int lfs_deorphan(lfs_t *lfs); int lfs_forceconsistency(lfs_t *lfs);
/// Block allocator /// /// Block allocator ///
@@ -456,15 +456,68 @@ static inline lfs_size_t lfs_tagsize(uint32_t tag) {
return tag & 0x00000fff; return tag & 0x00000fff;
} }
// operations on globals // operations on set of globals
static void lfs_globalsxor(lfs_globals_t *a, const lfs_globals_t *b) { static inline void lfs_globalxor(lfs_global_t *a, const lfs_global_t *b) {
a->move.pair[0] ^= b->move.pair[0]; for (int i = 0; i < sizeof(lfs_global_t)/2; i++) {
a->move.pair[1] ^= b->move.pair[1]; a->u16[i] ^= b->u16[i];
a->move.id ^= b->move.id; }
} }
static bool lfs_globalsiszero(const lfs_globals_t *a) { static inline bool lfs_globaliszero(const lfs_global_t *a) {
return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0); for (int i = 0; i < sizeof(lfs_global_t)/2; i++) {
if (a->u16[i] != 0) {
return false;
}
}
return true;
}
static inline void lfs_globalzero(lfs_global_t *a) {
memset(a->u16, 0x00, sizeof(lfs_global_t));
}
static inline void lfs_globalones(lfs_global_t *a) {
memset(a->u16, 0xff, sizeof(lfs_global_t));
}
static inline void lfs_globalxormove(lfs_global_t *a,
const lfs_block_t pair[2], uint16_t id) {
a->u16[0] ^= id;
for (int i = 0; i < sizeof(lfs_block_t[2])/2; i++) {
a->u16[1+i] ^= ((uint16_t*)pair)[i];
}
}
static inline void lfs_globalxordeorphaned(lfs_global_t *a, bool deorphaned) {
a->u16[0] ^= deorphaned << 15;
}
static inline const lfs_block_t *lfs_globalmovepair(const lfs_t *lfs) {
return (const lfs_block_t*)&lfs->globals.u16[1];
}
static inline uint16_t lfs_globalmoveid(const lfs_t *lfs) {
return 0x3ff & lfs->globals.u16[0];
}
static inline bool lfs_globalisdeorphaned(const lfs_t *lfs) {
return 0x8000 & lfs->globals.u16[0];
}
static inline void lfs_globalmove(lfs_t *lfs,
const lfs_block_t pair[2], uint16_t id) {
lfs_global_t diff;
lfs_globalzero(&diff);
lfs_globalxormove(&diff, lfs_globalmovepair(lfs), lfs_globalmoveid(lfs));
lfs_globalxormove(&diff, pair, id);
lfs_globalxor(&lfs->locals, &diff);
lfs_globalxor(&lfs->globals, &diff);
}
static inline void lfs_globaldeorphaned(lfs_t *lfs, bool deorphaned) {
deorphaned ^= lfs_globalisdeorphaned(lfs);
lfs_globalxordeorphaned(&lfs->locals, deorphaned);
lfs_globalxordeorphaned(&lfs->globals, deorphaned);
} }
@@ -670,15 +723,15 @@ static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit,
} }
static int lfs_commitglobals(lfs_t *lfs, struct lfs_commit *commit, static int lfs_commitglobals(lfs_t *lfs, struct lfs_commit *commit,
lfs_globals_t *locals) { lfs_global_t *locals) {
if (lfs_globalsiszero(&lfs->diff)) { if (lfs_globaliszero(&lfs->locals)) {
return 0; return 0;
} }
lfs_globalsxor(locals, &lfs->diff); lfs_globalxor(locals, &lfs->locals);
int err = lfs_commitattr(lfs, commit, int err = lfs_commitattr(lfs, commit,
LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(*locals)), locals); LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(lfs_global_t)), locals);
lfs_globalsxor(locals, &lfs->diff); lfs_globalxor(locals, &lfs->locals);
return err; return err;
} }
@@ -759,7 +812,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
dir->tail[1] = tail[1]; dir->tail[1] = tail[1];
dir->erased = false; dir->erased = false;
dir->split = split; dir->split = split;
dir->locals = (lfs_globals_t){{{0}}}; lfs_globalzero(&dir->locals);
// don't write out yet, let caller take care of that // don't write out yet, let caller take care of that
return 0; return 0;
@@ -774,8 +827,8 @@ static int lfs_dir_compact(lfs_t *lfs,
// There's nothing special about our global delta, so feed it back // There's nothing special about our global delta, so feed it back
// into the global global delta // into the global global delta
lfs_globalsxor(&lfs->diff, &dir->locals); lfs_globalxor(&lfs->locals, &dir->locals);
dir->locals = (lfs_globals_t){{{0}}}; lfs_globalzero(&dir->locals);
// increment revision count // increment revision count
dir->rev += 1; dir->rev += 1;
@@ -933,8 +986,8 @@ relocate:
if (!relocated) { if (!relocated) {
// successful commit, update globals // successful commit, update globals
lfs_globalsxor(&dir->locals, &lfs->diff); lfs_globalxor(&dir->locals, &lfs->locals);
lfs->diff = (lfs_globals_t){{{0}}}; lfs_globalzero(&lfs->locals);
} else { } else {
// update references if we relocated // update references if we relocated
LFS_DEBUG("Relocating %d %d to %d %d", LFS_DEBUG("Relocating %d %d to %d %d",
@@ -962,18 +1015,21 @@ relocate:
static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
const lfs_mattr_t *attrs) { const lfs_mattr_t *attrs) {
bool canceling = (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0); lfs_mattr_t cancelattr;
lfs_mattr_t cancel; lfs_global_t canceldiff;
if (canceling) { lfs_globalzero(&canceldiff);
if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 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
lfs->diff.move.pair[0] ^= 0xffffffff ^ lfs->globals.move.pair[0]; lfs_globalxormove(&canceldiff,
lfs->diff.move.pair[1] ^= 0xffffffff ^ lfs->globals.move.pair[1]; lfs_globalmovepair(lfs), lfs_globalmoveid(lfs));
lfs->diff.move.id ^= 0x3ff ^ lfs->globals.move.id; lfs_globalxormove(&canceldiff,
(lfs_block_t[2]){0xffffffff, 0xffffffff}, 0x3ff);
lfs_globalxor(&lfs->locals, &canceldiff);
cancel.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.move.id, 0); cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs_globalmoveid(lfs), 0);
cancel.next = attrs; cancelattr.next = attrs;
attrs = &cancel; attrs = &cancelattr;
} }
// calculate new directory size // calculate new directory size
@@ -1001,7 +1057,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
pdir.split = dir->split; pdir.split = dir->split;
pdir.tail[0] = dir->tail[0]; pdir.tail[0] = dir->tail[0];
pdir.tail[1] = dir->tail[1]; pdir.tail[1] = dir->tail[1];
lfs_globalsxor(&lfs->diff, &dir->locals); lfs_globalxor(&lfs->locals, &dir->locals);
return lfs_dir_commit(lfs, &pdir, return lfs_dir_commit(lfs, &pdir,
LFS_MKATTR(LFS_TYPE_TAIL + pdir.split, 0x3ff, LFS_MKATTR(LFS_TYPE_TAIL + pdir.split, 0x3ff,
pdir.tail, sizeof(pdir.tail), pdir.tail, sizeof(pdir.tail),
@@ -1074,16 +1130,12 @@ compact:
dir->off = commit.off; dir->off = commit.off;
dir->etag = commit.ptag; dir->etag = commit.ptag;
// successful commit, update globals // successful commit, update globals
lfs_globalsxor(&dir->locals, &lfs->diff); lfs_globalxor(&dir->locals, &lfs->locals);
lfs->diff = (lfs_globals_t){{{0}}}; lfs_globalzero(&lfs->locals);
} }
// update globals that are affected // update globals that are affected
if (canceling) { lfs_globalxor(&lfs->globals, &canceldiff);
lfs->globals.move.pair[0] = 0xffffffff;
lfs->globals.move.pair[1] = 0xffffffff;
lfs->globals.move.id = 0x3ff;
}
// update any directories that are affected // update any directories that are affected
for (lfs_dir_t *d = lfs->dirs; d; d = d->next) { for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
@@ -1147,7 +1199,8 @@ static int32_t lfs_dir_find(lfs_t *lfs,
uint16_t tempcount = 0; uint16_t tempcount = 0;
lfs_block_t temptail[2] = {0xffffffff, 0xffffffff}; lfs_block_t temptail[2] = {0xffffffff, 0xffffffff};
bool tempsplit = false; bool tempsplit = false;
lfs_globals_t templocals = (lfs_globals_t){{{0}}}; lfs_global_t templocals;
lfs_globalzero(&templocals);
while (true) { while (true) {
// extract next tag // extract next tag
@@ -1252,11 +1305,11 @@ static int32_t lfs_dir_find(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_paircmp(dir->pair, lfs->globals.move.pair) == 0) { if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0) {
if (lfs->globals.move.id == lfs_tagid(foundtag)) { if (lfs_globalmoveid(lfs) == lfs_tagid(foundtag)) {
foundtag = LFS_ERR_NOENT; foundtag = LFS_ERR_NOENT;
} else if (lfs_tagisvalid(foundtag) && } else if (lfs_tagisvalid(foundtag) &&
lfs->globals.move.id < lfs_tagid(foundtag)) { lfs_globalmoveid(lfs) < lfs_tagid(foundtag)) {
foundtag -= LFS_MKTAG(0, 1, 0); foundtag -= LFS_MKTAG(0, 1, 0);
} }
} }
@@ -1286,8 +1339,8 @@ static int lfs_dir_fetch(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_paircmp(dir->pair, lfs->globals.move.pair) == 0 && if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0 &&
lfs_tagid(gettag) <= lfs->globals.move.id) { lfs_tagid(gettag) <= lfs_globalmoveid(lfs)) {
// synthetic moves // synthetic moves
getdiff = LFS_MKTAG(0, 1, 0); getdiff = LFS_MKTAG(0, 1, 0);
} }
@@ -1422,11 +1475,9 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
/// Top level directory operations /// /// Top level directory operations ///
int lfs_mkdir(lfs_t *lfs, const char *path) { int lfs_mkdir(lfs_t *lfs, const char *path) {
// deorphan if we haven't yet, needed at most once after poweron // deorphan if we haven't yet, needed at most once after poweron
if (!lfs->deorphaned) { int err = lfs_forceconsistency(lfs);
int err = lfs_deorphan(lfs); if (err) {
if (err) { return err;
return err;
}
} }
lfs_mdir_t cwd; lfs_mdir_t cwd;
@@ -1445,7 +1496,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
lfs_alloc_ack(lfs); lfs_alloc_ack(lfs);
lfs_mdir_t dir; lfs_mdir_t dir;
int err = lfs_dir_alloc(lfs, &dir, false, cwd.tail); err = lfs_dir_alloc(lfs, &dir, false, cwd.tail);
if (err) { if (err) {
return err; return err;
} }
@@ -1817,8 +1868,8 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags, const char *path, int flags,
const struct lfs_file_config *cfg) { const struct lfs_file_config *cfg) {
// deorphan if we haven't yet, needed at most once after poweron // deorphan if we haven't yet, needed at most once after poweron
if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) { if ((flags & 3) != LFS_O_RDONLY) {
int err = lfs_deorphan(lfs); int err = lfs_forceconsistency(lfs);
if (err) { if (err) {
return err; return err;
} }
@@ -2543,15 +2594,13 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
int lfs_remove(lfs_t *lfs, const char *path) { int lfs_remove(lfs_t *lfs, const char *path) {
// deorphan if we haven't yet, needed at most once after poweron // deorphan if we haven't yet, needed at most once after poweron
if (!lfs->deorphaned) { int err = lfs_forceconsistency(lfs);
int err = lfs_deorphan(lfs); if (err) {
if (err) { return err;
return err;
}
} }
lfs_mdir_t cwd; lfs_mdir_t cwd;
int err = lfs_dir_fetch(lfs, &cwd, lfs->root); err = lfs_dir_fetch(lfs, &cwd, lfs->root);
if (err) { if (err) {
return err; return err;
} }
@@ -2580,6 +2629,9 @@ int lfs_remove(lfs_t *lfs, const char *path) {
if (dir.count > 0 || dir.split) { if (dir.count > 0 || dir.split) {
return LFS_ERR_NOTEMPTY; return LFS_ERR_NOTEMPTY;
} }
// mark fs as orphaned
lfs_globaldeorphaned(lfs, false);
} }
// delete the entry // delete the entry
@@ -2596,11 +2648,14 @@ int lfs_remove(lfs_t *lfs, const char *path) {
return err; return err;
} }
// fix orphan
lfs_globaldeorphaned(lfs, true);
// steal state // steal state
// TODO test for global state stealing? // TODO test for global state stealing?
cwd.tail[0] = dir.tail[0]; cwd.tail[0] = dir.tail[0];
cwd.tail[1] = dir.tail[1]; cwd.tail[1] = dir.tail[1];
lfs_globalsxor(&lfs->diff, &dir.locals); lfs_globalxor(&lfs->locals, &dir.locals);
err = lfs_dir_commit(lfs, &cwd, err = lfs_dir_commit(lfs, &cwd,
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
cwd.tail, sizeof(cwd.tail), cwd.tail, sizeof(cwd.tail),
@@ -2615,11 +2670,9 @@ int lfs_remove(lfs_t *lfs, const char *path) {
int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
// deorphan if we haven't yet, needed at most once after poweron // deorphan if we haven't yet, needed at most once after poweron
if (!lfs->deorphaned) { int err = lfs_forceconsistency(lfs);
int err = lfs_deorphan(lfs); if (err) {
if (err) { return err;
return err;
}
} }
// find old entry // find old entry
@@ -2665,6 +2718,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
if (prevdir.count > 0 || prevdir.split) { if (prevdir.count > 0 || prevdir.split) {
return LFS_ERR_NOTEMPTY; return LFS_ERR_NOTEMPTY;
} }
// mark fs as orphaned
lfs_globaldeorphaned(lfs, false);
} }
} else { } else {
// check that name fits // check that name fits
@@ -2678,15 +2734,10 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
} }
// create move to fix later // create move to fix later
lfs->diff.move.pair[0] = oldcwd.pair[0] ^ lfs->globals.move.pair[0]; lfs_globalmove(lfs, oldcwd.pair, lfs_tagid(oldtag));
lfs->diff.move.pair[1] = oldcwd.pair[1] ^ lfs->globals.move.pair[1];
lfs->diff.move.id = lfs_tagid(oldtag) ^ lfs->globals.move.id;
lfs->globals.move.pair[0] = oldcwd.pair[0];
lfs->globals.move.pair[1] = oldcwd.pair[1];
lfs->globals.move.id = lfs_tagid(oldtag);
// move over all attributes // move over all attributes
int err = lfs_dir_commit(lfs, &newcwd, err = lfs_dir_commit(lfs, &newcwd,
LFS_MKATTR(lfs_tagtype(oldtag), newid, newpath, strlen(newpath), LFS_MKATTR(lfs_tagtype(oldtag), newid, newpath, strlen(newpath),
LFS_MKATTR(LFS_FROM_MOVE, newid, &oldcwd, lfs_tagid(oldtag), LFS_MKATTR(LFS_FROM_MOVE, newid, &oldcwd, lfs_tagid(oldtag),
NULL))); NULL)));
@@ -2709,11 +2760,14 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
return err; return err;
} }
// fix orphan
lfs_globaldeorphaned(lfs, true);
// steal state // steal state
// TODO test for global state stealing? // TODO test for global state stealing?
newcwd.tail[0] = prevdir.tail[0]; newcwd.tail[0] = prevdir.tail[0];
newcwd.tail[1] = prevdir.tail[1]; newcwd.tail[1] = prevdir.tail[1];
lfs_globalsxor(&lfs->diff, &prevdir.locals); lfs_globalxor(&lfs->locals, &prevdir.locals);
err = lfs_dir_commit(lfs, &newcwd, err = lfs_dir_commit(lfs, &newcwd,
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
newcwd.tail, sizeof(newcwd.tail), newcwd.tail, sizeof(newcwd.tail),
@@ -2743,7 +2797,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
// // if we were a directory, find pred, replace tail // // if we were a directory, find pred, replace tail
// // TODO can this just deorphan? // // TODO can this just deorphan?
// if (prevexists && lfs_tagsubtype(prevattr.tag) == LFS_TYPE_DIR) { // if (prevexists && lfs_tagsubtype(prevattr.tag) == LFS_TYPE_DIR) {
// err = lfs_deorphan(lfs); // err = lfs_forceconsistency(lfs);
// if (err) { // if (err) {
// return err; // return err;
// } // }
@@ -2936,10 +2990,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->root[1] = 0xffffffff; lfs->root[1] = 0xffffffff;
lfs->files = NULL; lfs->files = NULL;
lfs->dirs = NULL; lfs->dirs = NULL;
lfs->deorphaned = false; lfs_globalones(&lfs->globals);
lfs->globals.move.pair[0] = 0xffffffff;
lfs->globals.move.pair[1] = 0xffffffff;
lfs->globals.move.id = 0x3ff;
// scan for any global updates // scan for any global updates
// TODO rm me? need to grab any inits // TODO rm me? need to grab any inits
@@ -3348,7 +3399,7 @@ static int lfs_relocate(lfs_t *lfs,
} }
// clean up bad block, which should now be a desync // clean up bad block, which should now be a desync
return lfs_deorphan(lfs); return lfs_forceconsistency(lfs);
} }
// find pred // find pred
@@ -3380,7 +3431,7 @@ int lfs_scan(lfs_t *lfs) {
} }
lfs_mdir_t dir = {.tail = {0, 1}}; lfs_mdir_t dir = {.tail = {0, 1}};
lfs->diff = (lfs_globals_t){{{0}}}; lfs_globalzero(&lfs->locals);
// iterate over all directory directory entries // iterate over all directory directory entries
while (!lfs_pairisnull(dir.tail)) { while (!lfs_pairisnull(dir.tail)) {
@@ -3390,40 +3441,105 @@ int lfs_scan(lfs_t *lfs) {
} }
// xor together indirect deletes // xor together indirect deletes
lfs_globalsxor(&lfs->diff, &dir.locals); lfs_globalxor(&lfs->locals, &dir.locals);
} }
// update littlefs with globals // update littlefs with globals
// TODO does this only run once? // TODO does this only run once?
// TODO Should we inline this into init?? // TODO Should we inline this into init??
lfs_globalsxor(&lfs->globals, &lfs->diff); lfs_globalxor(&lfs->globals, &lfs->locals);
lfs->diff = (lfs_globals_t){{{0}}}; lfs_globalzero(&lfs->locals);
if (!lfs_pairisnull(lfs->globals.move.pair)) { if (!lfs_pairisnull(lfs_globalmovepair(lfs))) {
LFS_DEBUG("Found move %d %d %d", LFS_DEBUG("Found move %d %d %d",
lfs->globals.move.pair[0], lfs_globalmovepair(lfs)[0],
lfs->globals.move.pair[1], lfs_globalmovepair(lfs)[1],
lfs->globals.move.id); lfs_globalmoveid(lfs));
} }
return 0; return 0;
} }
int lfs_deorphan(lfs_t *lfs) { int lfs_forceconsistency(lfs_t *lfs) {
lfs->deorphaned = true; if (!lfs_globalisdeorphaned(lfs)) {
if (lfs_pairisnull(lfs->root)) { // TODO rm me? // Fix any orphans
return 0; lfs_mdir_t pdir = {.split = true};
lfs_mdir_t dir = {.tail = {0, 1}};
// iterate over all directory directory entries
while (!lfs_pairisnull(dir.tail)) {
int err = lfs_dir_fetch(lfs, &dir, dir.tail);
if (err) {
return err;
}
// check head blocks for orphans
if (!pdir.split) {
// check if we have a parent
lfs_mdir_t parent;
int32_t tag = lfs_parent(lfs, pdir.tail, &parent);
if (tag < 0 && tag != LFS_ERR_NOENT) {
return tag;
}
if (tag == LFS_ERR_NOENT) {
// we are an orphan
LFS_DEBUG("Found orphan %d %d",
pdir.tail[0], pdir.tail[1]);
pdir.tail[0] = dir.tail[0];
pdir.tail[1] = dir.tail[1];
err = lfs_dir_commit(lfs, &pdir,
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
pdir.tail, sizeof(pdir.tail),
NULL));
if (err) {
return err;
}
break;
}
lfs_block_t pair[2];
int32_t res = lfs_dir_get(lfs, &parent, 0x7ffff000, tag, pair);
if (res < 0) {
return res;
}
if (!lfs_pairsync(pair, pdir.tail)) {
// we have desynced
LFS_DEBUG("Found half-orphan %d %d", pair[0], pair[1]);
pdir.tail[0] = pair[0];
pdir.tail[1] = pair[1];
err = lfs_dir_commit(lfs, &pdir,
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
pdir.tail, sizeof(pdir.tail),
NULL));
if (err) {
return err;
}
break;
}
}
memcpy(&pdir, &dir, sizeof(pdir));
}
// mark orphan as fixed
lfs_globaldeorphaned(lfs, false);
} }
// Fix bad moves if (lfs_globalmoveid(lfs) != 0x3ff) {
if (!lfs_pairisnull(lfs->globals.move.pair)) { // Fix bad moves
LFS_DEBUG("Fixing move %d %d %d", // TODO move to just deorphan? LFS_DEBUG("Fixing move %d %d %d", // TODO move to just deorphan?
lfs->globals.move.pair[0], lfs_globalmovepair(lfs)[0],
lfs->globals.move.pair[1], lfs_globalmovepair(lfs)[1],
lfs->globals.move.id); lfs_globalmoveid(lfs));
// 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.move.pair); int err = lfs_dir_fetch(lfs, &movedir, lfs_globalmovepair(lfs));
if (err) { if (err) {
return err; return err;
} }
@@ -3435,69 +3551,6 @@ int lfs_deorphan(lfs_t *lfs) {
} }
} }
lfs_mdir_t pdir = {.split = true};
lfs_mdir_t dir = {.tail = {0, 1}};
// iterate over all directory directory entries
while (!lfs_pairisnull(dir.tail)) {
int err = lfs_dir_fetch(lfs, &dir, dir.tail);
if (err) {
return err;
}
// check head blocks for orphans
if (!pdir.split) {
// check if we have a parent
lfs_mdir_t parent;
int32_t tag = lfs_parent(lfs, pdir.tail, &parent);
if (tag < 0 && tag != LFS_ERR_NOENT) {
return tag;
}
if (tag == LFS_ERR_NOENT) {
// we are an orphan
LFS_DEBUG("Found orphan %d %d", pdir.tail[0], pdir.tail[1]);
pdir.tail[0] = dir.tail[0];
pdir.tail[1] = dir.tail[1];
err = lfs_dir_commit(lfs, &pdir,
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
pdir.tail, sizeof(pdir.tail),
NULL));
if (err) {
return err;
}
break;
}
lfs_block_t pair[2];
int32_t res = lfs_dir_get(lfs, &parent, 0x7ffff000, tag, pair);
if (res < 0) {
return res;
}
if (!lfs_pairsync(pair, pdir.tail)) {
// we have desynced
LFS_DEBUG("Found half-orphan %d %d", pair[0], pair[1]);
pdir.tail[0] = pair[0];
pdir.tail[1] = pair[1];
err = lfs_dir_commit(lfs, &pdir,
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
pdir.tail, sizeof(pdir.tail),
NULL));
if (err) {
return err;
}
break;
}
}
memcpy(&pdir, &dir, sizeof(pdir));
}
return 0; return 0;
} }

29
lfs.h
View File

@@ -110,7 +110,7 @@ enum lfs_type {
LFS_TYPE_TAIL = 0x0c0, LFS_TYPE_TAIL = 0x0c0,
LFS_TYPE_SOFTTAIL = 0x0c0, LFS_TYPE_SOFTTAIL = 0x0c0,
LFS_TYPE_HARDTAIL = 0x0c1, LFS_TYPE_HARDTAIL = 0x0c1,
LFS_TYPE_CRC = 0x0ff, LFS_TYPE_CRC = 0x0ff, // TODO are trailing ones useful?
LFS_TYPE_INLINESTRUCT = 0x040, LFS_TYPE_INLINESTRUCT = 0x040,
LFS_TYPE_CTZSTRUCT = 0x041, LFS_TYPE_CTZSTRUCT = 0x041,
@@ -280,12 +280,9 @@ typedef struct lfs_mattr {
const struct lfs_mattr *next; const struct lfs_mattr *next;
} lfs_mattr_t; } lfs_mattr_t;
typedef struct lfs_globals { typedef union lfs_global {
struct lfs_move { uint16_t u16[5];
lfs_block_t pair[2]; } lfs_global_t;
uint16_t id;
} move;
} lfs_globals_t;
typedef struct lfs_mdir { typedef struct lfs_mdir {
lfs_block_t pair[2]; lfs_block_t pair[2];
@@ -296,7 +293,7 @@ typedef struct lfs_mdir {
uint16_t count; uint16_t count;
bool erased; bool erased;
bool split; bool split;
lfs_globals_t locals; lfs_global_t locals;
} lfs_mdir_t; } lfs_mdir_t;
typedef struct lfs_cache { typedef struct lfs_cache {
@@ -314,12 +311,13 @@ typedef struct lfs_file {
lfs_size_t size; lfs_size_t size;
} ctz; } ctz;
const struct lfs_file_config *cfg;
uint32_t flags; uint32_t flags;
lfs_off_t pos; lfs_off_t pos;
lfs_block_t block; lfs_block_t block;
lfs_off_t off; lfs_off_t off;
lfs_cache_t cache; lfs_cache_t cache;
const struct lfs_file_config *cfg;
} lfs_file_t; } lfs_file_t;
typedef struct lfs_dir { typedef struct lfs_dir {
@@ -353,21 +351,18 @@ typedef struct lfs_free {
// The littlefs type // The littlefs type
typedef struct lfs { typedef struct lfs {
const struct lfs_config *cfg; lfs_cache_t rcache;
lfs_cache_t pcache;
lfs_block_t root[2]; lfs_block_t root[2];
lfs_file_t *files; lfs_file_t *files;
lfs_dir_t *dirs; lfs_dir_t *dirs;
lfs_cache_t rcache; lfs_global_t globals;
lfs_cache_t pcache; lfs_global_t locals;
lfs_free_t free; lfs_free_t free;
bool deorphaned;
lfs_globals_t globals2;
lfs_globals_t globals;
lfs_globals_t diff;
const struct lfs_config *cfg;
lfs_size_t inline_size; lfs_size_t inline_size;
lfs_size_t attr_size; lfs_size_t attr_size;
lfs_size_t name_size; lfs_size_t name_size;