Revisited caching rules to optimize bus transactions

The littlefs driver has always had this really weird quirk: larger cache
sizes can significantly harm performance. This has probably been one of
the most surprising pieces of configuraing and optimizing littlefs.

The reason is that littlefs's caches are kinda dumb (this is somewhat
intentional, as dumb caches take up much less code space than smart
caches). When littlefs needs to read data, it will load the entire cache
line. This means that even when we only need a small 4 byte piece of
data, we may need to read a full 512 byte cache. And since
microcontrollers may be reading from storage over relatively slow bus
protocols, the time to send data over the bus may dominate other
operations.

Now that we have separate configuration options for "cache_size" and
"read_size", we can start making littlefs's caches a bit smarter. They
aren't going to be perfect, because code size is still a priority, but
there are some small improvements we can do:

1. Program caches write to prog_size aligned units, but eagerly cache as
   much as possible. There's no downside to using the full cache in
   program operations.

2. Add a hint parameter to cached reads. This internal API allows callers
   to tell the cache how much data they expect to need. This avoids
   excess bus traffic, and now we can even bypass the cache if the
   caller provides enough of a buffer.

   We can still fall back to reading full cache-lines in the cases where
   we don't know how much data we need by providing the block size as
   the hint. We do this for directory fetches and for file reads.

This has immediate improvements for both metadata-log traversal and CTZ
skip-list traversal, since these both only need to read 4-byte pointers
and can always bypass the cache, allowing reuse elsewhere.
This commit is contained in:
Christopher Haster 2018-08-20 14:47:52 -05:00
parent 4db96d4d44
commit 478dcdddef

300
lfs.c
View File

