mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-01 12:20:02 +00:00
Fixed issue where deorphan could get stuck circling between two half-orphans
This of course should never happen normally, two half-orphans requires two parents, which is disallowed in littlefs for this reason. But it can happen if there is an outdated half-orphan later in the metadata linked-list. The two half-orphans can cause the deorphan step to get stuck, constantly "fixing" the first half-orphan before it has a chance to remove the problematic, outdated half-orphan later in the list. The solution here is to do a full check for half-orphans before restarting the half-orphan loop. This strategy has the potential to visit more metadata blocks unnecessarily, but avoids situations where removing a later half-orphan will eventually cause an earlier half-orphan to resolve itself. Found with heuristic powerloss testing with test_relocations_reentrant_renames after 192 nested powerlosses.
This commit is contained in:
11
lfs.c
11
lfs.c
@ -4603,7 +4603,6 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
|
|||||||
|
|
||||||
int8_t found = 0;
|
int8_t found = 0;
|
||||||
|
|
||||||
restart:
|
|
||||||
// Check for orphans in two separate passes:
|
// Check for orphans in two separate passes:
|
||||||
// - 1 for half-orphans (relocations)
|
// - 1 for half-orphans (relocations)
|
||||||
// - 2 for full-orphans (removes/renames)
|
// - 2 for full-orphans (removes/renames)
|
||||||
@ -4612,10 +4611,12 @@ restart:
|
|||||||
// references to full-orphans, effectively hiding them from the deorphan
|
// references to full-orphans, effectively hiding them from the deorphan
|
||||||
// search.
|
// search.
|
||||||
//
|
//
|
||||||
for (int pass = 0; pass < 2; pass++) {
|
int pass = 0;
|
||||||
|
while (pass < 2) {
|
||||||
// Fix any orphans
|
// Fix any orphans
|
||||||
lfs_mdir_t pdir = {.split = true, .tail = {0, 1}};
|
lfs_mdir_t pdir = {.split = true, .tail = {0, 1}};
|
||||||
lfs_mdir_t dir;
|
lfs_mdir_t dir;
|
||||||
|
bool moreorphans = false;
|
||||||
|
|
||||||
// iterate over all directory directory entries
|
// iterate over all directory directory entries
|
||||||
while (!lfs_pair_isnull(pdir.tail)) {
|
while (!lfs_pair_isnull(pdir.tail)) {
|
||||||
@ -4676,7 +4677,7 @@ restart:
|
|||||||
|
|
||||||
// did our commit create more orphans?
|
// did our commit create more orphans?
|
||||||
if (state == LFS_OK_ORPHANED) {
|
if (state == LFS_OK_ORPHANED) {
|
||||||
goto restart;
|
moreorphans = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// refetch tail
|
// refetch tail
|
||||||
@ -4712,7 +4713,7 @@ restart:
|
|||||||
|
|
||||||
// did our commit create more orphans?
|
// did our commit create more orphans?
|
||||||
if (state == LFS_OK_ORPHANED) {
|
if (state == LFS_OK_ORPHANED) {
|
||||||
goto restart;
|
moreorphans = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// refetch tail
|
// refetch tail
|
||||||
@ -4722,6 +4723,8 @@ restart:
|
|||||||
|
|
||||||
pdir = dir;
|
pdir = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pass = moreorphans ? 0 : pass+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark orphans as fixed
|
// mark orphans as fixed
|
||||||
|
|||||||
Reference in New Issue
Block a user