Simplified the internal xored-globals implementation

There wasn't much use (and inconsistent compiler support) for storing
small values next to the unaligned lfs_global_t struct. So instead, I've
rounded the struct up to the nearest word to try to take advantage of
the alignment in xor and memset operations.

I've also moved the global fetching into lfs_mount, since that was the
only use of the operation. This allows for some variable reuse in the
mount function.
This commit is contained in:
Christopher Haster
2018-08-03 19:01:27 -05:00
parent 35f68d28cc
commit 97f35c3e05
2 changed files with 69 additions and 105 deletions

161
lfs.c
View File

@@ -265,7 +265,6 @@ static int32_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2],
lfs_mdir_t *parent); lfs_mdir_t *parent);
static int lfs_fs_relocate(lfs_t *lfs, static int lfs_fs_relocate(lfs_t *lfs,
const lfs_block_t oldpair[2], lfs_block_t newpair[2]); const lfs_block_t oldpair[2], lfs_block_t newpair[2]);
static int lfs_fs_scan(lfs_t *lfs);
static int lfs_fs_forceconsistency(lfs_t *lfs); static int lfs_fs_forceconsistency(lfs_t *lfs);
@@ -410,14 +409,14 @@ static inline lfs_size_t lfs_tagsize(uint32_t tag) {
// operations on set of globals // operations on set of globals
static inline void lfs_globalxor(lfs_global_t *a, const lfs_global_t *b) { 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++) { for (int i = 0; i < sizeof(lfs_global_t)/4; i++) {
a->u16[i] ^= b->u16[i]; a->u32[i] ^= b->u32[i];
} }
} }
static inline bool lfs_globaliszero(const lfs_global_t *a) { static inline bool lfs_globaliszero(const lfs_global_t *a) {
for (int i = 0; i < sizeof(lfs_global_t)/2; i++) { for (int i = 0; i < sizeof(lfs_global_t)/4; i++) {
if (a->u16[i] != 0) { if (a->u32[i] != 0) {
return false; return false;
} }
} }
@@ -425,53 +424,26 @@ static inline bool lfs_globaliszero(const lfs_global_t *a) {
} }
static inline void lfs_globalzero(lfs_global_t *a) { static inline void lfs_globalzero(lfs_global_t *a) {
memset(a->u16, 0x00, sizeof(lfs_global_t)); lfs_globalxor(a, a);
}
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 void lfs_globalfromle32(lfs_global_t *a) { static inline void lfs_globalfromle32(lfs_global_t *a) {
a->u16[0] = lfs_fromle16(a->u16[0]); lfs_pairfromle32(a->s.movepair);
lfs_pairfromle32((lfs_block_t*)&a->u16[1]); a->s.moveid = lfs_fromle16(a->s.moveid);
} }
static inline void lfs_globaltole32(lfs_global_t *a) { static inline void lfs_globaltole32(lfs_global_t *a) {
a->u16[0] = lfs_tole16(a->u16[0]); lfs_pairtole32(a->s.movepair);
lfs_pairtole32((lfs_block_t*)&a->u16[1]); a->s.moveid = lfs_tole16(a->s.moveid);
}
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, static inline void lfs_globalmove(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_globalzero(&diff); lfs_globalzero(&diff);
lfs_globalxormove(&diff, lfs_globalmovepair(lfs), lfs_globalmoveid(lfs)); diff.s.movepair[0] ^= lfs->globals.s.movepair[0] ^ pair[0];
lfs_globalxormove(&diff, pair, id); diff.s.movepair[1] ^= lfs->globals.s.movepair[1] ^ pair[1];
diff.s.moveid ^= lfs->globals.s.moveid ^ id;
lfs_globalfromle32(&lfs->locals); lfs_globalfromle32(&lfs->locals);
lfs_globalxor(&lfs->locals, &diff); lfs_globalxor(&lfs->locals, &diff);
lfs_globaltole32(&lfs->locals); lfs_globaltole32(&lfs->locals);
@@ -479,11 +451,8 @@ static inline void lfs_globalmove(lfs_t *lfs,
} }
static inline void lfs_globaldeorphaned(lfs_t *lfs, bool deorphaned) { static inline void lfs_globaldeorphaned(lfs_t *lfs, bool deorphaned) {
deorphaned ^= lfs_globalisdeorphaned(lfs); lfs->locals.s.deorphaned ^= lfs->globals.s.deorphaned ^ deorphaned;
lfs_globalfromle32(&lfs->locals); lfs->globals.s.deorphaned ^= lfs->globals.s.deorphaned ^ deorphaned;
lfs_globalxordeorphaned(&lfs->locals, deorphaned);
lfs_globaltole32(&lfs->locals);
lfs_globalxordeorphaned(&lfs->globals, deorphaned);
} }
@@ -696,7 +665,8 @@ static int lfs_commitglobals(lfs_t *lfs, struct lfs_commit *commit,
lfs_globalxor(locals, &lfs->locals); lfs_globalxor(locals, &lfs->locals);
int err = lfs_commitattr(lfs, commit, int err = lfs_commitattr(lfs, commit,
LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(lfs_global_t)), locals); LFS_MKTAG(LFS_TYPE_GLOBALS + locals->s.deorphaned,
0x3ff, sizeof(lfs_global_t)), locals);
lfs_globalxor(locals, &lfs->locals); lfs_globalxor(locals, &lfs->locals);
return err; return err;
} }
@@ -893,6 +863,7 @@ static int32_t lfs_dir_find(lfs_t *lfs,
} }
lfs_pairfromle32(temptail); lfs_pairfromle32(temptail);
} else if (lfs_tagsubtype(tag) == LFS_TYPE_GLOBALS) { } else if (lfs_tagsubtype(tag) == LFS_TYPE_GLOBALS) {
templocals.s.deorphaned = (lfs_tagtype(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, sizeof(templocals)); &templocals, sizeof(templocals));
if (err) { if (err) {
@@ -929,11 +900,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_globalmovepair(lfs)) == 0) { if (lfs_paircmp(dir->pair, lfs->globals.s.movepair) == 0) {
if (lfs_globalmoveid(lfs) == lfs_tagid(foundtag)) { if (lfs->globals.s.moveid == lfs_tagid(foundtag)) {
foundtag = LFS_ERR_NOENT; foundtag = LFS_ERR_NOENT;
} else if (lfs_tagisvalid(foundtag) && } else if (lfs_tagisvalid(foundtag) &&
lfs_globalmoveid(lfs) < lfs_tagid(foundtag)) { lfs->globals.s.moveid < lfs_tagid(foundtag)) {
foundtag -= LFS_MKTAG(0, 1, 0); foundtag -= LFS_MKTAG(0, 1, 0);
} }
} }
@@ -963,8 +934,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_globalmovepair(lfs)) == 0 && if (lfs_paircmp(dir->pair, lfs->globals.s.movepair) == 0 &&
lfs_tagid(gettag) <= lfs_globalmoveid(lfs)) { lfs_tagid(gettag) <= lfs->globals.s.moveid) {
// synthetic moves // synthetic moves
getdiff = LFS_MKTAG(0, 1, 0); getdiff = LFS_MKTAG(0, 1, 0);
} }
@@ -1166,18 +1137,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_globalzero(&canceldiff); lfs_globalzero(&canceldiff);
if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0) { if (lfs_paircmp(dir->pair, lfs->globals.s.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
lfs_globalxormove(&canceldiff, canceldiff.s.movepair[0] ^= lfs->globals.s.movepair[0] ^ 0xffffffff;
lfs_globalmovepair(lfs), lfs_globalmoveid(lfs)); canceldiff.s.movepair[1] ^= lfs->globals.s.movepair[1] ^ 0xffffffff;
lfs_globalxormove(&canceldiff, canceldiff.s.moveid ^= lfs->globals.s.moveid ^ 0x3ff;
(lfs_block_t[2]){0xffffffff, 0xffffffff}, 0x3ff);
lfs_globalfromle32(&lfs->locals); lfs_globalfromle32(&lfs->locals);
lfs_globalxor(&lfs->locals, &canceldiff); lfs_globalxor(&lfs->locals, &canceldiff);
lfs_globaltole32(&lfs->locals); lfs_globaltole32(&lfs->locals);
cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs_globalmoveid(lfs), 0); cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.s.moveid, 0);
cancelattr.next = attrs; cancelattr.next = attrs;
attrs = &cancelattr; attrs = &cancelattr;
} }
@@ -2814,7 +2784,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->root[0] = 0xffffffff; lfs->root[0] = 0xffffffff;
lfs->root[1] = 0xffffffff; lfs->root[1] = 0xffffffff;
lfs->mlist = NULL; lfs->mlist = NULL;
lfs_globalones(&lfs->globals); lfs->globals.s.movepair[0] = 0xffffffff;
lfs->globals.s.movepair[1] = 0xffffffff;
lfs->globals.s.moveid = 0x3ff;
lfs->globals.s.deorphaned = true;
lfs_globalzero(&lfs->locals); lfs_globalzero(&lfs->locals);
return 0; return 0;
@@ -2920,8 +2893,8 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
lfs_alloc_ack(lfs); lfs_alloc_ack(lfs);
// load superblock // load superblock
lfs_mdir_t dir; lfs_mdir_t superdir;
err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1});
if (err) { if (err) {
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_CORRUPT) {
LFS_ERROR("Invalid superblock at %d %d", 0, 1); LFS_ERROR("Invalid superblock at %d %d", 0, 1);
@@ -2930,7 +2903,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
} }
lfs_superblock_t superblock; lfs_superblock_t superblock;
int32_t res = lfs_dir_get(lfs, &dir, 0x7ffff000, int32_t res = lfs_dir_get(lfs, &superdir, 0x7ffff000,
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)), LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)),
&superblock); &superblock);
if (res < 0) { if (res < 0) {
@@ -2951,7 +2924,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
return LFS_ERR_INVAL; return LFS_ERR_INVAL;
} }
res = lfs_dir_get(lfs, &dir, 0x7ffff000, res = lfs_dir_get(lfs, &superdir, 0x7ffff000,
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, sizeof(lfs->root)), LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, sizeof(lfs->root)),
&lfs->root); &lfs->root);
if (res < 0) { if (res < 0) {
@@ -2990,11 +2963,28 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
} }
// scan for any global updates // scan for any global updates
err = lfs_fs_scan(lfs); lfs_mdir_t dir = {.tail = {0, 1}};
while (!lfs_pairisnull(dir.tail)) {
int err = lfs_dir_fetch(lfs, &dir, dir.tail);
if (err) { if (err) {
return err; return err;
} }
// xor together indirect deletes
lfs_globalxor(&lfs->locals, &dir.locals);
}
// update littlefs with globals
lfs_globalfromle32(&lfs->locals);
lfs_globalxor(&lfs->globals, &lfs->locals);
lfs_globalzero(&lfs->locals);
if (!lfs_pairisnull(lfs->globals.s.movepair)) {
LFS_DEBUG("Found move %d %d %d",
lfs->globals.s.movepair[0],
lfs->globals.s.movepair[1],
lfs->globals.s.moveid);
}
return 0; return 0;
} }
@@ -3186,41 +3176,10 @@ static int lfs_fs_relocate(lfs_t *lfs,
return 0; return 0;
} }
static int lfs_fs_scan(lfs_t *lfs) {
if (lfs_pairisnull(lfs->root)) {
return 0;
}
// iterate over all directory directory entries
lfs_mdir_t dir = {.tail = {0, 1}};
while (!lfs_pairisnull(dir.tail)) {
int err = lfs_dir_fetch(lfs, &dir, dir.tail);
if (err) {
return err;
}
// xor together indirect deletes
lfs_globalxor(&lfs->locals, &dir.locals);
}
// update littlefs with globals
lfs_globalfromle32(&lfs->locals);
lfs_globalxor(&lfs->globals, &lfs->locals);
lfs_globalzero(&lfs->locals);
if (!lfs_pairisnull(lfs_globalmovepair(lfs))) {
LFS_DEBUG("Found move %d %d %d",
lfs_globalmovepair(lfs)[0],
lfs_globalmovepair(lfs)[1],
lfs_globalmoveid(lfs));
}
return 0;
}
static int lfs_fs_forceconsistency(lfs_t *lfs) { static int lfs_fs_forceconsistency(lfs_t *lfs) {
if (!lfs_globalisdeorphaned(lfs)) { if (!lfs->globals.s.deorphaned) {
LFS_DEBUG("Found orphans %d", LFS_DEBUG("Found orphans %d",
lfs_globalisdeorphaned(lfs)); lfs->globals.s.deorphaned);
// Fix any orphans // Fix any orphans
lfs_mdir_t pdir = {.split = true}; lfs_mdir_t pdir = {.split = true};
@@ -3292,16 +3251,16 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
lfs_globaldeorphaned(lfs, false); lfs_globaldeorphaned(lfs, false);
} }
if (lfs_globalmoveid(lfs) != 0x3ff) { if (lfs->globals.s.moveid != 0x3ff) {
// Fix bad moves // Fix bad moves
LFS_DEBUG("Fixing move %d %d %d", LFS_DEBUG("Fixing move %d %d %d",
lfs_globalmovepair(lfs)[0], lfs->globals.s.movepair[0],
lfs_globalmovepair(lfs)[1], lfs->globals.s.movepair[1],
lfs_globalmoveid(lfs)); lfs->globals.s.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_globalmovepair(lfs)); int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.s.movepair);
if (err) { if (err) {
return err; return err;
} }

9
lfs.h
View File

@@ -287,18 +287,23 @@ typedef struct lfs_cache {
} lfs_cache_t; } lfs_cache_t;
typedef union lfs_global { typedef union lfs_global {
uint16_t u16[5]; uint32_t u32[3];
struct {
lfs_block_t movepair[2];
uint16_t moveid;
bool deorphaned;
} s;
} lfs_global_t; } lfs_global_t;
typedef struct lfs_mdir { typedef struct lfs_mdir {
lfs_block_t pair[2]; lfs_block_t pair[2];
lfs_block_t tail[2];
uint32_t rev; uint32_t rev;
uint32_t etag; uint32_t etag;
lfs_off_t off; lfs_off_t off;
uint16_t count; uint16_t count;
bool erased; bool erased;
bool split; bool split;
lfs_block_t tail[2];
lfs_global_t locals; lfs_global_t locals;
} lfs_mdir_t; } lfs_mdir_t;