]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: phase6: scan longform entries before header check
authorBill O'Donnell <bodonnel@redhat.com>
Tue, 15 Apr 2025 18:48:49 +0000 (13:48 -0500)
committerAndrey Albershteyn <aalbersh@kernel.org>
Mon, 28 Apr 2025 11:02:20 +0000 (13:02 +0200)
In longform_dir2_entry_check, if check_dir3_header() fails for v5
metadata, we immediately go to out_fix: and try to rebuild the
directory via longform_dir2_rebuild. But because we haven't yet
called longform_dir2_entry_check_data, the *hashtab used to rebuild
the directory is empty, which results in all existing entries
getting moved to lost+found, and an empty rebuilt directory. On top
of that, the empty directory is now short form, so its nlinks come
out wrong and this requires another repair run to fix.

Scan the entries before checking the header, so that we have a
decent chance of properly rebuilding the dir if the header is
corrupt, rather than orphaning all the entries and moving them to
lost+found.

Suggested-by: Eric Sandeen <sandeen@sandeen.net>
Signed-off-by: Bill O'Donnell <bodonnel@redhat.com>
[aalbersh updated changelog as suggested by Eric Sandeen]
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
repair/phase6.c

index 8804278a1fd027f32b764d5ccf52e5915f81fccd..a67cc0abd21ec07e1fe07787dc24e0dde4e0823b 100644 (file)
@@ -2431,6 +2431,11 @@ longform_dir2_entry_check(
                        continue;
                }
 
+               /* salvage any dirents that look ok */
+               longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot,
+                               irec, ino_offset, bp, hashtab,
+                               &freetab, da_bno, fmt == XFS_DIR2_FMT_BLOCK);
+
                /* check v5 metadata */
                if (xfs_has_crc(mp)) {
                        error = check_dir3_header(mp, bp, ino);
@@ -2445,9 +2450,6 @@ longform_dir2_entry_check(
                        }
                }
 
-               longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot,
-                               irec, ino_offset, bp, hashtab,
-                               &freetab, da_bno, fmt == XFS_DIR2_FMT_BLOCK);
                if (fmt == XFS_DIR2_FMT_BLOCK)
                        break;