@ -20,8 +20,21 @@
/// Caching block device operations ///
static int lfs_cache_read(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, bool store,
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;
rcache->block = 0xffffffff;
}
static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) {
// zero to avoid information leak
memset(pcache->buffer, 0xff, lfs->cfg->prog_size);
pcache->block = 0xffffffff;
}
static 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;
@ -57,7 +70,7 @@ static int lfs_cache_read(lfs_t *lfs,
continue;
}
if (!store && off % lfs->cfg->read_size == 0 &&
if (size >= hint && off % lfs->cfg->read_size == 0 &&
size >= lfs->cfg->read_size) {
// bypass cache?
lfs_size_t diff = size - (size % lfs->cfg->read_size);
@ -74,12 +87,13 @@ static int lfs_cache_read(lfs_t *lfs,
// load to cache, first condition can no longer fail
LFS_ASSERT(block < lfs->cfg->block_count);
lfs_size_t nsize = store ? lfs->cfg->cache_size : lfs->cfg->prog_size;
rcache->block = block;
rcache->off = lfs_aligndown(off, nsize);
rcache->size = nsize;
rcache->off = lfs_aligndown(off, lfs->cfg->prog_size);
rcache->size = lfs_min(lfs_min(
lfs_alignup(off+hint, lfs->cfg->prog_size),
lfs->cfg->block_size) - rcache->off, lfs->cfg->cache_size);
int err = lfs->cfg->read(lfs->cfg, rcache->block,
rcache->off, rcache->buffer, nsize);
rcache->off, rcache->buffer, rcache->size);
if (err) {
return err;
}
@ -88,21 +102,22 @@ static int lfs_cache_read(lfs_t *lfs,
return 0;
}
static int lfs_cache_cmp(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache,
static int lfs_bd_cmp(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off,
const void *buffer, lfs_size_t size) {
const uint8_t *data = buffer;
for (lfs_off_t i = 0; i < size; i++) {
uint8_t c;
int err = lfs_cache_read(lfs, pcache, rcache, true,
block, off+i, &c, 1);
uint8_t dat;
int err = lfs_bd_read(lfs,
pcache, rcache, hint-i,
block, off+i, &dat, 1);
if (err) {
return err;
}
if (c != data[i]) {
if (dat != data[i]) {
return false;
}
}
@ -110,37 +125,7 @@ static int lfs_cache_cmp(lfs_t *lfs,
return true;
}
static int lfs_cache_crc(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_block_t block, lfs_off_t off, lfs_size_t size, uint32_t *crc) {
for (lfs_off_t i = 0; i < size; i++) {
uint8_t c;
int err = lfs_cache_read(lfs, pcache, rcache, true,
block, off+i, &c, 1);
if (err) {
return err;
}
*crc = lfs_crc(*crc, &c, 1);
}
return 0;
}
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;
rcache->block = 0xffffffff;
}
static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) {
// zero to avoid information leak
memset(pcache->buffer, 0xff, lfs->cfg->prog_size);
pcache->block = 0xffffffff;
}
static int lfs_cache_flush(lfs_t *lfs,
static int lfs_bd_flush(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) {
if (pcache->block != 0xffffffff && pcache->block != 0xfffffffe) {
LFS_ASSERT(pcache->block < lfs->cfg->block_count);
@ -154,8 +139,9 @@ static int lfs_cache_flush(lfs_t *lfs,
if (validate) {
// check data on disk
lfs_cache_drop(lfs, rcache);
int res = lfs_cache_cmp(lfs, NULL, rcache, pcache->block,
pcache->off, pcache->buffer, diff);
int res = lfs_bd_cmp(lfs,
NULL, rcache, diff,
pcache->block, pcache->off, pcache->buffer, diff);
if (res < 0) {
return res;
}
@ -171,7 +157,19 @@ static int lfs_cache_flush(lfs_t *lfs,
return 0;
}
static int lfs_cache_prog(lfs_t *lfs,
static int lfs_bd_sync(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) {
lfs_cache_drop(lfs, rcache);
int err = lfs_bd_flush(lfs, pcache, rcache, validate);
if (err) {
return err;
}
return lfs->cfg->sync(lfs->cfg);
}
static int lfs_bd_prog(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate,
lfs_block_t block, lfs_off_t off,
const void *buffer, lfs_size_t size) {
@ -195,7 +193,7 @@ static int lfs_cache_prog(lfs_t *lfs,
pcache->size = off - pcache->off;
if (pcache->size == lfs->cfg->cache_size) {
// eagerly flush out pcache if we fill up
int err = lfs_cache_flush(lfs, pcache, rcache, validate);
int err = lfs_bd_flush(lfs, pcache, rcache, validate);
if (err) {
return err;
}
@ -217,46 +215,11 @@ static int lfs_cache_prog(lfs_t *lfs,
return 0;
}
/// General lfs block device operations ///
static int lfs_bd_read(lfs_t *lfs, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
return lfs_cache_read(lfs, &lfs->pcache, &lfs->rcache, true,
block, off, buffer, size);
}
static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
return lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, false,
block, off, buffer, size);
}
static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
return lfs_cache_cmp(lfs, NULL, &lfs->rcache, block, off, buffer, size);
}
static int lfs_bd_crc32(lfs_t *lfs, lfs_block_t block,
lfs_off_t off, lfs_size_t size, uint32_t *crc) {
return lfs_cache_crc(lfs, NULL, &lfs->rcache, block, off, size, crc);
}
static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
LFS_ASSERT(block < lfs->cfg->block_count);
return lfs->cfg->erase(lfs->cfg, block);
}
static int lfs_bd_sync(lfs_t *lfs) {
lfs_cache_drop(lfs, &lfs->rcache);
int err = lfs_cache_flush(lfs, &lfs->pcache, &lfs->rcache, false);
if (err) {
return err;
}
return lfs->cfg->sync(lfs->cfg);
}
/// Internal operations predeclared here ///
static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2],
@ -513,8 +476,9 @@ static int32_t lfs_commit_get(lfs_t *lfs, lfs_block_t block, lfs_off_t off,
if (buffer) {
lfs_size_t diff = lfs_min(
lfs_tag_size(gettag), lfs_tag_size(tag));
int err = lfs_bd_read(lfs, block,
off+sizeof(tag), buffer, diff);
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, diff,
block, off+sizeof(tag), buffer, diff);
if (err) {
return err;
}
@ -527,7 +491,9 @@ static int32_t lfs_commit_get(lfs_t *lfs, lfs_block_t block, lfs_off_t off,
}
uint32_t ntag;
int err = lfs_bd_read(lfs, block, off, &ntag, sizeof(ntag));
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, sizeof(ntag),
block, off, &ntag, sizeof(ntag));
if (err) {
return err;
}
@ -567,8 +533,9 @@ static int lfs_commit_attr(lfs_t *lfs, struct lfs_commit *commit,
// write out tag
uint32_t ntag = lfs_tole32((tag & 0x7fffffff) ^ commit->ptag);
commit->crc = lfs_crc(commit->crc, &ntag, sizeof(ntag));
int err = lfs_bd_prog(lfs, commit->block, commit->off,
&ntag, sizeof(ntag));
int err = lfs_bd_prog(lfs,
&lfs->pcache, &lfs->rcache, false,
commit->block, commit->off, &ntag, sizeof(ntag));
if (err) {
return err;
}
@ -577,7 +544,9 @@ static int lfs_commit_attr(lfs_t *lfs, struct lfs_commit *commit,
if (!(tag & 0x80000000)) {
// from memory
commit->crc = lfs_crc(commit->crc, buffer, size);
err = lfs_bd_prog(lfs, commit->block, commit->off, buffer, size);
err = lfs_bd_prog(lfs,
&lfs->pcache, &lfs->rcache, false,
commit->block, commit->off, buffer, size);
if (err) {
return err;
}
@ -587,13 +556,17 @@ static int lfs_commit_attr(lfs_t *lfs, struct lfs_commit *commit,
for (lfs_off_t i = 0; i < size; i++) {
// rely on caching to make this efficient
uint8_t dat;
err = lfs_bd_read(lfs, disk->block, disk->off+i, &dat, 1);
err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, size-i,
disk->block, disk->off+i, &dat, 1);
if (err) {
return err;
}
commit->crc = lfs_crc(commit->crc, &dat, 1);
err = lfs_bd_prog(lfs, commit->block, commit->off+i, &dat, 1);
err = lfs_bd_prog(lfs,
&lfs->pcache, &lfs->rcache, false,
commit->block, commit->off+i, &dat, 1);
if (err) {
return err;
}
@ -641,7 +614,9 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit,
disk.block = dir->pair[0];
disk.off = off + sizeof(tag);
int err = lfs_bd_read(lfs, dir->pair[0], off, &ntag, sizeof(ntag));
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, sizeof(ntag),
dir->pair[0], off, &ntag, sizeof(ntag));
if (err) {
return err;
}
@ -701,10 +676,14 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) {
lfs->cfg->prog_size);
// read erased state from next program unit
uint32_t tag;
int err = lfs_bd_read(lfs, commit->block, off, &tag, sizeof(tag));
if (err) {
return err;
uint32_t tag = 0;
if (off < lfs->cfg->block_size) {
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
commit->block, off, &tag, sizeof(tag));
if (err) {
return err;
}
}
// build crc tag
@ -718,7 +697,9 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) {
footer[0] = lfs_tole32(tag ^ commit->ptag);
commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0]));
footer[1] = lfs_tole32(commit->crc);
err = lfs_bd_prog(lfs, commit->block, commit->off, footer, sizeof(footer));
int err = lfs_bd_prog(lfs,
&lfs->pcache, &lfs->rcache, false,
commit->block, commit->off, &footer, sizeof(footer));
if (err) {
return err;
}
@ -726,15 +707,27 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) {
commit->ptag = tag;
// flush buffers
err = lfs_bd_sync(lfs);
err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false);
if (err) {
return err;
}
// successful commit, check checksum to make sure
uint32_t crc = 0xffffffff;
err = lfs_bd_crc32(lfs, commit->block, commit->begin,
commit->off-lfs_tag_size(tag)-commit->begin, &crc);
lfs_size_t size = commit->off - lfs_tag_size(tag) - commit->begin;
for (lfs_off_t i = 0; i < size; i++) {
// leave it up to caching to make this efficient
uint8_t dat;
err = lfs_bd_read(lfs,
NULL, &lfs->rcache, size-i,
commit->block, commit->begin+i, &dat, 1);
if (err) {
return err;
}
crc = lfs_crc(crc, &dat, 1);
}
if (err) {
return err;
}
@ -758,7 +751,13 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
// rather than clobbering one of the blocks we just pretend
// the revision may be valid
int err = lfs_bd_read(lfs, dir->pair[0], 0, &dir->rev, 4);
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, sizeof(dir->rev),
dir->pair[0], 0, &dir->rev, sizeof(dir->rev));
if (err) {
return err;
}
dir->rev = lfs_fromle32(dir->rev);
if (err && err != LFS_ERR_CORRUPT) {
return err;
@ -788,7 +787,8 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
// find the block with the most recent revision
uint32_t rev[2];
for (int i = 0; i < 2; i++) {
int err = lfs_cache_read(lfs, &lfs->pcache, &lfs->rcache, false,
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, sizeof(rev[i]),
dir->pair[i], 0, &rev[i], sizeof(rev[i]));
rev[i] = lfs_fromle32(rev[i]);
if (err && err != LFS_ERR_CORRUPT) {
@ -824,10 +824,17 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
lfs_global_zero(&templocals);
while (true) {
// reached end of block
if (off+sizeof(uint32_t) >= lfs->cfg->block_size) {
dir->erased = false;
break;
}
// extract next tag
uint32_t tag;
int err = lfs_bd_read(lfs, dir->pair[0],
off, &tag, sizeof(tag));
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
dir->pair[0], off, &tag, sizeof(tag));
if (err) {
if (err == LFS_ERR_CORRUPT) {
// can't continue?
@ -855,8 +862,9 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
if (lfs_tag_type(tag) == LFS_TYPE_CRC) {
// check the crc attr
uint32_t dcrc;
err = lfs_bd_read(lfs, dir->pair[0],
off+sizeof(tag), &dcrc, sizeof(dcrc));
err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc));
if (err) {
if (err == LFS_ERR_CORRUPT) {
dir->erased = false;
@ -883,23 +891,35 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
lfs->seed ^= crc;
crc = 0xffffffff;
} else {
err = lfs_bd_crc32(lfs, dir->pair[0],
off+sizeof(tag), lfs_tag_size(tag), &crc);
if (err) {
if (err == LFS_ERR_CORRUPT) {
dir->erased = false;
break;
// crc the entry first, leaving it in the cache
for (lfs_off_t j = 0; j < lfs_tag_size(tag); j++) {
uint8_t dat;
err = lfs_bd_read(lfs,
NULL, &lfs->rcache, lfs->cfg->block_size,
dir->pair[0], off+sizeof(tag)+j, &dat, 1);
if (err) {
if (err == LFS_ERR_CORRUPT) {
dir->erased = false;
break;
}
return err;
}
crc = lfs_crc(crc, &dat, 1);
}
// keep track of id count
if (lfs_tag_id(tag) < 0x3ff && lfs_tag_id(tag) >= tempcount) {
tempcount = lfs_tag_id(tag)+1;
}
// check for special tags
if (lfs_tag_subtype(tag) == LFS_TYPE_TAIL) {
tempsplit = (lfs_tag_type(tag) & 1);
err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
temptail, sizeof(temptail));
err = lfs_bd_read(lfs,
&lfs->pcache, &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;
@ -909,7 +929,9 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
lfs_pair_fromle32(temptail);
} else if (lfs_tag_subtype(tag) == LFS_TYPE_GLOBALS) {
templocals.l.deorphaned = (lfs_tag_type(tag) & 1);
err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
dir->pair[0], off+sizeof(tag),
&templocals, 10);
if (err) {
if (err == LFS_ERR_CORRUPT) {
@ -931,8 +953,11 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
// found a match?
if (lfs_tag_type(findtag) == LFS_TYPE_DIRSTRUCT) {
lfs_block_t child[2];
err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
child, sizeof(child));
err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache,
lfs->cfg->block_size,
dir->pair[0], off+sizeof(tag),
&child, sizeof(child));
if (err < 0) {
if (err == LFS_ERR_CORRUPT) {
dir->erased = false;
@ -948,6 +973,7 @@ static int32_t lfs_dir_fetchmatch(lfs_t *lfs,
}
} else if (lfs_tag_type(findtag) == LFS_TYPE_NAME) {
int res = lfs_bd_cmp(lfs,
NULL, &lfs->rcache, lfs_tag_size(findtag),
dir->pair[0], off+sizeof(tag),
findbuffer, lfs_tag_size(findtag));
if (res < 0) {
@ -1091,7 +1117,9 @@ static int lfs_dir_compact(lfs_t *lfs,
uint32_t crc = 0xffffffff;
uint32_t rev = lfs_tole32(dir->rev);
crc = lfs_crc(crc, &rev, sizeof(rev));
err = lfs_bd_prog(lfs, dir->pair[1], 0, &rev, sizeof(rev));
err = lfs_bd_prog(lfs,
&lfs->pcache, &lfs->rcache, false,
dir->pair[1], 0, &rev, sizeof(rev));
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
@ -1788,8 +1816,9 @@ static int lfs_ctz_find(lfs_t *lfs,
lfs_npw2(current-target+1) - 1,
lfs_ctz(current));
int err = lfs_cache_read(lfs, pcache, rcache, false,
head, 4*skip, &head, 4);
int err = lfs_bd_read(lfs,
pcache, rcache, sizeof(head),
head, 4*skip, &head, sizeof(head));
head = lfs_fromle32(head);
if (err) {
return err;
@ -1839,13 +1868,15 @@ static int lfs_ctz_extend(lfs_t *lfs,
if (size != lfs->cfg->block_size) {
for (lfs_off_t i = 0; i < size; i++) {
uint8_t data;
err = lfs_cache_read(lfs, NULL, rcache, true,
err = lfs_bd_read(lfs,
NULL, rcache, size-i,
head, i, &data, 1);
if (err) {
return err;
}
err = lfs_cache_prog(lfs, pcache, rcache, true,
err = lfs_bd_prog(lfs,
pcache, rcache, true,
nblock, i, &data, 1);
if (err) {
if (err == LFS_ERR_CORRUPT) {
@ -1866,7 +1897,7 @@ static int lfs_ctz_extend(lfs_t *lfs,
for (lfs_off_t i = 0; i < skips; i++) {
head = lfs_tole32(head);
err = lfs_cache_prog(lfs, pcache, rcache, true,
err = lfs_bd_prog(lfs, pcache, rcache, true,
nblock, 4*i, &head, 4);
head = lfs_fromle32(head);
if (err) {
@ -1877,8 +1908,9 @@ static int lfs_ctz_extend(lfs_t *lfs,
}
if (i != skips-1) {
err = lfs_cache_read(lfs, NULL, rcache, false,
head, 4*i, &head, 4);
err = lfs_bd_read(lfs,
NULL, rcache, sizeof(head),
head, 4*i, &head, sizeof(head));
head = lfs_fromle32(head);
if (err) {
return err;
@ -1922,8 +1954,9 @@ static int lfs_ctz_traverse(lfs_t *lfs,
lfs_block_t heads[2];
int count = 2 - (index & 1);
err = lfs_cache_read(lfs, pcache, rcache, false,
head, 0, &heads, count*4);
err = lfs_bd_read(lfs,
pcache, rcache, count*sizeof(head),
head, 0, &heads, count*sizeof(head));
heads[0] = lfs_fromle32(heads[0]);
heads[1] = lfs_fromle32(heads[1]);
if (err) {
@ -2131,13 +2164,15 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
// either read from dirty cache or disk
for (lfs_off_t i = 0; i < file->off; i++) {
uint8_t data;
err = lfs_cache_read(lfs, &file->cache, &lfs->rcache, true,
err = lfs_bd_read(lfs,
&file->cache, &lfs->rcache, file->off-i,
file->block, i, &data, 1);
if (err) {
return err;
}
err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, true,
err = lfs_bd_prog(lfs,
&lfs->pcache, &lfs->rcache, true,
nblock, i, &data, 1);
if (err) {
if (err == LFS_ERR_CORRUPT) {
@ -2207,7 +2242,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
// write out what we have
while (true) {
int err = lfs_cache_flush(lfs,
int err = lfs_bd_flush(lfs,
&file->cache, &lfs->rcache, true);
if (err) {
if (err == LFS_ERR_CORRUPT) {
@ -2350,7 +2385,8 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
// read as much as we can in current block
lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
int err = lfs_cache_read(lfs, NULL, &file->cache, true,
int err = lfs_bd_read(lfs,
NULL, &file->cache, lfs->cfg->block_size,
file->block, file->off, data, diff);
if (err) {
return err;
@ -2455,7 +2491,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
// program as much as we can in current block
lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
while (true) {
int err = lfs_cache_prog(lfs, &file->cache, &lfs->rcache, true,
int err = lfs_bd_prog(lfs, &file->cache, &lfs->rcache, true,
file->block, file->off, data, diff);
if (err) {
if (err == LFS_ERR_CORRUPT) {