diff mbox series

[10/17] xfs_scrub: don't double-scan inodes during phase 3

Message ID 173888086213.2738568.8939791256440476361.stgit@frogsfrogsfrogs (mailing list archive)
State Not Applicable, archived
Headers show
Series [01/17] libxfs: unmap xmbuf pages to avoid disaster | expand

Commit Message

Darrick J. Wong Feb. 6, 2025, 10:33 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

The bulkstat ioctl only allows us to specify the starting inode number
and the length of the bulkstat array.  It is possible that a bulkstat
request for {startino = 30, icount = 10} will return stat data for inode
50.  For most bulkstat users this is ok because they're marching
linearly across all inodes in the filesystem.

Unfortunately for scrub phase 3 this is undesirable because we only want
the inodes that belong to a specific inobt record because we need to
know about inodes that are marked as allocated but are too corrupt to
appear in the bulkstat output.  Another worker will process the inobt
record(s) that corresponds to the extra inodes, which means we can
double-scan some inodes.

Therefore, bulkstat_for_inumbers should trim out inodes that don't
correspond to the inumbers record that it is given.

Cc: <linux-xfs@vger.kernel.org> # v5.3.0
Fixes: e3724c8b82a320 ("xfs_scrub: refactor xfs_iterate_inodes_range_check")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
 scrub/inodes.c |   28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

Comments

Christoph Hellwig Feb. 7, 2025, 4:41 a.m. UTC | #1
Looks good:

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

Patch

diff --git a/scrub/inodes.c b/scrub/inodes.c
index 4d8b137a698004..a7ea24615e9255 100644
--- a/scrub/inodes.c
+++ b/scrub/inodes.c
@@ -50,15 +50,17 @@ 
  */
 static void
 bulkstat_for_inumbers(
-	struct scrub_ctx	*ctx,
-	struct descr		*dsc,
-	const struct xfs_inumbers *inumbers,
-	struct xfs_bulkstat_req	*breq)
+	struct scrub_ctx		*ctx,
+	struct descr			*dsc,
+	const struct xfs_inumbers	*inumbers,
+	struct xfs_bulkstat_req		*breq)
 {
-	struct xfs_bulkstat	*bstat = breq->bulkstat;
-	struct xfs_bulkstat	*bs;
-	int			i;
-	int			error;
+	struct xfs_bulkstat		*bstat = breq->bulkstat;
+	struct xfs_bulkstat		*bs;
+	const uint64_t			limit_ino =
+		inumbers->xi_startino + LIBFROG_BULKSTAT_CHUNKSIZE;
+	int				i;
+	int				error;
 
 	assert(inumbers->xi_allocmask != 0);
 
@@ -73,6 +75,16 @@  bulkstat_for_inumbers(
 			 strerror_r(error, errbuf, DESCR_BUFSZ));
 	}
 
+	/*
+	 * Bulkstat might return inodes beyond xi_startino + CHUNKSIZE.  Reduce
+	 * ocount to ignore inodes not described by the inumbers record.
+	 */
+	for (i = breq->hdr.ocount - 1; i >= 0; i--) {
+		if (breq->bulkstat[i].bs_ino < limit_ino)
+			break;
+		breq->hdr.ocount--;
+	}
+
 	/*
 	 * Check each of the stats we got back to make sure we got the inodes
 	 * we asked for.