[PATCH 07/11] xfs_repair: only update in-core extent state after scanning full extent

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Darrick J. Wong <darrick.wong@xxxxxxxxxx>

In process_bmbt_reclist_int, only update the in-core extent state after
clearing the entire extent for conflicts.  If we encounter conflicts
we'll try rebuilding the fork from rmap data and rescanning the fork.
It is essential to avoid polluting the in-memory state with garbage
data so that we don't end up nuking other files needlessly.  Found by
fuzzing recs[1].blockcount = middlebit in xfs/380.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
 repair/dinode.c |   30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)


diff --git a/repair/dinode.c b/repair/dinode.c
index ceffc52..c8c1850 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -751,7 +751,6 @@ _("%s fork in ino %" PRIu64 " claims free block %" PRIu64 "\n"),
 				/* fall through ... */
 			case XR_E_INUSE1:	/* seen by rmap */
 			case XR_E_UNKNOWN:
-				set_bmap_ext(agno, agbno, blen, XR_E_INUSE);
 				break;
 
 			case XR_E_BAD_STATE:
@@ -773,7 +772,6 @@ _("%s fork in inode %" PRIu64 " claims metadata block %" PRIu64 "\n"),
 
 			case XR_E_INUSE:
 			case XR_E_MULT:
-				set_bmap_ext(agno, agbno, blen, XR_E_MULT);
 				if (type == XR_INO_DATA &&
 				    xfs_sb_version_hasreflink(&mp->m_sb))
 					break;
@@ -792,6 +790,34 @@ _("%s fork in %s inode %" PRIu64 " claims CoW block %" PRIu64 "\n"),
 				do_error(
 _("illegal state %d in block map %" PRIu64 "\n"),
 					state, b);
+				goto done;
+			}
+		}
+
+		/*
+		 * Update the internal extent map only after we've checked
+		 * every block in this extent.  The first time we reject this
+		 * data fork we'll try to rebuild the bmbt from rmap data.
+		 * After a successful rebuild we'll try this scan again.
+		 * (If the rebuild fails we won't come back here.)
+		 */
+		agbno = XFS_FSB_TO_AGBNO(mp, irec.br_startblock);
+		ebno = agbno + irec.br_blockcount;
+		for (; agbno < ebno; agbno += blen) {
+			state = get_bmap_ext(agno, agbno, ebno, &blen);
+			switch (state)  {
+			case XR_E_FREE:
+			case XR_E_FREE1:
+			case XR_E_INUSE1:
+			case XR_E_UNKNOWN:
+				set_bmap_ext(agno, agbno, blen, XR_E_INUSE);
+				break;
+			case XR_E_INUSE:
+			case XR_E_MULT:
+				set_bmap_ext(agno, agbno, blen, XR_E_MULT);
+				break;
+			default:
+				break;
 			}
 		}
 		if (collect_rmaps) { /* && !check_dups */

--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux