WIP came back and I think I got something working last time?

This commit is contained in:
Christopher Haster
2021-01-14 00:34:38 -06:00
parent a22f9afb03
commit 907b76fef3

395
lfs.c
View File

@@ -15,6 +15,7 @@ static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) {
// do not zero, cheaper if cache is readonly or only going to be
// written with identical data (during relocates)
(void)lfs;
int heh;
rcache->block = LFS_BLOCK_NULL;
}
@@ -107,6 +108,94 @@ static int lfs_bd_read(lfs_t *lfs,
return 0;
}
int lfs_bd_read_(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off,
void *buffer, lfs_size_t size) {
uint8_t *data = buffer;
if (block >= lfs->cfg->block_count) {
return LFS_ERR_CORRUPT;
}
// clamp reads to block size, this simplifies checks for
// variable sized reads (leb)
lfs_size_t overrun = off+size - lfs->cfg->block_size;
memset(data + (size - overrun), 0, overrun);
size -= overrun;
while (size > 0) {
lfs_size_t diff = size;
if (pcache && block == pcache->block &&
off < pcache->off + pcache->size) {
if (off >= pcache->off) {
// is already in pcache?
diff = lfs_min(diff, pcache->size - (off-pcache->off));
memcpy(data, &pcache->buffer[off-pcache->off], diff);
data += diff;
off += diff;
size -= diff;
continue;
}
// pcache takes priority
diff = lfs_min(diff, pcache->off-off);
}
if (block == rcache->block &&
off < rcache->off + rcache->size) {
if (off >= rcache->off) {
// is already in rcache?
diff = lfs_min(diff, rcache->size - (off-rcache->off));
memcpy(data, &rcache->buffer[off-rcache->off], diff);
data += diff;
off += diff;
size -= diff;
continue;
}
// rcache takes priority
diff = lfs_min(diff, rcache->off-off);
}
if (size >= hint && off % lfs->cfg->read_size == 0 &&
size >= lfs->cfg->read_size) {
// bypass cache?
diff = lfs_aligndown(diff, lfs->cfg->read_size);
int err = lfs->cfg->read(lfs->cfg, block, off, data, diff);
if (err) {
return err;
}
data += diff;
off += diff;
size -= diff;
continue;
}
// load to cache, first condition can no longer fail
LFS_ASSERT(block < lfs->cfg->block_count);
rcache->block = block;
rcache->off = lfs_aligndown(off, lfs->cfg->read_size);
rcache->size = lfs_min(
lfs_min(
lfs_alignup(off+hint, lfs->cfg->read_size),
lfs->cfg->block_size)
- rcache->off,
lfs->cfg->cache_size);
int err = lfs->cfg->read(lfs->cfg, rcache->block,
rcache->off, rcache->buffer, rcache->size);
LFS_ASSERT(err <= 0);
if (err) {
return err;
}
}
return 0;
}
enum {
LFS_CMP_EQ = 0,
LFS_CMP_LT = 1,
@@ -373,55 +462,55 @@ void lfs_tole32_(void *buffer, uint32_t word) {
// encode/decode leb128 integers
// TODO modify *off in place instead of returning diff?
// TODO make these static
lfs_ssize_t lfs_bd_readleb128_(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off, uint32_t *pword) {
uint32_t word = 0;
for (int i = 0; true; i++) {
uint8_t byte;
// TODO would making hint = absolute offset make more sense
// with these layers?
int err = lfs_bd_read(lfs, pcache, rcache, hint-i,
block, off+i, &byte, 1);
if (err) {
return err;
}
// check for overflow
if (i > 4 && (byte & 0x7f) > 0xf) {
return LFS_ERR_OVERFLOW;
}
word |= (byte & 0x7f) << 7*i;
if (byte & 0x80) {
*pword = word;
return i+1;
}
}
}
lfs_ssize_t lfs_bd_progleb128_(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_off_t limit, uint32_t *crc,
lfs_block_t block, lfs_off_t off, uint32_t word) {
for (int i = 0; true; i++) {
uint8_t byte = word & 0x7f;
word >>= 7;
if (word != 0) {
byte |= 0x80;
}
int err = lfs_bd_prog_(lfs, pcache, rcache, limit, crc,
block, off+i, &byte, 1);
if (err) {
return err;
}
if (word == 0) {
return i+1;
}
}
}
//lfs_ssize_t lfs_bd_readleb128_(lfs_t *lfs,
// const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
// lfs_block_t block, lfs_off_t off, uint32_t *pword) {
// uint32_t word = 0;
// for (int i = 0; true; i++) {
// uint8_t byte;
// // TODO would making hint = absolute offset make more sense
// // with these layers?
// int err = lfs_bd_read(lfs, pcache, rcache, hint-i,
// block, off+i, &byte, 1);
// if (err) {
// return err;
// }
//
// // check for overflow
// if (i > 4 && (byte & 0x7f) > 0xf) {
// return LFS_ERR_OVERFLOW;
// }
//
// word |= (byte & 0x7f) << 7*i;
// if (byte & 0x80) {
// *pword = word;
// return i+1;
// }
// }
//}
//
//lfs_ssize_t lfs_bd_progleb128_(lfs_t *lfs,
// lfs_cache_t *pcache, lfs_cache_t *rcache,
// lfs_off_t limit, uint32_t *crc,
// lfs_block_t block, lfs_off_t off, uint32_t word) {
// for (int i = 0; true; i++) {
// uint8_t byte = word & 0x7f;
// word >>= 7;
// if (word != 0) {
// byte |= 0x80;
// }
//
// int err = lfs_bd_prog_(lfs, pcache, rcache, limit, crc,
// block, off+i, &byte, 1);
// if (err) {
// return err;
// }
//
// if (word == 0) {
// return i+1;
// }
// }
//}
/// Small type-level utilities ///
// operations on block pairs
@@ -2368,6 +2457,100 @@ compact:
//
//i = 28-lfs_npw2(delta+1);
// convenience functions for reading/writing leb128 encodings
// TODO move these?
lfs_ssize_t lfs_bd_readleb128_(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off, uint32_t *pword) {
int err = lfs_bd_read(lfs,
pcache, rcache, hint,
block, off, pword, sizeof(uint32_t));
if (err) {
return err;
}
return lfs_fromleb128_(pword, pword);
}
lfs_ssize_t lfs_bd_progleb128_(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_off_t limit, uint32_t *crc,
lfs_block_t block, lfs_off_t off,
uint32_t word) {
lfs_ssize_t diff = lfs_toleb128_(&word, word);
if (diff < 0) {
return diff;
}
int err = lfs_bd_prog_(lfs,
pcache, rcache, limit, crc,
block, off, &word, diff);
if (err) {
return err;
}
return diff;
}
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) {
uint8_t header[2*sizeof(uint32_t)];
lfs_size_t hdiff = 0;
int err = lfs_bd_read(lfs,
pcache, rcache, hint,
block, off, &header, sizeof(header));
if (err) {
return err;
}
lfs_ssize_t res = lfs_fromleb128_(tag, &header[hdiff]);
if (res < 0) {
return res;
}
hdiff += res;
res = lfs_fromleb128_(size, &header[hdiff]);
if (res < 0) {
return res;
}
hdiff += res;
return hdiff;
}
lfs_ssize_t lfs_bd_progtag_(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_off_t limit, 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;
lfs_ssize_t res = lfs_toleb128_(&header[hdiff], tag);
if (res < 0) {
return res;
}
hdiff += res;
res = lfs_toleb128_(&header[hdiff], size);
if (res < 0) {
return res;
}
hdiff += res;
int err = lfs_bd_prog_(lfs,
pcache, rcache, limit, crc,
block, off, &header, hdiff);
if (err) {
return err;
}
return hdiff;
}
// TODO should we just take mdir pointer? to a copy? we're carrying
// around a lot of state
lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff,
@@ -2426,78 +2609,45 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff,
// perform radix walk for alt-pointers?
if (lfs_tag_isradix_(tag)) {
printf("finding radices for 0x%08x!\n", tag);
//printf("finding radices for 0x%08x!\n", tag);
lfs_off_t roff = *proff;
// tags use only the lower 28-bits
for (int i = 0; i < 28 && roff; i++) {
// first get tag
// TODO consolidate into function
hdiff = 0;
err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, sizeof(header),
block, roff, &header, sizeof(header));
if (err) {
return err;
}
lfs_tag_t rtag;
lfs_ssize_t res = lfs_fromleb128_(&rtag, &header[0]);
lfs_off_t rsize;
lfs_ssize_t res = lfs_bd_readtag_(lfs,
&lfs->pcache, &lfs->rcache, 2*sizeof(uint32_t),
block, roff, &rtag, &rsize);
if (res < 0) {
return res;
}
hdiff += res;
lfs_tag_t rsize;
res = lfs_fromleb128_(&rsize, &header[hdiff]);
if (res < 0) {
return res;
}
hdiff += res;
lfs_size_t rdiff = hdiff + rsize;
lfs_ssize_t rdiff = res + rsize;
while (true) {
// and alt-pointer
hdiff = 0;
err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, sizeof(header),
block, roff+rdiff, &header, sizeof(header));
if (err) {
return err;
}
lfs_tag_t ralt;
res = lfs_fromleb128_(&ralt, &header[0]);
lfs_off_t nroff;
res = lfs_bd_readtag_(lfs,
&lfs->pcache, &lfs->rcache, 2*sizeof(uint32_t),
block, roff+rdiff, &ralt, &nroff);
if (res < 0) {
return res;
}
hdiff += res;
lfs_tag_t nroff;
res = lfs_fromleb128_(&nroff, &header[hdiff]);
if (res < 0) {
return res;
}
hdiff += res;
rdiff += hdiff;
rdiff += res;
// iterate through bits
for (; i < 28; i++) {
if ((tag ^ rtag) & (1 << (28-i))) {
// different bit, new alt-pointer
hdiff = 0;
hdiff += lfs_toleb128_(
&header[hdiff], LFS_MKALT_(28-i));
hdiff += lfs_toleb128_(
&header[hdiff], roff);
printf("new alt 0x%08x 0x%08x\n", LFS_MKALT_(28-i), roff);
err = lfs_bd_prog_(lfs,
res = lfs_bd_progtag_(lfs,
&lfs->pcache, &lfs->rcache, limit, crc,
block, off+diff, &header, hdiff);
if (err) {
return err;
block, off+diff, LFS_MKALT_(28-i), roff);
if (res < 0) {
return res;
}
diff += hdiff;
diff += res;
// follow alt-pointer?
if (lfs_tag_isalt_(ralt) &&
@@ -2512,14 +2662,15 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff,
// same bit, copy alt-pointer
if (lfs_tag_isalt_(ralt) &&
lfs_tag_alt_(ralt) == 28-i) {
printf("copy alt 0x%08x 0x%08x\n", LFS_MKALT_(28-i), roff);
err = lfs_bd_prog_(lfs,
//printf("copy alt 0x%08x 0x%08x\n", LFS_MKALT_(28-i), roff);
res = lfs_bd_progtag_(lfs,
&lfs->pcache, &lfs->rcache, limit, crc,
block, off+diff, &header, hdiff);
if (err) {
return err;
block, off+diff, ralt, nroff);
if (res < 0) {
return res;
}
diff += hdiff;
diff += res;
}
if (lfs_tag_isalt_(ralt) &&
@@ -2618,7 +2769,7 @@ static lfs_ssize_t lfs_dir_commitattrs_(lfs_t *lfs, lfs_off_t *roff,
return diff;
}
static int lfs_dir_commitfinalize_(lfs_t *lfs, lfs_mdir__t *mdir,
int lfs_dir_commitfinalize_(lfs_t *lfs, lfs_mdir__t *mdir,
lfs_off_t *roff, lfs_off_t limit, uint32_t crc,
lfs_block_t block, lfs_off_t off) {
// align to program units
@@ -2671,30 +2822,34 @@ static int lfs_dir_commitfinalize_(lfs_t *lfs, lfs_mdir__t *mdir,
off += res;
}
// build CRC tag, don't go through commitattr because we don't want
// to CRC padding
// TODO wait a sec, cyclic reference because of leb-size?
// build CRC tag, don't go through commitattr because we want
// to avoid CRCing our padding
uint8_t cstate[9];
cstate[0] = (uint8_t)LFS_MKTAG_(LFS_T_CRC, 0, 0);
lfs_size_t cdiff = 0;
cstate[cdiff] = (uint8_t)LFS_MKTAG_(LFS_T_CRC, 0, 0);
cdiff += 1;
// manually write prog_size leb128 to avoid issues with
// off-by-1 padding
lfs_size_t padding = eoff - (off+csize-4);
for (lfs_size_t i = 1; i < csize-4-1; i++) {
cstate[i] = 0x80 | (padding & 0x7f);
padding >>= 7;
lfs_size_t cpadding = eoff - (off+csize-4);
lfs_ssize_t res = lfs_toleb128_(&cstate[cdiff], cpadding);
if (res < 0) {
return res;
}
cstate[csize-4-1] = padding;
LFS_ASSERT(padding <= 0x7f);
cdiff += res;
crc = lfs_crc(crc, &cstate[0], csize-4);
lfs_tole32_(&cstate[csize-4], crc);
// pad written cpadding to avoid circularly dependent sizes
for (; cdiff < csize-4; cdiff++) {
cstate[cdiff] = 0x80;
}
crc = lfs_crc(crc, &cstate, cdiff);
lfs_tole32_(&cstate[cdiff], crc);
cdiff += sizeof(uint32_t);
// TODO ugh, need to signal no validate without signalling crc...
// should use different API? separate lfs_bd_progcrc_?
int err = lfs_bd_prog_(lfs, &lfs->pcache, &lfs->rcache,
lfs->cfg->block_size, &(uint32_t){0}, block, off,
&cstate, csize);
&cstate, cdiff);
if (err) {
return err;
}