|
@@ -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
|
|
|
|
|
-static void lfs_globalsxor(lfs_globals_t *a, const lfs_globals_t *b) {
|
|
|
|
|
- a->move.pair[0] ^= b->move.pair[0];
|
|
|
|
|
- a->move.pair[1] ^= b->move.pair[1];
|
|
|
|
|
- a->move.id ^= b->move.id;
|
|
|
|
|
|
|
+// operations on set of globals
|
|
|
|
|
+static inline void lfs_globalxor(lfs_global_t *a, const lfs_global_t *b) {
|
|
|
|
|
+ for (int i = 0; i < sizeof(lfs_global_t)/2; i++) {
|
|
|
|
|
+ a->u16[i] ^= b->u16[i];
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static inline bool lfs_globaliszero(const lfs_global_t *a) {
|
|
|
|
|
+ for (int i = 0; i < sizeof(lfs_global_t)/2; i++) {
|
|
|
|
|
+ if (a->u16[i] != 0) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static bool lfs_globalsiszero(const lfs_globals_t *a) {
|
|
|
|
|
- return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0);
|
|
|
|
|
|
|
+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) {
|
|
|
|
|
- if (lfs_globalsiszero(&lfs->diff)) {
|
|
|
|
|
|
|
+ lfs_global_t *locals) {
|
|
|
|
|
+ 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_globalsxor(locals, &lfs->diff);
|
|
|
|
|
|
|
+ LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(lfs_global_t)), locals);
|
|
|
|
|
+ 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);
|
|
|
|
|
- dir->locals = (lfs_globals_t){{{0}}};
|
|
|
|
|
|
|
+ lfs_globalxor(&lfs->locals, &dir->locals);
|
|
|
|
|
+ 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->diff = (lfs_globals_t){{{0}}};
|
|
|
|
|
|
|
+ lfs_globalxor(&dir->locals, &lfs->locals);
|
|
|
|
|
+ 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 cancel;
|
|
|
|
|
- if (canceling) {
|
|
|
|
|
|
|
+ lfs_mattr_t cancelattr;
|
|
|
|
|
+ lfs_global_t canceldiff;
|
|
|
|
|
+ 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->diff.move.pair[1] ^= 0xffffffff ^ lfs->globals.move.pair[1];
|
|
|
|
|
- lfs->diff.move.id ^= 0x3ff ^ lfs->globals.move.id;
|
|
|
|
|
|
|
+ lfs_globalxormove(&canceldiff,
|
|
|
|
|
+ lfs_globalmovepair(lfs), lfs_globalmoveid(lfs));
|
|
|
|
|
+ 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);
|
|
|
|
|
- cancel.next = attrs;
|
|
|
|
|
- attrs = &cancel;
|
|
|
|
|
|
|
+ cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs_globalmoveid(lfs), 0);
|
|
|
|
|
+ cancelattr.next = attrs;
|
|
|
|
|
+ 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->diff = (lfs_globals_t){{{0}}};
|
|
|
|
|
|
|
+ lfs_globalxor(&dir->locals, &lfs->locals);
|
|
|
|
|
+ lfs_globalzero(&lfs->locals);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// update globals that are affected
|
|
// update globals that are affected
|
|
|
- if (canceling) {
|
|
|
|
|
- lfs->globals.move.pair[0] = 0xffffffff;
|
|
|
|
|
- lfs->globals.move.pair[1] = 0xffffffff;
|
|
|
|
|
- lfs->globals.move.id = 0x3ff;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ lfs_globalxor(&lfs->globals, &canceldiff);
|
|
|
|
|
|
|
|
// 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->globals.move.id == lfs_tagid(foundtag)) {
|
|
|
|
|
|
|
+ if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0) {
|
|
|
|
|
+ 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 &&
|
|
|
|
|
- lfs_tagid(gettag) <= lfs->globals.move.id) {
|
|
|
|
|
|
|
+ if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0 &&
|
|
|
|
|
+ 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_deorphan(lfs);
|
|
|
|
|
- if (err) {
|
|
|
|
|
- return err;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ int err = lfs_forceconsistency(lfs);
|
|
|
|
|
+ if (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) {
|
|
|
|
|
- int err = lfs_deorphan(lfs);
|
|
|
|
|
|
|
+ if ((flags & 3) != LFS_O_RDONLY) {
|
|
|
|
|
+ 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_deorphan(lfs);
|
|
|
|
|
- if (err) {
|
|
|
|
|
- return err;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ int err = lfs_forceconsistency(lfs);
|
|
|
|
|
+ if (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_deorphan(lfs);
|
|
|
|
|
- if (err) {
|
|
|
|
|
- return err;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ int err = lfs_forceconsistency(lfs);
|
|
|
|
|
+ if (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->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);
|
|
|
|
|
|
|
+ lfs_globalmove(lfs, oldcwd.pair, 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->globals.move.pair[0] = 0xffffffff;
|
|
|
|
|
- lfs->globals.move.pair[1] = 0xffffffff;
|
|
|
|
|
- lfs->globals.move.id = 0x3ff;
|
|
|
|
|
|
|
+ lfs_globalones(&lfs->globals);
|
|
|
|
|
|
|
|
// 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,112 +3441,114 @@ 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->diff = (lfs_globals_t){{{0}}};
|
|
|
|
|
- if (!lfs_pairisnull(lfs->globals.move.pair)) {
|
|
|
|
|
|
|
+ lfs_globalxor(&lfs->globals, &lfs->locals);
|
|
|
|
|
+ lfs_globalzero(&lfs->locals);
|
|
|
|
|
+ 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->globals.move.pair[1],
|
|
|
|
|
- lfs->globals.move.id);
|
|
|
|
|
|
|
+ lfs_globalmovepair(lfs)[0],
|
|
|
|
|
+ lfs_globalmovepair(lfs)[1],
|
|
|
|
|
+ lfs_globalmoveid(lfs));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int lfs_deorphan(lfs_t *lfs) {
|
|
|
|
|
- lfs->deorphaned = true;
|
|
|
|
|
- if (lfs_pairisnull(lfs->root)) { // TODO rm me?
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+int lfs_forceconsistency(lfs_t *lfs) {
|
|
|
|
|
+ if (!lfs_globalisdeorphaned(lfs)) {
|
|
|
|
|
+ // Fix any orphans
|
|
|
|
|
+ lfs_mdir_t pdir = {.split = true};
|
|
|
|
|
+ lfs_mdir_t dir = {.tail = {0, 1}};
|
|
|
|
|
|
|
|
- // Fix bad moves
|
|
|
|
|
- if (!lfs_pairisnull(lfs->globals.move.pair)) {
|
|
|
|
|
- LFS_DEBUG("Fixing move %d %d %d", // TODO move to just deorphan?
|
|
|
|
|
- lfs->globals.move.pair[0],
|
|
|
|
|
- lfs->globals.move.pair[1],
|
|
|
|
|
- lfs->globals.move.id);
|
|
|
|
|
|
|
+ // iterate over all directory directory entries
|
|
|
|
|
+ while (!lfs_pairisnull(dir.tail)) {
|
|
|
|
|
+ int err = lfs_dir_fetch(lfs, &dir, dir.tail);
|
|
|
|
|
+ if (err) {
|
|
|
|
|
+ return err;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // fetch and delete the moved entry
|
|
|
|
|
- lfs_mdir_t movedir;
|
|
|
|
|
- int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.move.pair);
|
|
|
|
|
- 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;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // rely on cancel logic inside commit
|
|
|
|
|
- err = lfs_dir_commit(lfs, &movedir, NULL);
|
|
|
|
|
- if (err) {
|
|
|
|
|
- return err;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- lfs_mdir_t pdir = {.split = true};
|
|
|
|
|
- lfs_mdir_t dir = {.tail = {0, 1}};
|
|
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // iterate over all directory directory entries
|
|
|
|
|
- while (!lfs_pairisnull(dir.tail)) {
|
|
|
|
|
- int err = lfs_dir_fetch(lfs, &dir, dir.tail);
|
|
|
|
|
- if (err) {
|
|
|
|
|
- return err;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ lfs_block_t pair[2];
|
|
|
|
|
+ int32_t res = lfs_dir_get(lfs, &parent, 0x7ffff000, tag, pair);
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 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 (!lfs_pairsync(pair, pdir.tail)) {
|
|
|
|
|
+ // we have desynced
|
|
|
|
|
+ LFS_DEBUG("Found half-orphan %d %d", pair[0], pair[1]);
|
|
|
|
|
|
|
|
- if (tag == LFS_ERR_NOENT) {
|
|
|
|
|
- // we are an orphan
|
|
|
|
|
- LFS_DEBUG("Found orphan %d %d", pdir.tail[0], pdir.tail[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;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- 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;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- break;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- lfs_block_t pair[2];
|
|
|
|
|
- int32_t res = lfs_dir_get(lfs, &parent, 0x7ffff000, tag, pair);
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- return res;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ memcpy(&pdir, &dir, sizeof(pdir));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (!lfs_pairsync(pair, pdir.tail)) {
|
|
|
|
|
- // we have desynced
|
|
|
|
|
- LFS_DEBUG("Found half-orphan %d %d", pair[0], pair[1]);
|
|
|
|
|
|
|
+ // mark orphan as fixed
|
|
|
|
|
+ lfs_globaldeorphaned(lfs, false);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- 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;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (lfs_globalmoveid(lfs) != 0x3ff) {
|
|
|
|
|
+ // Fix bad moves
|
|
|
|
|
+ LFS_DEBUG("Fixing move %d %d %d", // TODO move to just deorphan?
|
|
|
|
|
+ lfs_globalmovepair(lfs)[0],
|
|
|
|
|
+ lfs_globalmovepair(lfs)[1],
|
|
|
|
|
+ lfs_globalmoveid(lfs));
|
|
|
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // fetch and delete the moved entry
|
|
|
|
|
+ lfs_mdir_t movedir;
|
|
|
|
|
+ int err = lfs_dir_fetch(lfs, &movedir, lfs_globalmovepair(lfs));
|
|
|
|
|
+ if (err) {
|
|
|
|
|
+ return err;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- memcpy(&pdir, &dir, sizeof(pdir));
|
|
|
|
|
|
|
+ // rely on cancel logic inside commit
|
|
|
|
|
+ err = lfs_dir_commit(lfs, &movedir, NULL);
|
|
|
|
|
+ if (err) {
|
|
|
|
|
+ return err;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
return 0;
|