mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 00:38:29 +01:00
WIP cleaned up commit logic
This commit is contained in:
159
lfs.c
159
lfs.c
@@ -457,16 +457,13 @@ static inline lfs_size_t lfs_tagsize(uint32_t tag) {
|
||||
}
|
||||
|
||||
// operations on globals
|
||||
static lfs_globals_t lfs_globals_xor(
|
||||
const lfs_globals_t *a, const lfs_globals_t *b) {
|
||||
lfs_globals_t res;
|
||||
res.move.pair[0] = a->move.pair[0] ^ b->move.pair[0];
|
||||
res.move.pair[1] = a->move.pair[1] ^ b->move.pair[1];
|
||||
res.move.id = a->move.id ^ b->move.id;
|
||||
return res;
|
||||
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;
|
||||
}
|
||||
|
||||
static bool lfs_globals_iszero(const lfs_globals_t *a) {
|
||||
static bool lfs_globalsiszero(const lfs_globals_t *a) {
|
||||
return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0);
|
||||
}
|
||||
|
||||
@@ -488,18 +485,8 @@ struct lfs_diskoff {
|
||||
};
|
||||
|
||||
static int32_t lfs_commitget(lfs_t *lfs, lfs_block_t block, lfs_off_t off,
|
||||
uint32_t tag, uint32_t getmask, uint32_t gettag, void *buffer,
|
||||
bool stopatcommit) {
|
||||
uint16_t id = lfs_tagid(gettag);
|
||||
lfs_size_t size = lfs_tagsize(gettag);
|
||||
|
||||
// synthetic moves
|
||||
if ((block == lfs->globals.move.pair[0] ||
|
||||
block == lfs->globals.move.pair[1])
|
||||
&& lfs_tagid(gettag) <= lfs->globals.move.id) {
|
||||
gettag += LFS_MKTAG(0, 1, 0);
|
||||
}
|
||||
|
||||
uint32_t tag, uint32_t getmask, uint32_t gettag, int32_t difftag,
|
||||
void *buffer, bool stopatcommit) {
|
||||
// iterate over dir block backwards (for faster lookups)
|
||||
while (off > sizeof(tag)) {
|
||||
LFS_ASSERT(off > sizeof(tag)+lfs_tagsize(tag));
|
||||
@@ -508,22 +495,24 @@ static int32_t lfs_commitget(lfs_t *lfs, lfs_block_t block, lfs_off_t off,
|
||||
if (lfs_tagtype(tag) == LFS_TYPE_CRC && stopatcommit) {
|
||||
break;
|
||||
} else if (lfs_tagtype(tag) == LFS_TYPE_DELETE) {
|
||||
if (lfs_tagid(tag) <= lfs_tagid(gettag)) {
|
||||
gettag += LFS_MKTAG(0, 1, 0);
|
||||
if (lfs_tagid(tag) <= lfs_tagid(gettag + difftag)) {
|
||||
difftag += LFS_MKTAG(0, 1, 0);
|
||||
}
|
||||
} else if ((tag & getmask) == (gettag & getmask)) {
|
||||
} else if ((tag & getmask) == ((gettag + difftag) & getmask)) {
|
||||
if (buffer) {
|
||||
lfs_size_t diff = lfs_min(size, lfs_tagsize(tag));
|
||||
lfs_size_t diff = lfs_min(
|
||||
lfs_tagsize(gettag), lfs_tagsize(tag));
|
||||
int err = lfs_bd_read(lfs, block,
|
||||
off+sizeof(tag), buffer, diff);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
memset((uint8_t*)buffer + diff, 0, size - diff);
|
||||
memset((uint8_t*)buffer + diff, 0,
|
||||
lfs_tagsize(gettag) - diff);
|
||||
}
|
||||
|
||||
return (tag & 0xffc00fff) | LFS_MKTAG(0, id, 0);
|
||||
return tag - difftag;
|
||||
}
|
||||
|
||||
uint32_t ntag;
|
||||
@@ -640,7 +629,8 @@ static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit,
|
||||
int32_t res = lfs_commitget(lfs, commit->block,
|
||||
commit->off, commit->ptag,
|
||||
lfs_tagisuser(tag) ? 0x7ffff000 : 0x7c3ff000,
|
||||
LFS_MKTAG(lfs_tagtype(tag), toid, 0), NULL, true);
|
||||
LFS_MKTAG(lfs_tagtype(tag), toid, 0),
|
||||
0, NULL, true);
|
||||
if (res < 0 && res != LFS_ERR_NOENT) {
|
||||
return res;
|
||||
}
|
||||
@@ -661,22 +651,18 @@ static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit,
|
||||
}
|
||||
|
||||
static int lfs_commitglobals(lfs_t *lfs, struct lfs_commit *commit,
|
||||
const lfs_globals_t *source, const lfs_globals_t *diff) {
|
||||
if (lfs_globals_iszero(diff)) {
|
||||
lfs_globals_t *locals) {
|
||||
if (lfs_globalsiszero(&lfs->diff)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO check performance/complexity of different strategies here
|
||||
lfs_globals_t res = lfs_globals_xor(source, diff);
|
||||
lfs_globalsxor(locals, &lfs->diff);
|
||||
int err = lfs_commitattr(lfs, commit,
|
||||
LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(res)), &res);
|
||||
if (err) {
|
||||
LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(*locals)), locals);
|
||||
lfs_globalsxor(locals, &lfs->diff);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
|
||||
// align to program units
|
||||
lfs_off_t off = lfs_alignup(commit->off + 2*sizeof(uint32_t),
|
||||
@@ -754,7 +740,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
dir->tail[1] = tail[1];
|
||||
dir->erased = false;
|
||||
dir->split = split;
|
||||
dir->globals = (lfs_globals_t){0};
|
||||
dir->locals = (lfs_globals_t){0};
|
||||
|
||||
// don't write out yet, let caller take care of that
|
||||
return 0;
|
||||
@@ -769,11 +755,8 @@ static int lfs_dir_compact(lfs_t *lfs,
|
||||
|
||||
// There's nothing special about our global delta, so feed it back
|
||||
// into the global global delta
|
||||
// TODO IMMENSE HMM globals get bleed into from above, need to be fixed after commits due to potential moves
|
||||
lfs_globals_t gtemp = dir->globals; // TODO hmm, why did we have different variables then?
|
||||
|
||||
lfs->diff = lfs_globals_xor(&lfs->diff, &dir->globals);
|
||||
dir->globals = (lfs_globals_t){0};
|
||||
lfs_globalsxor(&lfs->diff, &dir->locals);
|
||||
dir->locals = (lfs_globals_t){0};
|
||||
|
||||
// increment revision count
|
||||
dir->rev += 1;
|
||||
@@ -812,27 +795,14 @@ static int lfs_dir_compact(lfs_t *lfs,
|
||||
.crc = crc,
|
||||
.ptag = 0,
|
||||
|
||||
// space is complicated, we need room for tail, crc, and we
|
||||
// keep cap at around half a block
|
||||
// space is complicated, we need room for tail, crc, globals,
|
||||
// and we cap at half a block to give room for metadata updates
|
||||
.begin = 0,
|
||||
.end = lfs_min(
|
||||
lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size),
|
||||
lfs->cfg->block_size - 5*sizeof(uint32_t)),
|
||||
lfs->cfg->block_size - 34),
|
||||
};
|
||||
|
||||
if (!relocated) {
|
||||
err = lfs_commitglobals(lfs, &commit,
|
||||
&dir->globals, &lfs->diff);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOSPC) {
|
||||
goto split;
|
||||
} else if (err == LFS_ERR_CORRUPT) {
|
||||
goto relocate;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// commit with a move
|
||||
for (uint16_t id = begin; id < end; id++) {
|
||||
err = lfs_commitmove(lfs, &commit,
|
||||
@@ -850,7 +820,17 @@ static int lfs_dir_compact(lfs_t *lfs,
|
||||
}
|
||||
|
||||
// reopen reserved space at the end
|
||||
commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t);
|
||||
commit.end = lfs->cfg->block_size - 8;
|
||||
|
||||
if (!relocated) {
|
||||
err = lfs_commitglobals(lfs, &commit, &dir->locals);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto relocate;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lfs_pairisnull(dir->tail)) {
|
||||
// commit tail, which may be new after last size check
|
||||
@@ -929,7 +909,11 @@ relocate:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (relocated) {
|
||||
if (!relocated) {
|
||||
// successful commit, update globals
|
||||
lfs_globalsxor(&dir->locals, &lfs->diff);
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
} else {
|
||||
// update references if we relocated
|
||||
LFS_DEBUG("Relocating %d %d to %d %d",
|
||||
oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]);
|
||||
@@ -937,13 +921,8 @@ relocate:
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
}
|
||||
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, >emp); // TODO hmm, why did we have different variables then?
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -962,7 +941,7 @@ static int lfs_dir_commit(lfs_t *lfs,
|
||||
.ptag = dir->etag,
|
||||
|
||||
.begin = dir->off,
|
||||
.end = lfs->cfg->block_size - 2*sizeof(uint32_t),
|
||||
.end = lfs->cfg->block_size - 8,
|
||||
};
|
||||
|
||||
for (const lfs_mattr_t *a = attrs; a; a = a->next) {
|
||||
@@ -975,7 +954,7 @@ static int lfs_dir_commit(lfs_t *lfs,
|
||||
}
|
||||
}
|
||||
|
||||
int err = lfs_commitglobals(lfs, &commit, &dir->globals, &lfs->diff);
|
||||
int err = lfs_commitglobals(lfs, &commit, &dir->locals);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
|
||||
goto compact;
|
||||
@@ -991,12 +970,11 @@ static int lfs_dir_commit(lfs_t *lfs,
|
||||
return err;
|
||||
}
|
||||
|
||||
// successful commit, lets update dir
|
||||
// successful commit, update dir
|
||||
dir->off = commit.off;
|
||||
dir->etag = commit.ptag;
|
||||
// // TODO hm
|
||||
// dir->globals = lfs_globals_xor(&dir->globals, &lfs->diff);
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
|
||||
// successful commit, update globals
|
||||
lfs_globalsxor(&dir->locals, &lfs->diff);
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
break;
|
||||
|
||||
@@ -1053,7 +1031,7 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
||||
dir->tail[1] = 0xffffffff;
|
||||
dir->count = 0;
|
||||
dir->split = false;
|
||||
dir->globals = (lfs_globals_t){0};
|
||||
dir->locals = (lfs_globals_t){0};
|
||||
|
||||
dir->rev = lfs_tole32(rev[0]);
|
||||
lfs_crc(&crc, &dir->rev, sizeof(dir->rev));
|
||||
@@ -1131,7 +1109,7 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
||||
}
|
||||
} else if (lfs_tagtype(tag) == LFS_TYPE_GLOBALS) {
|
||||
err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
|
||||
&tempdir.globals, sizeof(tempdir.globals));
|
||||
&tempdir.locals, sizeof(tempdir.locals));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -1196,8 +1174,15 @@ static int lfs_dir_fetch(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 difftag = 0;
|
||||
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0 &&
|
||||
lfs_tagid(gettag) <= lfs->globals.move.id) {
|
||||
// synthetic moves
|
||||
difftag = LFS_MKTAG(0, 1, 0);
|
||||
}
|
||||
|
||||
return lfs_commitget(lfs, dir->pair[0], dir->off, dir->etag,
|
||||
getmask, gettag, buffer, false);
|
||||
getmask, gettag, difftag, buffer, false);
|
||||
}
|
||||
|
||||
static int lfs_dir_append(lfs_t *lfs, lfs_mdir_t *dir, uint16_t *id) {
|
||||
@@ -1218,12 +1203,11 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) {
|
||||
}
|
||||
|
||||
if (err != LFS_ERR_NOENT && pdir.split) {
|
||||
// steal tail, and global state
|
||||
// steal tail and global state
|
||||
pdir.split = dir->split;
|
||||
pdir.tail[0] = dir->tail[0];
|
||||
pdir.tail[1] = dir->tail[1];
|
||||
lfs->diff = dir->globals;
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, &dir->globals);
|
||||
lfs_globalsxor(&lfs->diff, &dir->locals);
|
||||
|
||||
return lfs_dir_commit(lfs, &pdir,
|
||||
LFS_MKATTR(LFS_TYPE_TAIL + pdir.split, 0x3ff,
|
||||
@@ -2617,6 +2601,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
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);
|
||||
|
||||
// move over all attributes
|
||||
int err = lfs_dir_commit(lfs, &newcwd,
|
||||
@@ -2639,9 +2626,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO test for global state stealing?
|
||||
// steal global state
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, &prevdir.globals);
|
||||
// TODO test for global state stealing?
|
||||
lfs_globalsxor(&lfs->diff, &prevdir.locals);
|
||||
|
||||
newcwd.tail[0] = prevdir.tail[0];
|
||||
newcwd.tail[1] = prevdir.tail[1];
|
||||
@@ -2793,7 +2780,6 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
lfs->globals.move.pair[0] = 0xffffffff;
|
||||
lfs->globals.move.pair[1] = 0xffffffff;
|
||||
lfs->globals.move.id = 0x3ff;
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
|
||||
// scan for any global updates
|
||||
// TODO rm me? need to grab any inits
|
||||
@@ -3202,6 +3188,7 @@ static int lfs_relocate(lfs_t *lfs,
|
||||
return err;
|
||||
}
|
||||
|
||||
// if we can't find dir, it must be new
|
||||
if (err != LFS_ERR_NOENT) {
|
||||
// just replace bad pair, no desync can occur
|
||||
parent.tail[0] = newpair[0];
|
||||
@@ -3226,7 +3213,6 @@ static int lfs_relocate(lfs_t *lfs,
|
||||
}
|
||||
}
|
||||
|
||||
// couldn't find dir, must be new
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3236,7 +3222,7 @@ int lfs_scan(lfs_t *lfs) {
|
||||
}
|
||||
|
||||
lfs_mdir_t dir = {.tail = {0, 1}};
|
||||
lfs_globals_t globals = {{{0xffffffff, 0xffffffff}, 0x3ff}};
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
|
||||
// iterate over all directory directory entries
|
||||
while (!lfs_pairisnull(dir.tail)) {
|
||||
@@ -3246,11 +3232,13 @@ int lfs_scan(lfs_t *lfs) {
|
||||
}
|
||||
|
||||
// xor together indirect deletes
|
||||
globals = lfs_globals_xor(&globals, &dir.globals);
|
||||
lfs_globalsxor(&lfs->diff, &dir.locals);
|
||||
}
|
||||
|
||||
// update littlefs with globals
|
||||
lfs->globals = globals;
|
||||
// TODO does this only run once?
|
||||
// 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_DEBUG("Found move %d %d %d",
|
||||
@@ -3285,6 +3273,9 @@ int lfs_fixmove(lfs_t *lfs) {
|
||||
return err;
|
||||
}
|
||||
|
||||
lfs->globals.move.pair[0] = 0xffffffff;
|
||||
lfs->globals.move.pair[1] = 0xffffffff;
|
||||
lfs->globals.move.id = 0x3ff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
3
lfs.h
3
lfs.h
@@ -284,7 +284,7 @@ typedef struct lfs_mdir {
|
||||
uint16_t count;
|
||||
bool erased;
|
||||
bool split;
|
||||
lfs_globals_t globals;
|
||||
lfs_globals_t locals;
|
||||
} lfs_mdir_t;
|
||||
|
||||
typedef struct lfs_cache {
|
||||
@@ -353,6 +353,7 @@ typedef struct lfs {
|
||||
|
||||
lfs_free_t free;
|
||||
bool deorphaned;
|
||||
lfs_globals_t globals2;
|
||||
lfs_globals_t globals;
|
||||
lfs_globals_t diff;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user