From ba1c76435a479658b30da14a9cd82efa1ceecf0c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sat, 10 Dec 2022 22:38:20 -0600 Subject: [PATCH] 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. --- lfs.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lfs.c b/lfs.c index 12864c79..7a4b41a8 100644 --- a/lfs.c +++ b/lfs.c @@ -4603,7 +4603,6 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) { int8_t found = 0; -restart: // Check for orphans in two separate passes: // - 1 for half-orphans (relocations) // - 2 for full-orphans (removes/renames) @@ -4612,10 +4611,12 @@ restart: // references to full-orphans, effectively hiding them from the deorphan // search. // - for (int pass = 0; pass < 2; pass++) { + int pass = 0; + while (pass < 2) { // Fix any orphans lfs_mdir_t pdir = {.split = true, .tail = {0, 1}}; lfs_mdir_t dir; + bool moreorphans = false; // iterate over all directory directory entries while (!lfs_pair_isnull(pdir.tail)) { @@ -4676,7 +4677,7 @@ restart: // did our commit create more orphans? if (state == LFS_OK_ORPHANED) { - goto restart; + moreorphans = true; } // refetch tail @@ -4712,7 +4713,7 @@ restart: // did our commit create more orphans? if (state == LFS_OK_ORPHANED) { - goto restart; + moreorphans = true; } // refetch tail @@ -4722,6 +4723,8 @@ restart: pdir = dir; } + + pass = moreorphans ? 0 : pass+1; } // mark orphans as fixed