diff mbox series

[2/2] xfs_repair: synthesize incore inode tree records when required

Message ID 173197107039.920975.2579223976323116080.stgit@frogsfrogsfrogs (mailing list archive)
State New
Headers show
Series [1/2] xfs_repair: fix crasher in pf_queuing_worker | expand

Commit Message

Darrick J. Wong Nov. 18, 2024, 11:07 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

On a filesystem with 64k fsblock size, xfs/093 fails with the following:

Phase 3 - for each AG...
        - scan and clear agi unlinked lists...
found inodes not in the inode allocation tree
found inodes not in the inode allocation tree
        - process known inodes and perform inode discovery...
        - agno = 0
xfs_repair: dino_chunks.c:1166: process_aginodes: Assertion `num_inos == igeo->ialloc_inos' failed.
./common/xfs: line 392: 361225 Aborted                 (core dumped) $XFS_REPAIR_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV

In this situation, the inode size is 512b, which means that two inobt
records map to a single fs block.  However, the inobt walk didn't find
the second record, so it didn't create a second incore ino_tree_node_t
object.  The assertion trips, and we fail to repair the filesystem.

To fix this, synthesize incore inode records when we know that they must
exist.  Mark the inodes as in use so that they will not be purged from
parent directories or moved to lost+found if the directory tree is also
compromised.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 repair/dino_chunks.c |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

Comments

Christoph Hellwig Nov. 19, 2024, 6:09 a.m. UTC | #1
Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>
diff mbox series

Patch

diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c
index 1953613345190d..86e29dd9ae05eb 100644
--- a/repair/dino_chunks.c
+++ b/repair/dino_chunks.c
@@ -1050,6 +1050,8 @@  process_aginodes(
 	first_ino_rec = ino_rec = findfirst_inode_rec(agno);
 
 	while (ino_rec != NULL)  {
+		xfs_agino_t	synth_agino;
+
 		/*
 		 * paranoia - step through inode records until we step
 		 * through a full allocation of inodes.  this could
@@ -1068,6 +1070,32 @@  process_aginodes(
 				num_inos += XFS_INODES_PER_CHUNK;
 		}
 
+		/*
+		 * We didn't find all the inobt records for this block, so the
+		 * incore tree is missing a few records.  This implies that the
+		 * inobt is heavily damaged, so synthesize the incore records.
+		 * Mark all the inodes in use to minimize data loss.
+		 */
+		for (synth_agino = first_ino_rec->ino_startnum + num_inos;
+		     num_inos < igeo->ialloc_inos;
+		     synth_agino += XFS_INODES_PER_CHUNK,
+		     num_inos += XFS_INODES_PER_CHUNK) {
+			int		i;
+
+			ino_rec = find_inode_rec(mp, agno, synth_agino);
+			if (ino_rec)
+				continue;
+
+			ino_rec = set_inode_free_alloc(mp, agno, synth_agino);
+			do_warn(
+ _("found inobt record for inode %" PRIu64 " but not inode %" PRIu64 ", pretending that we did\n"),
+					XFS_AGINO_TO_INO(mp, agno,
+						first_ino_rec->ino_startnum),
+					XFS_AGINO_TO_INO(mp, agno,
+						synth_agino));
+			for (i = 0; i < XFS_INODES_PER_CHUNK; i++)
+				set_inode_used(ino_rec, i);
+		}
 		ASSERT(num_inos == igeo->ialloc_inos);
 
 		if (pf_args) {