From 2a7f0ed11bd5e991977263a90ae714d2a62abced Mon Sep 17 00:00:00 2001 From: "Deomid \"rojer\" Ryabkov" Date: Tue, 14 May 2019 18:18:29 +0100 Subject: [PATCH 1/5] Fix compilation with -Wundef --- lfs_util.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lfs_util.h b/lfs_util.h index 28b1400..5a34eb3 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -143,14 +143,14 @@ static inline int lfs_scmp(uint32_t a, uint32_t b) { // Convert between 32-bit little-endian and native order static inline uint32_t lfs_fromle32(uint32_t a) { #if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) return a; #elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return __builtin_bswap32(a); #else return (((uint8_t*)&a)[0] << 0) | @@ -167,14 +167,14 @@ static inline uint32_t lfs_tole32(uint32_t a) { // Convert between 32-bit big-endian and native order static inline uint32_t lfs_frombe32(uint32_t a) { #if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) return __builtin_bswap32(a); #elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return a; #else return (((uint8_t*)&a)[0] << 24) | From 2533a0f6d6317cbd5819681289cf5cd8500af78d Mon Sep 17 00:00:00 2001 From: "Deomid \"rojer\" Ryabkov" Date: Thu, 16 May 2019 17:51:22 +0100 Subject: [PATCH 2/5] Make lfs1_crc static so it doesn't conflict with prefixed LFS1 code When LFS1 code is present and LFS_MIGRATE is enabled --- lfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lfs.c b/lfs.c index f042408..7692d09 100644 --- a/lfs.c +++ b/lfs.c @@ -3900,7 +3900,7 @@ typedef struct lfs1_superblock { /// Low-level wrappers v1->v2 /// -void lfs1_crc(uint32_t *crc, const void *buffer, size_t size) { +static void lfs1_crc(uint32_t *crc, const void *buffer, size_t size) { *crc = lfs_crc(*crc, buffer, size); } From 9899c7fe486d4a581fb84ecf832a574896d411b7 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 21 May 2019 17:21:52 -0500 Subject: [PATCH 3/5] Fixed read cache amount based on hint and offset Found by apmorton --- lfs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lfs.c b/lfs.c index 7692d09..b0e6819 100644 --- a/lfs.c +++ b/lfs.c @@ -84,9 +84,12 @@ static int lfs_bd_read(lfs_t *lfs, LFS_ASSERT(block < lfs->cfg->block_count); rcache->block = block; rcache->off = lfs_aligndown(off, lfs->cfg->read_size); - rcache->size = lfs_min(lfs_alignup(off+hint, lfs->cfg->read_size), - lfs_min(lfs->cfg->block_size - rcache->off, - lfs->cfg->cache_size)); + rcache->size = lfs_min( + lfs_min( + lfs_alignup(off+hint, lfs->cfg->read_size), + lfs->cfg->block_size) + - rcache->off, + lfs->cfg->cache_size); int err = lfs->cfg->read(lfs->cfg, rcache->block, rcache->off, rcache->buffer, rcache->size); if (err) { From 12e464e9c37dd865e432716856bf2a30fd948297 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 22 May 2019 14:24:05 -0500 Subject: [PATCH 4/5] Fixed issue with writes following a truncate The problem was not setting the file state correctly after the truncate. To truncate < size, we end up using the cache to traverse the ctz skip-list far away from where our file->pos is. We can leave the last block in the cache in case we're going to append to the file, but if we do this we need to set up file->block+file->off to tell use where we are in the file, and set the LFS_F_READING flag to indicate that our cache contains read data. Note this is different than the LFS_F_DIRTY, which we need also. The purpose of the flags are as follows: - LFS_F_DIRTY - file ctz skip-list branch is out of sync with filesystem, need to update metadata - LFS_F_READING - file cache is in use for reading, need to drop cache - LFS_F_WRITING - file cache is in use for writing, need to write out cache to disk The difference between flags is subtle but important because read/prog caches are handled differently. Prog caches have asserts in place to catch programs without erases (the infamous pcache->block == 0xffffffff assert). Though maybe the names deserve an update... Found by ebinans --- lfs.c | 5 +- tests/test_truncate.sh | 144 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/lfs.c b/lfs.c index b0e6819..71dad3a 100644 --- a/lfs.c +++ b/lfs.c @@ -2867,13 +2867,14 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { // lookup new head in ctz skip list err = lfs_ctz_find(lfs, NULL, &file->cache, file->ctz.head, file->ctz.size, - size, &file->ctz.head, &(lfs_off_t){0}); + size, &file->block, &file->off); if (err) { return err; } + file->ctz.head = file->block; file->ctz.size = size; - file->flags |= LFS_F_DIRTY; + file->flags |= LFS_F_DIRTY | LFS_F_READING; } else if (size > oldsize) { lfs_off_t pos = file->pos; diff --git a/tests/test_truncate.sh b/tests/test_truncate.sh index 053b2e0..c12fc0d 100755 --- a/tests/test_truncate.sh +++ b/tests/test_truncate.sh @@ -11,6 +11,150 @@ tests/test.py << TEST lfs_format(&lfs, &cfg) => 0; TEST +echo "--- Simple truncate ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldynoop", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + + strcpy((char*)buffer, "hair"); + size = strlen((char*)buffer); + for (lfs_off_t j = 0; j < $LARGESIZE; j += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_size(&lfs, &file[0]) => $LARGESIZE; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldynoop", LFS_O_RDWR) => 0; + lfs_file_size(&lfs, &file[0]) => $LARGESIZE; + + lfs_file_truncate(&lfs, &file[0], $MEDIUMSIZE) => 0; + lfs_file_size(&lfs, &file[0]) => $MEDIUMSIZE; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldynoop", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file[0]) => $MEDIUMSIZE; + + size = strlen("hair"); + for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "hair", size) => 0; + } + lfs_file_read(&lfs, &file[0], buffer, size) => 0; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Truncate and read ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldyread", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + + strcpy((char*)buffer, "hair"); + size = strlen((char*)buffer); + for (lfs_off_t j = 0; j < $LARGESIZE; j += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_size(&lfs, &file[0]) => $LARGESIZE; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldyread", LFS_O_RDWR) => 0; + lfs_file_size(&lfs, &file[0]) => $LARGESIZE; + + lfs_file_truncate(&lfs, &file[0], $MEDIUMSIZE) => 0; + lfs_file_size(&lfs, &file[0]) => $MEDIUMSIZE; + + size = strlen("hair"); + for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "hair", size) => 0; + } + lfs_file_read(&lfs, &file[0], buffer, size) => 0; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldyread", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file[0]) => $MEDIUMSIZE; + + size = strlen("hair"); + for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "hair", size) => 0; + } + lfs_file_read(&lfs, &file[0], buffer, size) => 0; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + +echo "--- Truncate and write ---" +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldywrite", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + + strcpy((char*)buffer, "hair"); + size = strlen((char*)buffer); + for (lfs_off_t j = 0; j < $LARGESIZE; j += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_size(&lfs, &file[0]) => $LARGESIZE; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldywrite", LFS_O_RDWR) => 0; + lfs_file_size(&lfs, &file[0]) => $LARGESIZE; + + lfs_file_truncate(&lfs, &file[0], $MEDIUMSIZE) => 0; + lfs_file_size(&lfs, &file[0]) => $MEDIUMSIZE; + + strcpy((char*)buffer, "bald"); + size = strlen((char*)buffer); + for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { + lfs_file_write(&lfs, &file[0], buffer, size) => size; + } + lfs_file_size(&lfs, &file[0]) => $MEDIUMSIZE; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file[0], "baldywrite", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file[0]) => $MEDIUMSIZE; + + size = strlen("bald"); + for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { + lfs_file_read(&lfs, &file[0], buffer, size) => size; + memcmp(buffer, "bald", size) => 0; + } + lfs_file_read(&lfs, &file[0], buffer, size) => 0; + + lfs_file_close(&lfs, &file[0]) => 0; + lfs_unmount(&lfs) => 0; +TEST + +# More aggressive general truncation tests truncate_test() { STARTSIZES="$1" STARTSEEKS="$2" From ef77195a640db9fa0dda16fc982373b9427fae1a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 22 May 2019 16:18:41 -0500 Subject: [PATCH 5/5] Fixed limit of inline files based on LFS_ATTR_MAX The maximum limit of inline files and attributes are unrelated, but were not at a point in littlefs v2 development. This should be checking against the bit-field limit in the littlefs tag. Found by lsilvaalmeida --- lfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lfs.c b/lfs.c index 71dad3a..a12fdcf 100644 --- a/lfs.c +++ b/lfs.c @@ -2737,7 +2737,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, if ((file->flags & LFS_F_INLINE) && lfs_max(file->pos+nsize, file->ctz.size) > - lfs_min(LFS_ATTR_MAX, lfs_min( + lfs_min(0x3fe, lfs_min( lfs->cfg->cache_size, lfs->cfg->block_size/8))) { // inline file doesn't fit anymore file->off = file->pos;