Skip to content

Commit

Permalink
Fixed issue where deorphan could get stuck circling between two half-…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
geky committed Dec 17, 2022
1 parent d1b254d commit ba1c764
Showing 1 changed file with 7 additions and 4 deletions.
11 changes: 7 additions & 4 deletions lfs.c
Expand Up @@ -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)
Expand All @@ -4612,10 +4611,12 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
// 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)) {
Expand Down Expand Up @@ -4676,7 +4677,7 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {

// did our commit create more orphans?
if (state == LFS_OK_ORPHANED) {
goto restart;
moreorphans = true;
}

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

// did our commit create more orphans?
if (state == LFS_OK_ORPHANED) {
goto restart;
moreorphans = true;
}

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

pdir = dir;
}

pass = moreorphans ? 0 : pass+1;
}

// mark orphans as fixed
Expand Down

0 comments on commit ba1c764

Please sign in to comment.