Merge pull request #800 from littlefs-project/fix-boundary-truncates

Fix block-boundary truncate issues
This commit is contained in:
Christopher Haster
2023-04-26 14:31:23 -05:00
committed by GitHub
2 changed files with 104 additions and 53 deletions
+48 -19
View File
@@ -3465,7 +3465,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
// find out which block we're extending from // find out which block we're extending from
int err = lfs_ctz_find(lfs, NULL, &file->cache, int err = lfs_ctz_find(lfs, NULL, &file->cache,
file->ctz.head, file->ctz.size, file->ctz.head, file->ctz.size,
file->pos-1, &file->block, &file->off); file->pos-1, &file->block, &(lfs_off_t){0});
if (err) { if (err) {
file->flags |= LFS_F_ERRED; file->flags |= LFS_F_ERRED;
return err; return err;
@@ -3643,26 +3643,55 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
lfs_off_t pos = file->pos; lfs_off_t pos = file->pos;
lfs_off_t oldsize = lfs_file_rawsize(lfs, file); lfs_off_t oldsize = lfs_file_rawsize(lfs, file);
if (size < oldsize) { if (size < oldsize) {
// need to flush since directly changing metadata // revert to inline file?
int err = lfs_file_flush(lfs, file); if (size <= lfs_min(0x3fe, lfs_min(
if (err) { lfs->cfg->cache_size,
return err; (lfs->cfg->metadata_max ?
} lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
// flush+seek to head
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET);
if (res < 0) {
return (int)res;
}
// lookup new head in ctz skip list // read our data into rcache temporarily
err = lfs_ctz_find(lfs, NULL, &file->cache, lfs_cache_drop(lfs, &lfs->rcache);
file->ctz.head, file->ctz.size, res = lfs_file_flushedread(lfs, file,
size, &file->block, &file->off); lfs->rcache.buffer, size);
if (err) { if (res < 0) {
return err; return (int)res;
} }
// need to set pos/block/off consistently so seeking back to file->ctz.head = LFS_BLOCK_INLINE;
// the old position does not get confused file->ctz.size = size;
file->pos = size; file->flags |= LFS_F_DIRTY | LFS_F_READING | LFS_F_INLINE;
file->ctz.head = file->block; file->cache.block = file->ctz.head;
file->ctz.size = size; file->cache.off = 0;
file->flags |= LFS_F_DIRTY | LFS_F_READING; file->cache.size = lfs->cfg->cache_size;
memcpy(file->cache.buffer, lfs->rcache.buffer, size);
} else {
// need to flush since directly changing metadata
int err = lfs_file_flush(lfs, file);
if (err) {
return err;
}
// lookup new head in ctz skip list
err = lfs_ctz_find(lfs, NULL, &file->cache,
file->ctz.head, file->ctz.size,
size-1, &file->block, &(lfs_off_t){0});
if (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.size = size;
file->flags |= LFS_F_DIRTY | LFS_F_READING;
}
} else if (size > oldsize) { } else if (size > oldsize) {
// flush+seek if not already at end // flush+seek if not already at end
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END); lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
+56 -34
View File
@@ -1,7 +1,8 @@
# simple truncate # simple truncate
[cases.test_truncate_simple] [cases.test_truncate_simple]
defines.MEDIUMSIZE = [32, 2048] defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
defines.LARGESIZE = 8192 defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
if = 'MEDIUMSIZE < LARGESIZE'
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -14,7 +15,8 @@ code = '''
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -37,8 +39,9 @@ code = '''
size = strlen("hair"); size = strlen("hair");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
memcmp(buffer, "hair", size) => 0; => lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs_file_read(&lfs, &file, buffer, size) => 0;
@@ -48,8 +51,9 @@ code = '''
# truncate and read # truncate and read
[cases.test_truncate_read] [cases.test_truncate_read]
defines.MEDIUMSIZE = [32, 2048] defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
defines.LARGESIZE = 8192 defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
if = 'MEDIUMSIZE < LARGESIZE'
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -62,7 +66,8 @@ code = '''
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -78,8 +83,9 @@ code = '''
size = strlen("hair"); size = strlen("hair");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
memcmp(buffer, "hair", size) => 0; => lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs_file_read(&lfs, &file, buffer, size) => 0;
@@ -92,8 +98,9 @@ code = '''
size = strlen("hair"); size = strlen("hair");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
memcmp(buffer, "hair", size) => 0; => lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs_file_read(&lfs, &file, buffer, size) => 0;
@@ -148,7 +155,7 @@ code = '''
lfs_file_truncate(&lfs, &file, trunc) => 0; lfs_file_truncate(&lfs, &file, trunc) => 0;
lfs_file_tell(&lfs, &file) => qsize; lfs_file_tell(&lfs, &file) => qsize;
lfs_file_size(&lfs, &file) => trunc; lfs_file_size(&lfs, &file) => trunc;
/* Read should produce second quarter */ /* Read should produce second quarter */
lfs_file_read(&lfs, &file, rb, size) => trunc - qsize; lfs_file_read(&lfs, &file, rb, size) => trunc - qsize;
memcmp(rb, wb + qsize, trunc - qsize) => 0; memcmp(rb, wb + qsize, trunc - qsize) => 0;
@@ -159,8 +166,9 @@ code = '''
# truncate and write # truncate and write
[cases.test_truncate_write] [cases.test_truncate_write]
defines.MEDIUMSIZE = [32, 2048] defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
defines.LARGESIZE = 8192 defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
if = 'MEDIUMSIZE < LARGESIZE'
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -173,7 +181,8 @@ code = '''
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -184,13 +193,16 @@ code = '''
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
/* truncate */
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
/* and write */
strcpy((char*)buffer, "bald"); strcpy((char*)buffer, "bald");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
} }
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -203,8 +215,9 @@ code = '''
size = strlen("bald"); size = strlen("bald");
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
memcmp(buffer, "bald", size) => 0; => lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "bald", lfs_min(size, MEDIUMSIZE-j)) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs_file_read(&lfs, &file, buffer, size) => 0;
@@ -215,7 +228,7 @@ code = '''
# truncate write under powerloss # truncate write under powerloss
[cases.test_truncate_reentrant_write] [cases.test_truncate_reentrant_write]
defines.SMALLSIZE = [4, 512] defines.SMALLSIZE = [4, 512]
defines.MEDIUMSIZE = [32, 1024] defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025]
defines.LARGESIZE = 2048 defines.LARGESIZE = 2048
reentrant = true reentrant = true
code = ''' code = '''
@@ -236,10 +249,11 @@ code = '''
size == (size_t)SMALLSIZE); size == (size_t)SMALLSIZE);
for (lfs_off_t j = 0; j < size; j += 4) { for (lfs_off_t j = 0; j < size; j += 4) {
uint8_t buffer[1024]; uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 4) => 4; lfs_file_read(&lfs, &file, buffer, lfs_min(4, size-j))
assert(memcmp(buffer, "hair", 4) == 0 || => lfs_min(4, size-j);
memcmp(buffer, "bald", 4) == 0 || assert(memcmp(buffer, "hair", lfs_min(4, size-j)) == 0 ||
memcmp(buffer, "comb", 4) == 0); memcmp(buffer, "bald", lfs_min(4, size-j)) == 0 ||
memcmp(buffer, "comb", lfs_min(4, size-j)) == 0);
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
@@ -251,19 +265,23 @@ code = '''
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
} }
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
/* truncate */
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
/* and write */
strcpy((char*)buffer, "bald"); strcpy((char*)buffer, "bald");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
} }
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -275,7 +293,8 @@ code = '''
strcpy((char*)buffer, "comb"); strcpy((char*)buffer, "comb");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < SMALLSIZE; j += size) { for (lfs_off_t j = 0; j < SMALLSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, SMALLSIZE-j))
=> lfs_min(size, SMALLSIZE-j);
} }
lfs_file_size(&lfs, &file) => SMALLSIZE; lfs_file_size(&lfs, &file) => SMALLSIZE;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -429,7 +448,7 @@ code = '''
# noop truncate # noop truncate
[cases.test_truncate_nop] [cases.test_truncate_nop]
defines.MEDIUMSIZE = [32, 2048] defines.MEDIUMSIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfs_format(&lfs, cfg) => 0; lfs_format(&lfs, cfg) => 0;
@@ -442,10 +461,11 @@ code = '''
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
// this truncate should do nothing // this truncate should do nothing
lfs_file_truncate(&lfs, &file, j+size) => 0; lfs_file_truncate(&lfs, &file, j+lfs_min(size, MEDIUMSIZE-j)) => 0;
} }
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -455,8 +475,9 @@ code = '''
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
memcmp(buffer, "hair", size) => 0; => lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs_file_read(&lfs, &file, buffer, size) => 0;
@@ -468,8 +489,9 @@ code = '''
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
memcmp(buffer, "hair", size) => 0; => lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
} }
lfs_file_read(&lfs, &file, buffer, size) => 0; lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;