From cafe6ab46603244522916c7580385bfd04a3cff4 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sat, 15 Sep 2018 02:28:45 -0500 Subject: [PATCH] Fixed issue with splitting metadata-pairs in full filesystem Depending on your perspective, this may not be a necessary operation, given that a nearly-full filesystem is already prone to ENOSPC errors, especially a COW filesystem. However, splitting metadata-pairs can happen in really unfortunate situations, such as removing files. The solution here is to allow "overcompaction", that is, a compaction without bounds checking to allow splitting. This unfortunately pushes our metadata-pairs past their reasonable limit of saturation, which means writes get exponentially costly. However it does allow littlefs to continue working in extreme situations. --- lfs.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lfs.c b/lfs.c index 860794649d8..f7cb7972a9f 100644 --- a/lfs.c +++ b/lfs.c @@ -1290,6 +1290,7 @@ static int lfs_dir_compact(lfs_t *lfs, // setup compaction bool splitted = false; bool exhausted = false; + bool overcompacting = false; struct lfs_commit commit; commit.block = dir->pair[1]; @@ -1310,9 +1311,11 @@ static int lfs_dir_compact(lfs_t *lfs, // cleanup delete, and we cap at half a block to give room // for metadata updates commit.begin = 0; - commit.end = lfs_min( - lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size), - lfs->cfg->block_size - 38); + commit.end = lfs->cfg->block_size - 38; + if (!overcompacting) { + commit.end = lfs_min(commit.end, + lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size)); + } if (!splitted) { // increment revision count @@ -1369,8 +1372,9 @@ static int lfs_dir_compact(lfs_t *lfs, 0x003ff000, LFS_MKTAG(0, id, 0), -LFS_MKTAG(0, begin, 0), source, attrs); - if (err && !(splitted && err == LFS_ERR_NOSPC)) { - if (err == LFS_ERR_NOSPC) { + if (err && !(splitted && !overcompacting && + err == LFS_ERR_NOSPC)) { + if (!overcompacting && err == LFS_ERR_NOSPC) { goto split; } else if (err == LFS_ERR_CORRUPT) { goto relocate; @@ -1457,6 +1461,11 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t tail; err = lfs_dir_alloc(lfs, &tail); if (err) { + if (err == LFS_ERR_NOSPC) { + // No space to expand? Try overcompacting + overcompacting = true; + goto commit; + } return err; }