Skip to content

Commit db2abfb

Browse files
committed
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.
1 parent 98e841a commit db2abfb

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

lfs.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4603,7 +4603,6 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
46034603

46044604
int8_t found = 0;
46054605

4606-
restart:
46074606
// Check for orphans in two separate passes:
46084607
// - 1 for half-orphans (relocations)
46094608
// - 2 for full-orphans (removes/renames)
@@ -4612,10 +4611,12 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
46124611
// references to full-orphans, effectively hiding them from the deorphan
46134612
// search.
46144613
//
4615-
for (int pass = 0; pass < 2; pass++) {
4614+
int pass = 0;
4615+
while (pass < 2) {
46164616
// Fix any orphans
46174617
lfs_mdir_t pdir = {.split = true, .tail = {0, 1}};
46184618
lfs_mdir_t dir;
4619+
bool moreorphans = false;
46194620

46204621
// iterate over all directory directory entries
46214622
while (!lfs_pair_isnull(pdir.tail)) {
@@ -4676,7 +4677,7 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
46764677

46774678
// did our commit create more orphans?
46784679
if (state == LFS_OK_ORPHANED) {
4679-
goto restart;
4680+
moreorphans = true;
46804681
}
46814682

46824683
// refetch tail
@@ -4712,7 +4713,7 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
47124713

47134714
// did our commit create more orphans?
47144715
if (state == LFS_OK_ORPHANED) {
4715-
goto restart;
4716+
moreorphans = true;
47164717
}
47174718

47184719
// refetch tail
@@ -4722,6 +4723,8 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
47224723

47234724
pdir = dir;
47244725
}
4726+
4727+
pass = moreorphans ? 0 : pass+1;
47254728
}
47264729

47274730
// mark orphans as fixed

0 commit comments

Comments
 (0)