From c663c55926f205723c3d56dd7030bacbe7960f8e Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 7 Jul 2020 17:14:30 -0700 Subject: [PATCH] Free space of overwritten files in LittleFS (#7434) * Free space of overwritten files in LittleFS Fixes #7426 LittleFS doesn't update the on-flash data structures when a file is reopened as O_TRUNC until the file is closed. This means the space of the original, inaccessible file cannot be used, causing OOS errors in cases when a large file is being overwritten. Explicitly call the file sync operation to update the on-flash metadata as soon as a file is opened. For normal files it's a no-op, but for O_TRUNC modes it will free the space, allowing full overwrite of large files. * Add host test case for change --- libraries/LittleFS/src/LittleFS.cpp | 1 + tests/host/fs/test_fs.inc | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/libraries/LittleFS/src/LittleFS.cpp b/libraries/LittleFS/src/LittleFS.cpp index b85075112e..7fd4351fcb 100644 --- a/libraries/LittleFS/src/LittleFS.cpp +++ b/libraries/LittleFS/src/LittleFS.cpp @@ -87,6 +87,7 @@ FileImplPtr LittleFSImpl::open(const char* path, OpenMode openMode, AccessMode a // a directory whose name we are carrying around but which cannot be read or written return std::make_shared(this, path, nullptr, flags, creation); } else if (rc == 0) { + lfs_file_sync(&_lfs, fd.get()); return std::make_shared(this, path, fd, flags, creation); } else { DEBUGV("LittleFSDirImpl::openFile: rc=%d fd=%p path=`%s` openMode=%d accessMode=%d err=%d\n", diff --git a/tests/host/fs/test_fs.inc b/tests/host/fs/test_fs.inc index 0a2cc423fc..683f3a99ba 100644 --- a/tests/host/fs/test_fs.inc +++ b/tests/host/fs/test_fs.inc @@ -198,6 +198,28 @@ TEST_CASE(TESTPRE "seek() pase EOF returns error (#7323)", TESTPAT) f.close(); } +TEST_CASE(TESTPRE "Rewriting file frees space immediately (#7426)", TESTPAT) +{ + FS_MOCK_DECLARE(64, 8, 512, ""); + REQUIRE(FSTYPE.begin()); + FSInfo inf; + FSTYPE.info(inf); + // Calculate the size to write per-FS, due to differing overheads + int kbToWrite = (inf.totalBytes - inf.usedBytes - 8192) / 1024; + // Create and overwrite a file >50% of spaceA (48/64K) + for (auto x = 0; x < 2; x++) { + auto f = FSTYPE.open("/file1.bin", "w"); + REQUIRE(f); + uint8_t buff[1024]; + memset(buff, 0xaa, 1024); + for (auto i = 0; i < kbToWrite; i++) { + REQUIRE(f.write(buff, 1024)); + } + f.close(); + FSTYPE.info(inf); + } +} + #ifdef FS_HAS_DIRS #if FSTYPE != SDFS