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
|
// setup compaction
|
||||||
bool splitted = false;
|
bool splitted = false;
|
||||||
bool exhausted = false;
|
bool exhausted = false;
|
||||||
|
bool overcompacting = false;
|
||||||
|
|
||||||
struct lfs_commit commit;
|
struct lfs_commit commit;
|
||||||
commit.block = dir->pair[1];
|
commit.block = dir->pair[1];
|
||||||
@@ -1310,9 +1311,11 @@ commit:
|
|||||||
// cleanup delete, and we cap at half a block to give room
|
// cleanup delete, and we cap at half a block to give room
|
||||||
// for metadata updates
|
// for metadata updates
|
||||||
commit.begin = 0;
|
commit.begin = 0;
|
||||||
commit.end = lfs_min(
|
commit.end = lfs->cfg->block_size - 38;
|
||||||
lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size),
|
if (!overcompacting) {
|
||||||
lfs->cfg->block_size - 38);
|
commit.end = lfs_min(commit.end,
|
||||||
|
lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size));
|
||||||
|
}
|
||||||
|
|
||||||
if (!splitted) {
|
if (!splitted) {
|
||||||
// increment revision count
|
// increment revision count
|
||||||
@@ -1369,8 +1372,9 @@ commit:
|
|||||||
0x003ff000, LFS_MKTAG(0, id, 0),
|
0x003ff000, LFS_MKTAG(0, id, 0),
|
||||||
-LFS_MKTAG(0, begin, 0),
|
-LFS_MKTAG(0, begin, 0),
|
||||||
source, attrs);
|
source, attrs);
|
||||||
if (err && !(splitted && err == LFS_ERR_NOSPC)) {
|
if (err && !(splitted && !overcompacting &&
|
||||||
if (err == LFS_ERR_NOSPC) {
|
err == LFS_ERR_NOSPC)) {
|
||||||
|
if (!overcompacting && err == LFS_ERR_NOSPC) {
|
||||||
goto split;
|
goto split;
|
||||||
} else if (err == LFS_ERR_CORRUPT) {
|
} else if (err == LFS_ERR_CORRUPT) {
|
||||||
goto relocate;
|
goto relocate;
|
||||||
@@ -1457,6 +1461,11 @@ split:
|
|||||||
lfs_mdir_t tail;
|
lfs_mdir_t tail;
|
||||||
err = lfs_dir_alloc(lfs, &tail);
|
err = lfs_dir_alloc(lfs, &tail);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
if (err == LFS_ERR_NOSPC) {
|
||||||
|
// No space to expand? Try overcompacting
|
||||||
|
overcompacting = true;
|
||||||
|
goto commit;
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user