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.
This commit is contained in:
@@ -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 @@ commit:
|
||||
// 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 @@ commit:
|
||||
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 @@ split:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user