mirror of
https://gitee.com/openharmony/third_party_littlefs
synced 2024-12-04 05:01:55 +00:00
Fixed lfs_file_truncate issue where internal state may not be flushed
This was caused by the new lfs_file_rawseek optimization that can skip flushing when calculated file->pos is unchanged combined with an implicit expectation in lfs_file_truncate that lfs_file_rawseek unconditionally sets file->pos. Because of this assumption, lfs_file_truncate could leave file->pos in an outdated state while changing the internal file metadata. Humorously, this was always gauranteed to trigger the skip in lfs_file_rawseek when we try to restore the file->pos, leaving the file->cache used to do the CTZ skip-list lookup in a potentially bad state. The easiest fix is to just update file->pos correctly. Note we don't want to explicitly flush since we can leverage the same noop optimization if we truncate to the file position. Which I've added a test for.
This commit is contained in:
parent
3216b07c3b
commit
745d98cde0
3
lfs.c
3
lfs.c
@ -3106,6 +3106,9 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// need to set pos/block/off consistently so seeking back to
|
||||||
|
// the old position does not get confused
|
||||||
|
file->pos = size;
|
||||||
file->ctz.head = file->block;
|
file->ctz.head = file->block;
|
||||||
file->ctz.size = size;
|
file->ctz.size = size;
|
||||||
file->flags |= LFS_F_DIRTY | LFS_F_READING;
|
file->flags |= LFS_F_DIRTY | LFS_F_READING;
|
||||||
|
@ -392,3 +392,48 @@ code = '''
|
|||||||
|
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[[case]] # noop truncate
|
||||||
|
define.MEDIUMSIZE = [32, 2048]
|
||||||
|
code = '''
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "baldynoop",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT) => 0;
|
||||||
|
|
||||||
|
strcpy((char*)buffer, "hair");
|
||||||
|
size = strlen((char*)buffer);
|
||||||
|
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||||
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||||
|
|
||||||
|
// this truncate should do nothing
|
||||||
|
lfs_file_truncate(&lfs, &file, j+size) => 0;
|
||||||
|
}
|
||||||
|
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||||
|
|
||||||
|
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
|
||||||
|
// should do nothing again
|
||||||
|
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
|
||||||
|
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||||
|
|
||||||
|
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||||
|
memcmp(buffer, "hair", size) => 0;
|
||||||
|
}
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// still there after reboot?
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
|
||||||
|
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||||
|
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||||
|
memcmp(buffer, "hair", size) => 0;
|
||||||
|
}
|
||||||
|
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
Loading…
Reference in New Issue
Block a user