forked from Imagelibrary/littlefs
Continued implementation of forward-crcs, adopted new test runners
This fixes most of the remaining bugs (except one with multiple padding commits + noop erases in test_badblocks), with some other code tweaks. The biggest change was dropping reliance on end-of-block commits to know when to stop parsing commits. We can just continue to parse tags and rely on the crc for catch bad commits, avoiding a backwards-compatiblity hiccup. So no new commit tag. Also renamed nprogcrc -> fcrc and commitcrc -> ccrc and made naming in the code a bit more consistent.
This commit is contained in:
@@ -584,13 +584,14 @@ lfs_emubd_swear_t lfs_emubd_wear(const struct lfs_config *cfg,
|
||||
wear = 0;
|
||||
}
|
||||
|
||||
LFS_EMUBD_TRACE("lfs_emubd_wear -> %"PRIu32, wear);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_wear -> %"PRIi32, wear);
|
||||
return wear;
|
||||
}
|
||||
|
||||
int lfs_emubd_setwear(const struct lfs_config *cfg,
|
||||
lfs_block_t block, lfs_emubd_wear_t wear) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_setwear(%p, %"PRIu32")", (void*)cfg, block);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_setwear(%p, %"PRIu32", %"PRIi32")",
|
||||
(void*)cfg, block, wear);
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// check if block is valid
|
||||
@@ -599,12 +600,12 @@ int lfs_emubd_setwear(const struct lfs_config *cfg,
|
||||
// set the wear
|
||||
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
|
||||
if (!b) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_setwear -> %"PRIu32, LFS_ERR_NOMEM);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_setwear -> %d", LFS_ERR_NOMEM);
|
||||
return LFS_ERR_NOMEM;
|
||||
}
|
||||
b->wear = wear;
|
||||
|
||||
LFS_EMUBD_TRACE("lfs_emubd_setwear -> %"PRIu32, 0);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_setwear -> %d", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
290
lfs.c
290
lfs.c
@@ -133,6 +133,7 @@ static int lfs_bd_cmp(lfs_t *lfs,
|
||||
|
||||
for (lfs_off_t i = 0; i < size; i += diff) {
|
||||
uint8_t dat[8];
|
||||
|
||||
diff = lfs_min(size-i, sizeof(dat));
|
||||
int err = lfs_bd_read(lfs,
|
||||
pcache, rcache, hint-i,
|
||||
@@ -437,21 +438,23 @@ static inline void lfs_gstate_tole32(lfs_gstate_t *a) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// operations on estate in CRC tags
|
||||
struct lfs_estate {
|
||||
// operations on forward-CRCs used to track erased state
|
||||
struct lfs_fcrc {
|
||||
lfs_size_t size;
|
||||
uint32_t crc;
|
||||
};
|
||||
|
||||
static void lfs_estate_fromle32(struct lfs_estate *estate) {
|
||||
estate->size = lfs_fromle32(estate->size);
|
||||
estate->crc = lfs_fromle32(estate->crc);
|
||||
static void lfs_fcrc_fromle32(struct lfs_fcrc *fcrc) {
|
||||
fcrc->size = lfs_fromle32(fcrc->size);
|
||||
fcrc->crc = lfs_fromle32(fcrc->crc);
|
||||
}
|
||||
|
||||
static void lfs_estate_tole32(struct lfs_estate *estate) {
|
||||
estate->size = lfs_tole32(estate->size);
|
||||
estate->crc = lfs_tole32(estate->crc);
|
||||
#ifndef LFS_READONLY
|
||||
static void lfs_fcrc_tole32(struct lfs_fcrc *fcrc) {
|
||||
fcrc->size = lfs_tole32(fcrc->size);
|
||||
fcrc->crc = lfs_tole32(fcrc->crc);
|
||||
}
|
||||
#endif
|
||||
|
||||
// other endianness operations
|
||||
static void lfs_ctz_fromle32(struct lfs_ctz *ctz) {
|
||||
@@ -1075,8 +1078,8 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
|
||||
bool tempsplit = false;
|
||||
lfs_stag_t tempbesttag = besttag;
|
||||
|
||||
bool hasestate = false;
|
||||
struct lfs_estate estate;
|
||||
bool hasfcrc = false;
|
||||
struct lfs_fcrc fcrc;
|
||||
|
||||
dir->rev = lfs_tole32(dir->rev);
|
||||
uint32_t crc = lfs_crc(0xffffffff, &dir->rev, sizeof(dir->rev));
|
||||
@@ -1144,61 +1147,85 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
|
||||
dir->tail[1] = temptail[1];
|
||||
dir->split = tempsplit;
|
||||
|
||||
if (hasestate) {
|
||||
// check if the next page is erased
|
||||
//
|
||||
// check for an fcrc matching the next prog's erased state, if
|
||||
// this failed most likely a previous prog was interrupted, we
|
||||
// need a new erase
|
||||
if (hasfcrc) {
|
||||
// this may look inefficient, but since cache_size is
|
||||
// probably > prog_size, the data will always remain in
|
||||
// cache for the next iteration
|
||||
|
||||
// first we get a tag-worth of bits, this is so we can
|
||||
// tweak our current tag to force future writes to be
|
||||
// different than the erased state
|
||||
lfs_tag_t etag;
|
||||
// first read the leading byte, this always contains a bit
|
||||
// we can perturb to avoid writes that don't change the fcrc
|
||||
uint8_t eperturb;
|
||||
err = lfs_bd_read(lfs,
|
||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||
dir->pair[0], dir->off, &etag, sizeof(etag));
|
||||
dir->pair[0], dir->off, &eperturb, 1);
|
||||
if (err && err != LFS_ERR_CORRUPT) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// perturb valid bit?
|
||||
dir->etag |= 0x80000000 & ~lfs_frombe32(etag);
|
||||
dir->etag |= (0x80 & ~eperturb) << 24;
|
||||
|
||||
// crc the rest the full prog_size, including etag in case
|
||||
// the actual esize is < tag size (though this shouldn't
|
||||
// happen normally)
|
||||
uint32_t tcrc = 0xffffffff;
|
||||
// crc the full prog_size, don't bother avoiding a reread
|
||||
// of the eperturb, it should still be in our cache
|
||||
uint32_t ecrc = 0xffffffff;
|
||||
err = lfs_bd_crc(lfs,
|
||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||
dir->pair[0], dir->off, estate.size, &tcrc);
|
||||
dir->pair[0], dir->off, fcrc.size, &ecrc);
|
||||
if (err && err != LFS_ERR_CORRUPT) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (tcrc == estate.crc) {
|
||||
// found beginning of erased part?
|
||||
if (ecrc == fcrc.crc) {
|
||||
dir->erased = true;
|
||||
break;
|
||||
}
|
||||
} else if (lfs_tag_chunk(tag) < 2) {
|
||||
// for backwards compatibility we fall through here on
|
||||
// unrecognized tags, leaving it up to the CRC to reject
|
||||
// bad commits
|
||||
} else {
|
||||
// end of block commit
|
||||
dir->erased = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// reset crc
|
||||
crc = 0xffffffff;
|
||||
hasestate = false;
|
||||
} else {
|
||||
// crc the entry first, hopefully leaving it in the cache
|
||||
err = lfs_bd_crc(lfs,
|
||||
hasfcrc = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// crc the entry first, hopefully leaving it in the cache
|
||||
err = lfs_bd_crc(lfs,
|
||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||
dir->pair[0], off+sizeof(tag),
|
||||
lfs_tag_dsize(tag)-sizeof(tag), &crc);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
dir->erased = false;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// directory modification tags?
|
||||
if (lfs_tag_type1(tag) == LFS_TYPE_NAME) {
|
||||
// increase count of files if necessary
|
||||
if (lfs_tag_id(tag) >= tempcount) {
|
||||
tempcount = lfs_tag_id(tag) + 1;
|
||||
}
|
||||
} else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) {
|
||||
tempcount += lfs_tag_splice(tag);
|
||||
|
||||
if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
|
||||
(LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) {
|
||||
tempbesttag |= 0x80000000;
|
||||
} else if (tempbesttag != -1 &&
|
||||
lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
|
||||
tempbesttag += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
|
||||
}
|
||||
} else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) {
|
||||
tempsplit = (lfs_tag_chunk(tag) & 1);
|
||||
|
||||
err = lfs_bd_read(lfs,
|
||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||
dir->pair[0], off+sizeof(tag),
|
||||
lfs_tag_dsize(tag)-sizeof(tag), &crc);
|
||||
dir->pair[0], off+sizeof(tag), &temptail, 8);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
dir->erased = false;
|
||||
@@ -1206,78 +1233,47 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// directory modification tags?
|
||||
if (lfs_tag_type1(tag) == LFS_TYPE_NAME) {
|
||||
// increase count of files if necessary
|
||||
if (lfs_tag_id(tag) >= tempcount) {
|
||||
tempcount = lfs_tag_id(tag) + 1;
|
||||
lfs_pair_fromle32(temptail);
|
||||
} else if (lfs_tag_type3(tag) == LFS_TYPE_FCRC) {
|
||||
err = lfs_bd_read(lfs,
|
||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||
dir->pair[0], off+sizeof(tag),
|
||||
&fcrc, sizeof(fcrc));
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
dir->erased = false;
|
||||
break;
|
||||
}
|
||||
} else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) {
|
||||
tempcount += lfs_tag_splice(tag);
|
||||
|
||||
if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
|
||||
(LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) {
|
||||
tempbesttag |= 0x80000000;
|
||||
} else if (tempbesttag != -1 &&
|
||||
lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
|
||||
tempbesttag += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
|
||||
}
|
||||
} else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) {
|
||||
tempsplit = (lfs_tag_chunk(tag) & 1);
|
||||
|
||||
err = lfs_bd_read(lfs,
|
||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||
dir->pair[0], off+sizeof(tag),
|
||||
&temptail, sizeof(temptail));
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
dir->erased = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lfs_pair_fromle32(temptail);
|
||||
} else if (lfs_tag_type1(tag) == LFS_TYPE_NPROGCRC) {
|
||||
err = lfs_bd_read(lfs,
|
||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||
dir->pair[0], off+sizeof(tag),
|
||||
&estate, sizeof(estate));
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
dir->erased = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lfs_estate_fromle32(&estate);
|
||||
hasestate = true;
|
||||
}
|
||||
|
||||
// found a match for our fetcher?
|
||||
if ((fmask & tag) == (fmask & ftag)) {
|
||||
int res = cb(data, tag, &(struct lfs_diskoff){
|
||||
dir->pair[0], off+sizeof(tag)});
|
||||
if (res < 0) {
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
dir->erased = false;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
lfs_fcrc_fromle32(&fcrc);
|
||||
hasfcrc = true;
|
||||
}
|
||||
|
||||
if (res == LFS_CMP_EQ) {
|
||||
// found a match
|
||||
tempbesttag = tag;
|
||||
} else if ((LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) ==
|
||||
(LFS_MKTAG(0x7ff, 0x3ff, 0) & tempbesttag)) {
|
||||
// found an identical tag, but contents didn't match
|
||||
// this must mean that our besttag has been overwritten
|
||||
tempbesttag = -1;
|
||||
} else if (res == LFS_CMP_GT &&
|
||||
lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
|
||||
// found a greater match, keep track to keep
|
||||
// things sorted
|
||||
tempbesttag = tag | 0x80000000;
|
||||
// found a match for our fetcher?
|
||||
if ((fmask & tag) == (fmask & ftag)) {
|
||||
int res = cb(data, tag, &(struct lfs_diskoff){
|
||||
dir->pair[0], off+sizeof(tag)});
|
||||
if (res < 0) {
|
||||
if (res == LFS_ERR_CORRUPT) {
|
||||
dir->erased = false;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
if (res == LFS_CMP_EQ) {
|
||||
// found a match
|
||||
tempbesttag = tag;
|
||||
} else if ((LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) ==
|
||||
(LFS_MKTAG(0x7ff, 0x3ff, 0) & tempbesttag)) {
|
||||
// found an identical tag, but contents didn't match
|
||||
// this must mean that our besttag has been overwritten
|
||||
tempbesttag = -1;
|
||||
} else if (res == LFS_CMP_GT &&
|
||||
lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
|
||||
// found a greater match, keep track to keep things sorted
|
||||
tempbesttag = tag | 0x80000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1584,11 +1580,12 @@ static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit,
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
|
||||
static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
|
||||
// align to program units
|
||||
//
|
||||
// this gets a bit complex as we have two types of crcs:
|
||||
// - 4-word crc with estate to check following prog (middle of block)
|
||||
// - 5-word crc with fcrc to check following prog (middle of block)
|
||||
// - 2-word crc with no following prog (end of block)
|
||||
const lfs_off_t end = lfs_alignup(
|
||||
lfs_min(commit->off + 5*sizeof(uint32_t), lfs->cfg->block_size),
|
||||
@@ -1601,75 +1598,77 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
|
||||
// padding is not crced, which lets fetches skip padding but
|
||||
// makes committing a bit more complicated
|
||||
while (commit->off < end) {
|
||||
lfs_off_t off = commit->off + sizeof(lfs_tag_t);
|
||||
lfs_off_t noff = lfs_min(end - off, 0x3fe) + off;
|
||||
lfs_off_t noff = lfs_min(end - (commit->off+sizeof(lfs_tag_t)), 0x3fe)
|
||||
+ (commit->off+sizeof(lfs_tag_t));
|
||||
// too large for crc tag? need padding commits
|
||||
if (noff < end) {
|
||||
noff = lfs_min(noff, end - 2*sizeof(uint32_t));
|
||||
noff = lfs_min(noff, end - 5*sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// clamp erase size to tag size, this gives us the full tag as potential
|
||||
// to intentionally invalidate erase CRCs
|
||||
const lfs_size_t esize = lfs_max(
|
||||
lfs->cfg->prog_size, sizeof(lfs_tag_t));
|
||||
lfs_tag_t etag = 0;
|
||||
// space for estate? also only emit on last commit in padding commits
|
||||
if (noff <= lfs->cfg->block_size - esize) {
|
||||
// first we get a tag-worth of bits, this is so we can
|
||||
// tweak our current tag to force future writes to be
|
||||
// different than the erased state
|
||||
// space for fcrc?
|
||||
uint8_t eperturb = -1;
|
||||
if (noff < lfs->cfg->block_size) {
|
||||
// first read the leading byte, this always contains a bit
|
||||
// we can perturb to avoid writes that don't change the fcrc
|
||||
int err = lfs_bd_read(lfs,
|
||||
NULL, &lfs->rcache, esize,
|
||||
commit->block, noff, &etag, sizeof(etag));
|
||||
NULL, &lfs->rcache, lfs->cfg->prog_size,
|
||||
commit->block, noff, &eperturb, 1);
|
||||
if (err && err != LFS_ERR_CORRUPT) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// find expected erased state
|
||||
uint32_t ecrc = 0xffffffff;
|
||||
// find the expected fcrc, don't bother avoiding a reread
|
||||
// of the eperturb, it should still be in our cache
|
||||
struct lfs_fcrc fcrc = {
|
||||
// if our commit is a padding commit, we only care about
|
||||
// invalidating outdated commits if there is a partial write,
|
||||
// so we fcrc the minimum amount (1 byte)
|
||||
.size=(noff < end ? 1 : lfs->cfg->prog_size),
|
||||
.crc=0xffffffff,
|
||||
};
|
||||
err = lfs_bd_crc(lfs,
|
||||
NULL, &lfs->rcache, esize,
|
||||
commit->block, noff, esize, &ecrc);
|
||||
NULL, &lfs->rcache, fcrc.size,
|
||||
commit->block, noff, fcrc.size, &fcrc.crc);
|
||||
if (err && err != LFS_ERR_CORRUPT) {
|
||||
return err;
|
||||
}
|
||||
|
||||
struct lfs_estate estate = {.size = esize, .crc = ecrc};
|
||||
lfs_estate_tole32(&estate);
|
||||
lfs_fcrc_tole32(&fcrc);
|
||||
err = lfs_dir_commitattr(lfs, commit,
|
||||
LFS_MKTAG(LFS_TYPE_NPROGCRC, 0x3ff, sizeof(estate)),
|
||||
&estate);
|
||||
LFS_MKTAG(LFS_TYPE_FCRC, 0x3ff, sizeof(struct lfs_fcrc)),
|
||||
&fcrc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// build crc state
|
||||
off = commit->off + sizeof(lfs_tag_t);
|
||||
// build commit crc
|
||||
struct {
|
||||
lfs_tag_t tag;
|
||||
uint32_t crc;
|
||||
} cstate;
|
||||
lfs_tag_t ctag = LFS_MKTAG(LFS_TYPE_COMMITCRC, 0x3ff, noff-off);
|
||||
cstate.tag = lfs_tobe32(ctag ^ commit->ptag);
|
||||
commit->crc = lfs_crc(commit->crc, &cstate.tag, sizeof(cstate.tag));
|
||||
cstate.crc = lfs_tole32(commit->crc);
|
||||
} ccrc;
|
||||
lfs_tag_t ntag = LFS_MKTAG(LFS_TYPE_CCRC, 0x3ff,
|
||||
noff - (commit->off+sizeof(lfs_tag_t)));
|
||||
ccrc.tag = lfs_tobe32(ntag ^ commit->ptag);
|
||||
commit->crc = lfs_crc(commit->crc, &ccrc.tag, sizeof(lfs_tag_t));
|
||||
ccrc.crc = lfs_tole32(commit->crc);
|
||||
|
||||
int err = lfs_bd_prog(lfs,
|
||||
&lfs->pcache, &lfs->rcache, false,
|
||||
commit->block, commit->off, &cstate, sizeof(cstate));
|
||||
commit->block, commit->off, &ccrc, sizeof(ccrc));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// keep track of non-padding checksum to verify
|
||||
if (off1 == 0) {
|
||||
off1 = off;
|
||||
off1 = commit->off + sizeof(lfs_tag_t);
|
||||
crc1 = commit->crc;
|
||||
}
|
||||
|
||||
commit->off = noff;
|
||||
// perturb valid bit?
|
||||
commit->ptag = ctag | (0x80000000 & ~lfs_frombe32(etag));
|
||||
commit->ptag = ntag | ((0x80 & ~eperturb) << 24);
|
||||
// reset crc for next commit
|
||||
commit->crc = 0xffffffff;
|
||||
}
|
||||
@@ -1693,12 +1692,12 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check against known crc for non-padding commits
|
||||
// check non-padding commits against known crc
|
||||
if (crc != crc1) {
|
||||
return LFS_ERR_CORRUPT;
|
||||
}
|
||||
|
||||
// make sure to check crc in case we happened to pick
|
||||
// make sure to check crc in case we happen to pick
|
||||
// up an unrelated crc (frozen block?)
|
||||
err = lfs_bd_crc(lfs,
|
||||
NULL, &lfs->rcache, sizeof(uint32_t),
|
||||
@@ -4556,7 +4555,8 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) {
|
||||
LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0);
|
||||
LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0x000 || orphans >= 0);
|
||||
LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) < 0x3ff || orphans <= 0);
|
||||
lfs->gstate.tag += orphans;
|
||||
lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) |
|
||||
((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31));
|
||||
@@ -4587,6 +4587,10 @@ static int lfs_fs_demove(lfs_t *lfs) {
|
||||
lfs->gdisk.pair[1],
|
||||
lfs_tag_id(lfs->gdisk.tag));
|
||||
|
||||
// no other gstate is supported at this time, so if we found something else
|
||||
// something most likely went wrong in gstate calculation
|
||||
LFS_ASSERT(lfs_tag_type3(lfs->gdisk.tag) == LFS_TYPE_DELETE);
|
||||
|
||||
// fetch and delete the moved entry
|
||||
lfs_mdir_t movedir;
|
||||
int err = lfs_dir_fetch(lfs, &movedir, lfs->gdisk.pair);
|
||||
|
||||
4
lfs.h
4
lfs.h
@@ -112,8 +112,8 @@ enum lfs_type {
|
||||
LFS_TYPE_SOFTTAIL = 0x600,
|
||||
LFS_TYPE_HARDTAIL = 0x601,
|
||||
LFS_TYPE_MOVESTATE = 0x7ff,
|
||||
LFS_TYPE_COMMITCRC = 0x502,
|
||||
LFS_TYPE_NPROGCRC = 0x5ff,
|
||||
LFS_TYPE_CCRC = 0x502,
|
||||
LFS_TYPE_FCRC = 0x5ff,
|
||||
|
||||
// internal chip sources
|
||||
LFS_FROM_NOOP = 0x000,
|
||||
|
||||
@@ -23,8 +23,8 @@ TAG_TYPES = {
|
||||
'hardtail': (0x7ff, 0x601),
|
||||
'gstate': (0x700, 0x700),
|
||||
'movestate': (0x7ff, 0x7ff),
|
||||
'crc': (0x700, 0x500),
|
||||
'nprogcrc': (0x7ff, 0x5ff),
|
||||
'crc': (0x780, 0x500),
|
||||
'fcrc': (0x7ff, 0x5ff),
|
||||
}
|
||||
|
||||
class Tag:
|
||||
@@ -126,10 +126,9 @@ class Tag:
|
||||
return ntag
|
||||
|
||||
def typerepr(self):
|
||||
if (self.is_('crc') and not self.is_('nprogcrc') and
|
||||
getattr(self, 'crc', 0xffffffff) != 0xffffffff):
|
||||
if (self.is_('crc') and getattr(self, 'crc', 0xffffffff) != 0xffffffff):
|
||||
crc_status = ' (bad)'
|
||||
elif self.is_('nprogcrc') and getattr(self, 'erased', False):
|
||||
elif self.is_('fcrc') and getattr(self, 'erased', False):
|
||||
crc_status = ' (era)'
|
||||
else:
|
||||
crc_status = ''
|
||||
@@ -203,7 +202,7 @@ class MetadataPair:
|
||||
tag = Tag((int(tag) ^ ntag) & 0x7fffffff)
|
||||
tag.off = off + 4
|
||||
tag.data = block[off+4:off+tag.dsize]
|
||||
if tag.is_('crc') and not tag.is_('nprogcrc'):
|
||||
if tag.is_('crc'):
|
||||
crc = binascii.crc32(block[off:off+2*4], crc)
|
||||
else:
|
||||
crc = binascii.crc32(block[off:off+tag.dsize], crc)
|
||||
@@ -212,7 +211,7 @@ class MetadataPair:
|
||||
|
||||
self.all_.append(tag)
|
||||
|
||||
if tag.is_('nprogcrc') and len(tag.data) == 8:
|
||||
if tag.is_('fcrc') and len(tag.data) == 8:
|
||||
etag = tag
|
||||
estate = struct.unpack('<II', tag.data)
|
||||
elif tag.is_('crc'):
|
||||
@@ -228,8 +227,6 @@ class MetadataPair:
|
||||
if ecrc == dcrc:
|
||||
etag.erased = True
|
||||
corrupt = True
|
||||
elif not (tag.is_('crc 0x0') or tag.is_('crc 0x1')):
|
||||
corrupt = True
|
||||
|
||||
# reset tag parsing
|
||||
crc = 0
|
||||
@@ -244,7 +241,7 @@ class MetadataPair:
|
||||
# find most recent tags
|
||||
self.tags = []
|
||||
for tag in self.log:
|
||||
if tag.is_('crc') or tag.is_('splice'):
|
||||
if tag.is_('crc') or tag.is_('fcrc') or tag.is_('splice'):
|
||||
continue
|
||||
elif tag.id == 0x3ff:
|
||||
if tag in self and self[tag] is tag:
|
||||
|
||||
Reference in New Issue
Block a user