Fixed incorrect cache reuse when seeking from end-of-block
In v2.5, we introduced an optimization to avoid rereading data when seeking inside the file cache. Unfortunately this used a slightly wrong condition to check if the cache was "live", which meant seeks from end-of-blocks could end up with invalid caches and wrong data. Not great. The problem is the nuance of when a file's cache is "live": 1. The file is marked as LFS_F_READING or LFS_F_WRITING. But we can't reuse the cache when writing, so we only care about LFS_F_READING. 2. file->off != lfs->cfg->block_size (end-of-block). This is an optimization to avoid eagerly reading blocks we may not actually care about. We weren't checking for the end-of-block case, which meant if you seeked _from_ the end of a block to a seemingly valid location in the file cache, you could end up with an invalid cache. Note that end-of-block may not be powers-of-two due to CTZ skip-list pointers. --- The fix is to check for the end-of-block case in lfs_file_seek. Note this now matches the need-new-block logic in lfs_file_flushedread. This logic change may also make lfs_file_seek call lfs_file_flush more often, but only in cases where lfs_file_flush is a noop. I've also extended the test_seek tests to cover a few more boundary-read cases and prevent a regression in the future. Found by wjl and lrodorigo
This commit is contained in:
@@ -3725,13 +3725,8 @@ static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file,
|
||||
|
||||
// if we're only reading and our new offset is still in the file's cache
|
||||
// we can avoid flushing and needing to reread the data
|
||||
if (
|
||||
#ifndef LFS_READONLY
|
||||
!(file->flags & LFS_F_WRITING)
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
) {
|
||||
if ((file->flags & LFS_F_READING)
|
||||
&& file->off != lfs->cfg->block_size) {
|
||||
int oindex = lfs_ctz_index(lfs, &(lfs_off_t){file->pos});
|
||||
lfs_off_t noff = npos;
|
||||
int nindex = lfs_ctz_index(lfs, &noff);
|
||||
|
||||
Reference in New Issue
Block a user