From 20dbdd616162b0a8503437f0f8ebda4f786a9714 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 24 Feb 2025 10:21:44 -0800 Subject: [PATCH] xfs_scrub: ignore freed inodes when single-stepping during phase 3 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" Reviewed-by: Christoph Hellwig --- scrub/inodes.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/scrub/inodes.c b/scrub/inodes.c index 84696a5bc..24a1dcab9 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++; -- 2.39.5