WIP Unknown progress, saving for reference
This commit is contained in:
@@ -659,6 +659,14 @@ struct lfs_diskoff {
|
|||||||
lfs_off_t off;
|
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(...) \
|
#define LFS_MKATTRS(...) \
|
||||||
(struct lfs_mattr[]){__VA_ARGS__}, \
|
(struct lfs_mattr[]){__VA_ARGS__}, \
|
||||||
sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr)
|
sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr)
|
||||||
@@ -667,6 +675,10 @@ struct lfs_diskoff {
|
|||||||
(struct lfs_mattr_[]){__VA_ARGS__}, \
|
(struct lfs_mattr_[]){__VA_ARGS__}, \
|
||||||
sizeof((struct lfs_mattr_[]){__VA_ARGS__}) / sizeof(struct lfs_mattr_)
|
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
|
// operations on global state
|
||||||
static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) {
|
static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) {
|
||||||
for (int i = 0; i < 3; i++) {
|
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_ssize_t lfs_bd_readtag_(lfs_t *lfs,
|
||||||
lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
|
lfs_cache_t *pcache, lfs_cache_t *rcache,
|
||||||
lfs_block_t block, lfs_off_t off, lfs_tag_t *tag, lfs_size_t *size) {
|
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)];
|
uint8_t header[2*sizeof(uint32_t)];
|
||||||
lfs_size_t hdiff = 0;
|
lfs_size_t hdiff = 0;
|
||||||
|
|
||||||
@@ -2516,6 +2530,11 @@ lfs_ssize_t lfs_bd_readtag_(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
hdiff += res;
|
hdiff += res;
|
||||||
|
|
||||||
|
// TODO is this the best place for this?
|
||||||
|
if (crc) {
|
||||||
|
*crc = lfs_crc(*crc, header, hdiff);
|
||||||
|
}
|
||||||
|
|
||||||
return hdiff;
|
return hdiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2549,6 +2568,155 @@ lfs_ssize_t lfs_bd_progtag_(lfs_t *lfs,
|
|||||||
return hdiff;
|
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 name dir->mdir for these low-level operations?
|
||||||
// TODO I don't think a mask works anymore, do we need this?
|
// 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,
|
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_tag_t rtag;
|
||||||
lfs_off_t rsize;
|
lfs_off_t rsize;
|
||||||
lfs_ssize_t rdiff = lfs_bd_readtag_(lfs,
|
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);
|
mdir->pair[0], roff, &rtag, &rsize);
|
||||||
if (rdiff < 0) {
|
if (rdiff < 0) {
|
||||||
return rdiff;
|
return rdiff;
|
||||||
@@ -2604,7 +2772,7 @@ lfs_stag_t lfs_dir_getattrslice_(lfs_t *lfs, lfs_mdir__t *mdir,
|
|||||||
lfs_off_t nroff;
|
lfs_off_t nroff;
|
||||||
// TODO are hints correct both here and commit?
|
// TODO are hints correct both here and commit?
|
||||||
lfs_soff_t res = lfs_bd_readtag_(lfs,
|
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);
|
mdir->pair[0], roff+rdiff, &ralt, &nroff);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return res;
|
return res;
|
||||||
@@ -2716,7 +2884,7 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff,
|
|||||||
lfs_tag_t rtag;
|
lfs_tag_t rtag;
|
||||||
lfs_off_t rsize;
|
lfs_off_t rsize;
|
||||||
lfs_ssize_t res = lfs_bd_readtag_(lfs,
|
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);
|
block, roff, &rtag, &rsize);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return res;
|
return res;
|
||||||
@@ -2728,7 +2896,7 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff,
|
|||||||
lfs_tag_t ralt;
|
lfs_tag_t ralt;
|
||||||
lfs_off_t nroff;
|
lfs_off_t nroff;
|
||||||
res = lfs_bd_readtag_(lfs,
|
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);
|
block, roff+rdiff, &ralt, &nroff);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
Reference in New Issue
Block a user