diff mbox series

[1/3] xfs_scrub: detect infinite loops when scanning inodes

Message ID 161017368431.1141483.1015560955108076159.stgit@magnolia (mailing list archive)
State Superseded, archived
Headers show
Series xfs: add the ability to flag a fs for repair | expand

Commit Message

Darrick J. Wong Jan. 9, 2021, 6:28 a.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

During an inode scan (aka phase 3) when we're scanning the inode btree
to find files to check, make sure that each invocation of inumbers
actually gives us an inobt record with a startino that's at least as
large as what we asked for so that we always make forward progress.

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

Comments

Darrick J. Wong Jan. 9, 2021, 7 a.m. UTC | #1
On Fri, Jan 08, 2021 at 10:28:04PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> During an inode scan (aka phase 3) when we're scanning the inode btree
> to find files to check, make sure that each invocation of inumbers
> actually gives us an inobt record with a startino that's at least as
> large as what we asked for so that we always make forward progress.

Heh, this should have gone in the random fixes series.  Sigh...

--D

> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> ---
>  scrub/inodes.c |   16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> 
> diff --git a/scrub/inodes.c b/scrub/inodes.c
> index bdc12df3..4550db83 100644
> --- a/scrub/inodes.c
> +++ b/scrub/inodes.c
> @@ -119,6 +119,7 @@ scan_ag_inodes(
>  	struct scrub_ctx	*ctx = (struct scrub_ctx *)wq->wq_ctx;
>  	struct xfs_bulkstat	*bs;
>  	struct xfs_inumbers	*inumbers;
> +	uint64_t		nextino = cvt_agino_to_ino(&ctx->mnt, agno, 0);
>  	int			i;
>  	int			error;
>  	int			stale_count = 0;
> @@ -153,6 +154,21 @@ scan_ag_inodes(
>  	/* Find the inode chunk & alloc mask */
>  	error = -xfrog_inumbers(&ctx->mnt, ireq);
>  	while (!error && !si->aborted && ireq->hdr.ocount > 0) {
> +		/*
> +		 * Make sure that we always make forward progress while we
> +		 * scan the inode btree.
> +		 */
> +		if (nextino > inumbers->xi_startino) {
> +			str_corrupt(ctx, descr,
> +	_("AG %u inode btree is corrupt near agino %lu, got %lu"), agno,
> +				cvt_ino_to_agino(&ctx->mnt, nextino),
> +				cvt_ino_to_agino(&ctx->mnt,
> +						ireq->inumbers[0].xi_startino));
> +			si->aborted = true;
> +			break;
> +		}
> +		nextino = ireq->hdr.ino;
> +
>  		/*
>  		 * We can have totally empty inode chunks on filesystems where
>  		 * there are more than 64 inodes per block.  Skip these.
>
diff mbox series

Patch

diff --git a/scrub/inodes.c b/scrub/inodes.c
index bdc12df3..4550db83 100644
--- a/scrub/inodes.c
+++ b/scrub/inodes.c
@@ -119,6 +119,7 @@  scan_ag_inodes(
 	struct scrub_ctx	*ctx = (struct scrub_ctx *)wq->wq_ctx;
 	struct xfs_bulkstat	*bs;
 	struct xfs_inumbers	*inumbers;
+	uint64_t		nextino = cvt_agino_to_ino(&ctx->mnt, agno, 0);
 	int			i;
 	int			error;
 	int			stale_count = 0;
@@ -153,6 +154,21 @@  scan_ag_inodes(
 	/* Find the inode chunk & alloc mask */
 	error = -xfrog_inumbers(&ctx->mnt, ireq);
 	while (!error && !si->aborted && ireq->hdr.ocount > 0) {
+		/*
+		 * Make sure that we always make forward progress while we
+		 * scan the inode btree.
+		 */
+		if (nextino > inumbers->xi_startino) {
+			str_corrupt(ctx, descr,
+	_("AG %u inode btree is corrupt near agino %lu, got %lu"), agno,
+				cvt_ino_to_agino(&ctx->mnt, nextino),
+				cvt_ino_to_agino(&ctx->mnt,
+						ireq->inumbers[0].xi_startino));
+			si->aborted = true;
+			break;
+		}
+		nextino = ireq->hdr.ino;
+
 		/*
 		 * We can have totally empty inode chunks on filesystems where
 		 * there are more than 64 inodes per block.  Skip these.