[PATCH 16/17] xfs_scrub: ignore freed inodes when single-stepping during phase 3

Darrick J. Wong
2025-02-06T22:34:51Z

For inodes that inumbers told us were allocated but weren't loaded by
the bulkstat call, we fall back to loading bulkstat data one inode at a
time to try to find the inodes that are too corrupt to load.

However, there are a couple of outcomes of the single bulkstat call that
clearly indicate that the inode is free, not corrupt. In this case, the
phase 3 inode scan will try to scrub the inode, only to be told ENOENT
because it doesn't exist.

As an optimization here, don't increment ocount, just move on to the
next inode in the mask.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/inodes.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/scrub/inodes.c b/scrub/inodes.c
index 84696a5bcda7d1..24a1dcab94c22d 100644
--- a/scrub/inodes.c
+++ b/scrub/inodes.c
@@ -160,10 +160,34 @@ bulkstat_single_step(
*/
error = -xfrog_bulkstat_single(&ctx->mnt,
inumbers->xi_startino + i, breq->hdr.flags, bs);
- if (error || bs->bs_ino != inumbers->xi_startino + i) {
+ switch (error) {
+ case ENOENT:
+ /*
+ * This inode wasn't found, and no results were
+ * returned. We've likely hit the end of the
+ * filesystem, but we'll move on to the next inode in
+ * the mask for the sake of caution.
+ */
+ continue;
+ case 0:
+ /*
+ * If a result was returned but it wasn't the inode
+ * we were looking for, then the missing inode was
+ * freed. Move on to the next inode in the mask.
+ */
+ if (bs->bs_ino != inumbers->xi_startino + i)
+ continue;
+ break;
+ default:
+ /*
+ * Some error happened. Synthesize a bulkstat record
+ * so that phase3 can try to see if there's a corrupt
+ * inode that needs repairing.
+ */
memset(bs, 0, sizeof(struct xfs_bulkstat));
bs->bs_ino = inumbers->xi_startino + i;
bs->bs_blksize = ctx->mnt_sv.f_frsize;
+ break;
}

breq->hdr.ocount++;