Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
  • Loading branch information
geky committed Dec 17, 2022
commit ba1c76435a479658b30da14a9cd82efa1ceecf0c
11 changes: 7 additions & 4 deletions lfs.c
Original file line number Diff line number Diff line change
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