WIP Unknown progress, saving for reference

This commit is contained in:
Christopher Haster
2022-12-18 01:38:24 -06:00
parent a8dce05bbc
commit 4cde70dbee
2 changed files with 176 additions and 7 deletions
+174 -6
View File
@@ -659,6 +659,14 @@ struct lfs_diskoff {
lfs_off_t off;
};
struct lfs_pattern_ {
lfs_tag_t mask;
lfs_tag_t tag;
int (*cb)(void *data, lfs_block_t block, lfs_off_t off);
void *data;
lfs_off_t scratch_off;
};
#define LFS_MKATTRS(...) \
(struct lfs_mattr[]){__VA_ARGS__}, \
sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr)
@@ -667,6 +675,10 @@ struct lfs_diskoff {
(struct lfs_mattr_[]){__VA_ARGS__}, \
sizeof((struct lfs_mattr_[]){__VA_ARGS__}) / sizeof(struct lfs_mattr_)
#define LFS_MKPATTERNS_(...) \
(struct lfs_pattern_[]){__VA_ARGS__}, \
sizeof((struct lfs_pattern_[]){__VA_ARGS__}) / sizeof(struct lfs_pattern_)
// operations on global state
static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) {
for (int i = 0; i < 3; i++) {
@@ -2492,8 +2504,10 @@ lfs_ssize_t lfs_bd_progleb128_(lfs_t *lfs,
}
lfs_ssize_t lfs_bd_readtag_(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off, lfs_tag_t *tag, lfs_size_t *size) {
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_size_t hint, uint32_t *crc,
lfs_block_t block, lfs_off_t off,
lfs_tag_t *tag, lfs_size_t *size) {
uint8_t header[2*sizeof(uint32_t)];
lfs_size_t hdiff = 0;
@@ -2516,6 +2530,11 @@ lfs_ssize_t lfs_bd_readtag_(lfs_t *lfs,
}
hdiff += res;
// TODO is this the best place for this?
if (crc) {
*crc = lfs_crc(*crc, header, hdiff);
}
return hdiff;
}
@@ -2549,6 +2568,155 @@ lfs_ssize_t lfs_bd_progtag_(lfs_t *lfs,
return hdiff;
}
int lfs_dir_fetchmatch_(lfs_t *lfs,
lfs_mdir__t *mdir, const lfs_block_t pair[2],
struct lfs_pattern_ *patterns, lfs_size_t pattern_count) {
// if either block address is invalid we return LFS_ERR_CORRUPT here,
// otherwise later writes to the pair could fail
if (pair[0] >= lfs->cfg->block_count || pair[1] >= lfs->cfg->block_count) {
return LFS_ERR_CORRUPT;
}
// find the block with the most recent revision
uint32_t revs[2] = {0, 0};
int r = 0;
for (int i = 0; i < 2; i++) {
int err = lfs_bd_read(lfs,
NULL, &lfs->rcache, sizeof(revs[i]),
pair[i], 0, &revs[i], sizeof(revs[i]));
revs[i] = lfs_fromle32(revs[i]);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err != LFS_ERR_CORRUPT &&
lfs_scmp(revs[i], revs[(i+1)%2]) > 0) {
r = i;
}
}
// scan tags to fetch the mdir, possibly falling back to the other block
for (int i = 0; i < 2; i++) {
lfs_mdir__t scratch;
scratch.pair[0] = pair[(r+i+0) % 2];
scratch.pair[1] = pair[(r+i+1) % 2];
scratch.rev = revs[(r+i) % 2];
scratch.eoff = 0;
for (int i = 0; i < pattern_count; i++) {
patterns[i].scratch_off = 0;
}
bool hasestate = false;
struct lfs_estate estate;
uint32_t rev = lfs_tole32(mdir->rev);
uint32_t crc = lfs_crc(0xffffffff, &rev, sizeof(rev));
while (true) {
// extract next tag
lfs_tag_t tag;
lfs_size_t size;
lfs_ssize_t diff = lfs_bd_readtag_(lfs,
NULL, &lfs->rcache, 2*sizeof(uint32_t), &crc,
scratch.pair[0], scratch.eoff, &tag, &size);
if (diff < 0) {
if (diff == LFS_ERR_CORRUPT) {
// can't continue
mdir->erased = false;
break;
}
return diff;
}
scratch.eoff += diff;
// out of range?
if (scratch.eoff + size > lfs->cfg->block_size) {
mdir->erased = false;
break;
}
if (lfs_tag_type_(tag) == LFS_T_CRC) {
// check the crc attr
uint32_t dcrc;
int err = lfs_bd_read(lfs,
NULL, &lfs->rcache, lfs->cfg->block_size,
scratch.pair[0], scratch.eoff, &dcrc, sizeof(dcrc));
if (err) {
if (err == LFS_ERR_CORRUPT) {
mdir->erased = false;
break;
}
return err;
}
dcrc = lfs_fromle32(dcrc);
scratch.eoff += sizeof(dcrc);
if (crc != dcrc) {
mdir->erased = false;
break;
}
// TODO pseudrandom numbers, gcrc, etc
// found a valid commit!
for (int i = 0; i < pattern_count; i++) {
if (patterns[i].scratch_off != 0) {
int err = patterns[i].cb(patterns[i].data,
scratch.pair[0],
patterns[i].scratch_off);
if (err) {
return err;
}
}
patterns[i].scratch_off = 0;
}
*mdir = scratch;
if (hasestate) {
}
// reset crc for next commit
crc = 0xffffffff;
hasestate = false;
// TODO handle erasestate
mdir->erased = false; // TODO
} else {
// crc the entry first, hopefully leaving it in the cache
int err = lfs_bd_crc(lfs,
NULL, &lfs->rcache, lfs->cfg->block_size,
scratch.pair[0], scratch.eoff,
size, &crc);
if (err) {
if (err == LFS_ERR_CORRUPT) {
mdir->erased = false;
break;
}
return err;
}
// TODO handle dir modifying tags?
// found matches?
for (int i = 0; i < pattern_count; i++) {
if ((patterns[i].mask & patterns[i].tag) ==
(patterns[i].mask & tag)) {
patterns[i].scratch_off = scratch.eoff;
}
}
}
}
}
}
int lfs_dir_fetch_(lfs_t *lfs,
lfs_mdir__t *mdir, const lfs_block_t pair[2]) {
return lfs_dir_fetchmatch_(lfs, mdir, pair, NULL, 0);
}
// TODO name dir->mdir for these low-level operations?
// TODO I don't think a mask works anymore, do we need this?
lfs_stag_t lfs_dir_getattrslice_(lfs_t *lfs, lfs_mdir__t *mdir,
@@ -2566,7 +2734,7 @@ lfs_stag_t lfs_dir_getattrslice_(lfs_t *lfs, lfs_mdir__t *mdir,
lfs_tag_t rtag;
lfs_off_t rsize;
lfs_ssize_t rdiff = lfs_bd_readtag_(lfs,
NULL, &lfs->rcache, 2*sizeof(uint32_t),
NULL, &lfs->rcache, 2*sizeof(uint32_t), NULL,
mdir->pair[0], roff, &rtag, &rsize);
if (rdiff < 0) {
return rdiff;
@@ -2604,7 +2772,7 @@ lfs_stag_t lfs_dir_getattrslice_(lfs_t *lfs, lfs_mdir__t *mdir,
lfs_off_t nroff;
// TODO are hints correct both here and commit?
lfs_soff_t res = lfs_bd_readtag_(lfs,
NULL, &lfs->rcache, 2*sizeof(uint32_t),
NULL, &lfs->rcache, 2*sizeof(uint32_t), NULL,
mdir->pair[0], roff+rdiff, &ralt, &nroff);
if (res < 0) {
return res;
@@ -2716,7 +2884,7 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff,
lfs_tag_t rtag;
lfs_off_t rsize;
lfs_ssize_t res = lfs_bd_readtag_(lfs,
&lfs->pcache, &lfs->rcache, 2*sizeof(uint32_t),
&lfs->pcache, &lfs->rcache, 2*sizeof(uint32_t), NULL,
block, roff, &rtag, &rsize);
if (res < 0) {
return res;
@@ -2728,7 +2896,7 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff,
lfs_tag_t ralt;
lfs_off_t nroff;
res = lfs_bd_readtag_(lfs,
&lfs->pcache, &lfs->rcache, 2*sizeof(uint32_t),
&lfs->pcache, &lfs->rcache, 2*sizeof(uint32_t), NULL,
block, roff+rdiff, &ralt, &nroff);
if (res < 0) {
return res;
+2 -1
View File
@@ -336,7 +336,8 @@ typedef struct lfs_mdir_ {
lfs_off_t eoff;
uint16_t count;
//bool erased;
// TODO need both erased and eperturb?
bool erased;
bool split;
bool eperturb;
lfs_block_t tail[2];