From 11664160a838fade5b91260756a1abf6fd8d85a6 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 25 Jun 2017 14:01:33 -0500 Subject: [PATCH] Fixed relocation bug when a file is closed with lingering caches This bug required larger cache sizes to notice, since block errors usually get detected in the early stages of writing to files. Since the fix here requires both lfs_file_write and lfs_file_flush relocate file blocks, the relocation logic was moved out into a seperate function. --- lfs.c | 99 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/lfs.c b/lfs.c index 4c135aa..4cad04c 100644 --- a/lfs.c +++ b/lfs.c @@ -1183,6 +1183,50 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { return err; } +static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { +relocate: + LFS_DEBUG("Bad block at %d", file->block); + + // just relocate what exists into new block + lfs_block_t nblock; + int err = lfs_alloc(lfs, &nblock); + if (err) { + return err; + } + + // either read from dirty cache or disk + for (lfs_off_t i = 0; i < file->off; i++) { + uint8_t data; + if (file->cache.block == file->block && i >= file->cache.off) { + data = file->cache.buffer[i - file->cache.off]; + } else { + // just read from disk + err = lfs_bd_read(lfs, file->block, i, &data, 1); + if (err) { + return err; + } + } + + err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, + nblock, i, &data, 1); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // copy over new state of file + memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); + file->cache.block = lfs->pcache.block; + file->cache.off = lfs->pcache.off; + lfs->pcache.block = 0xffffffff; + + file->block = nblock; + return 0; +} + static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_READING) { // just drop read cache @@ -1225,9 +1269,21 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { } // write out what we have - int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); - if (err) { - return err; + while (true) { + int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + break; +relocate: + err = lfs_file_relocate(lfs, file); + if (err) { + return err; + } } // actual file updates @@ -1396,45 +1452,10 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, break; relocate: - LFS_DEBUG("Bad block at %d", file->block); - - // just relocate what exists into new block - lfs_block_t nblock; - err = lfs_alloc(lfs, &nblock); + err = lfs_file_relocate(lfs, file); if (err) { return err; } - - // either read from dirty cache or disk - for (lfs_off_t i = 0; i < file->off; i++) { - uint8_t data; - if (file->cache.block == file->block && i >= file->cache.off) { - data = file->cache.buffer[i - file->cache.off]; - } else { - // just read from disk - err = lfs_bd_read(lfs, file->block, i, &data, 1); - if (err) { - return err; - } - } - - err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, - nblock, i, &data, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - // copy over new state of file - memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); - file->cache.block = lfs->pcache.block; - file->cache.off = lfs->pcache.off; - lfs->pcache.block = 0xffffffff; - - file->block = nblock; } file->pos += diff;