All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] xfs: inode scrubber fixes
@ 2019-01-08 20:32 Darrick J. Wong
  2019-01-08 20:32 ` [PATCH 1/7] xfs: never try to scrub more than 64 inodes per inobt record Darrick J. Wong
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:32 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster

Hi all,

This is a resend of the inode scrubber fix series from late last year.
Most of it's been reviewed (patches 1, 3, 4, 5) but there have been
some review comments about unclear code in three of the patches, so I'm
resending the whole series, looking for review of patches 2, 6, and 7.

Patch 1 corrects a condition where we needed to clamp the number of
inodes checked for a given inobt record to the inode chunk size.

Patches 2-3 move the inobt record alignment checks to a separate
function and enhance the function to check that when we have more than
one inobt record per cluster we actually check that *all* of the
necessary records are present and in the correct order.  This patch
includes fixes for the finobt alignment false positives recently
reported by Chandan.

Patches 4-6 reorganize the inobt free data checks to deal with the
"multiple inobt records per icluster" situation.  In restructuring the
code to do so, we also rename variables and functions to be less
confusing about what they're there for.  We also fix the 'is the inode
free?' check to calculate dinode buffer offsets correctly in the
"multiple inobt records per icluster" situation.

Patch 7 consolidates the on-disk inode pointer calculation logic into
xchk_iallocbt_check_cluster.

If you're going to start using this mess, you probably ought to just
pull from my git trees.  The kernel patches[1] should apply against
5.0-rc1.

Comments and questions are, as always, welcome.

--D

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/7] xfs: never try to scrub more than 64 inodes per inobt record
  2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
@ 2019-01-08 20:32 ` Darrick J. Wong
  2019-01-08 20:32 ` [PATCH 2/7] xfs: check the ir_startino alignment directly Darrick J. Wong
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:32 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster

From: Darrick J. Wong <darrick.wong@oracle.com>

Make sure we never check more than XFS_INODES_PER_CHUNK inodes for any
given inobt record since there can be more than one inobt record mapped
to an inode cluster.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/scrub/ialloc.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)


diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 882dc56c5c21..fd431682db0b 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -203,7 +203,8 @@ xchk_iallocbt_check_freemask(
 	int				error = 0;
 
 	/* Make sure the freemask matches the inode records. */
-	nr_inodes = mp->m_inodes_per_cluster;
+	nr_inodes = min_t(unsigned int, XFS_INODES_PER_CHUNK,
+			mp->m_inodes_per_cluster);
 
 	for (agino = irec->ir_startino;
 	     agino < irec->ir_startino + XFS_INODES_PER_CHUNK;

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/7] xfs: check the ir_startino alignment directly
  2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
  2019-01-08 20:32 ` [PATCH 1/7] xfs: never try to scrub more than 64 inodes per inobt record Darrick J. Wong
@ 2019-01-08 20:32 ` Darrick J. Wong
  2019-01-09 13:32   ` Brian Foster
  2019-01-08 20:32 ` [PATCH 3/7] xfs: check inobt record alignment on big block filesystems Darrick J. Wong
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:32 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster

From: Darrick J. Wong <darrick.wong@oracle.com>

In xchk_iallocbt_rec, check the alignment of ir_startino by converting
the inode cluster block alignment into units of inodes instead of the
other way around (converting ir_startino to blocks).  This prevents us
from tripping over off-by-one errors in ir_startino which are obscured
by the inode -> block conversion.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/scrub/ialloc.c |   56 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 6 deletions(-)


diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index fd431682db0b..1c6fef9b3799 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -265,6 +265,53 @@ xchk_iallocbt_check_freemask(
 	return error;
 }
 
+/*
+ * Make sure this inode btree record is aligned properly.  Because a fs block
+ * contains multiple inodes, we check that the inobt record is aligned to the
+ * correct inode, not just the correct block on disk.  This results in a finer
+ * grained corruption check.
+ */
+STATIC void
+xchk_iallocbt_rec_alignment(
+	struct xchk_btree		*bs,
+	struct xfs_inobt_rec_incore	*irec)
+{
+	struct xfs_mount		*mp = bs->sc->mp;
+
+	/*
+	 * finobt records have different positioning requirements than inobt
+	 * records: each finobt record must have a corresponding inobt record.
+	 * That is checked in the xref function, so for now we only catch the
+	 * obvious case where the record isn't at all aligned properly.
+	 *
+	 * Note that if a fs block contains more than a single chunk of inodes,
+	 * we will have finobt records only for those chunks containing free
+	 * inodes, and therefore expect chunk alignment of finobt records.
+	 * Otherwise, we expect that the finobt record is aligned to the
+	 * cluster alignment as told by the superblock.
+	 */
+	if (bs->cur->bc_btnum == XFS_BTNUM_FINO) {
+		unsigned int	imask;
+
+		imask = min_t(unsigned int, XFS_INODES_PER_CHUNK,
+				mp->m_cluster_align_inodes) - 1;
+		if (irec->ir_startino & imask)
+			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+		return;
+	}
+
+	/* inobt records must be aligned to cluster and inoalignmnt size. */
+	if (irec->ir_startino & (mp->m_cluster_align_inodes - 1)) {
+		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+		return;
+	}
+
+	if (irec->ir_startino & (mp->m_inodes_per_cluster - 1)) {
+		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+		return;
+	}
+}
+
 /* Scrub an inobt/finobt record. */
 STATIC int
 xchk_iallocbt_rec(
@@ -277,7 +324,6 @@ xchk_iallocbt_rec(
 	uint64_t			holes;
 	xfs_agnumber_t			agno = bs->cur->bc_private.a.agno;
 	xfs_agino_t			agino;
-	xfs_agblock_t			agbno;
 	xfs_extlen_t			len;
 	int				holecount;
 	int				i;
@@ -304,11 +350,9 @@ xchk_iallocbt_rec(
 		goto out;
 	}
 
-	/* Make sure this record is aligned to cluster and inoalignmnt size. */
-	agbno = XFS_AGINO_TO_AGBNO(mp, irec.ir_startino);
-	if ((agbno & (mp->m_cluster_align - 1)) ||
-	    (agbno & (mp->m_blocks_per_cluster - 1)))
-		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+	xchk_iallocbt_rec_alignment(bs, &irec);
+	if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
+		goto out;
 
 	iabt->inodes += irec.ir_count;
 

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/7] xfs: check inobt record alignment on big block filesystems
  2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
  2019-01-08 20:32 ` [PATCH 1/7] xfs: never try to scrub more than 64 inodes per inobt record Darrick J. Wong
  2019-01-08 20:32 ` [PATCH 2/7] xfs: check the ir_startino alignment directly Darrick J. Wong
@ 2019-01-08 20:32 ` Darrick J. Wong
  2019-01-08 20:33 ` [PATCH 4/7] xfs: hoist inode cluster checks out of loop Darrick J. Wong
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:32 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster, Dave Chinner

From: Darrick J. Wong <darrick.wong@oracle.com>

On a big block filesystem, there may be multiple inobt records covering
a single inode cluster.  These records obviously won't be aligned to
cluster alignment rules, and they must cover the entire cluster.  Teach
scrub to check for these things.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/scrub/ialloc.c |   41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)


diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 1c6fef9b3799..b8bfa93fd1a4 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -47,6 +47,12 @@ xchk_setup_ag_iallocbt(
 struct xchk_iallocbt {
 	/* Number of inodes we see while scanning inobt. */
 	unsigned long long	inodes;
+
+	/* Expected next startino, for big block filesystems. */
+	xfs_agino_t		next_startino;
+
+	/* Expected end of the current inode cluster. */
+	xfs_agino_t		next_cluster_ino;
 };
 
 /*
@@ -277,6 +283,7 @@ xchk_iallocbt_rec_alignment(
 	struct xfs_inobt_rec_incore	*irec)
 {
 	struct xfs_mount		*mp = bs->sc->mp;
+	struct xchk_iallocbt		*iabt = bs->private;
 
 	/*
 	 * finobt records have different positioning requirements than inobt
@@ -300,6 +307,27 @@ xchk_iallocbt_rec_alignment(
 		return;
 	}
 
+	if (iabt->next_startino != NULLAGINO) {
+		/*
+		 * We're midway through a cluster of inodes that is mapped by
+		 * multiple inobt records.  Did we get the record for the next
+		 * irec in the sequence?
+		 */
+		if (irec->ir_startino != iabt->next_startino) {
+			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+			return;
+		}
+
+		iabt->next_startino += XFS_INODES_PER_CHUNK;
+
+		/* Are we done with the cluster? */
+		if (iabt->next_startino >= iabt->next_cluster_ino) {
+			iabt->next_startino = NULLAGINO;
+			iabt->next_cluster_ino = NULLAGINO;
+		}
+		return;
+	}
+
 	/* inobt records must be aligned to cluster and inoalignmnt size. */
 	if (irec->ir_startino & (mp->m_cluster_align_inodes - 1)) {
 		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
@@ -310,6 +338,17 @@ xchk_iallocbt_rec_alignment(
 		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
 		return;
 	}
+
+	if (mp->m_inodes_per_cluster <= XFS_INODES_PER_CHUNK)
+		return;
+
+	/*
+	 * If this is the start of an inode cluster that can be mapped by
+	 * multiple inobt records, the next inobt record must follow exactly
+	 * after this one.
+	 */
+	iabt->next_startino = irec->ir_startino + XFS_INODES_PER_CHUNK;
+	iabt->next_cluster_ino = irec->ir_startino + mp->m_inodes_per_cluster;
 }
 
 /* Scrub an inobt/finobt record. */
@@ -474,6 +513,8 @@ xchk_iallocbt(
 	struct xfs_btree_cur	*cur;
 	struct xchk_iallocbt	iabt = {
 		.inodes		= 0,
+		.next_startino	= NULLAGINO,
+		.next_cluster_ino = NULLAGINO,
 	};
 	int			error;
 

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/7] xfs: hoist inode cluster checks out of loop
  2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
                   ` (2 preceding siblings ...)
  2019-01-08 20:32 ` [PATCH 3/7] xfs: check inobt record alignment on big block filesystems Darrick J. Wong
@ 2019-01-08 20:33 ` Darrick J. Wong
  2019-01-08 20:33 ` [PATCH 5/7] xfs: clean up the inode cluster checking in the inobt scrub Darrick J. Wong
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:33 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster, Dave Chinner

From: Darrick J. Wong <darrick.wong@oracle.com>

Hoist the inode cluster checks out of the inobt record check loop into
a separate function in preparation for refactoring of that loop.  No
functional changes here; that's in the next patch.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/scrub/ialloc.c |  119 +++++++++++++++++++++++++++----------------------
 1 file changed, 65 insertions(+), 54 deletions(-)


diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index b8bfa93fd1a4..0ce793d92995 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -188,19 +188,19 @@ xchk_iallocbt_check_cluster_freemask(
 	return 0;
 }
 
-/* Make sure the free mask is consistent with what the inodes think. */
+/* Check an inode cluster. */
 STATIC int
-xchk_iallocbt_check_freemask(
+xchk_iallocbt_check_cluster(
 	struct xchk_btree		*bs,
-	struct xfs_inobt_rec_incore	*irec)
+	struct xfs_inobt_rec_incore	*irec,
+	xfs_agino_t			agino)
 {
 	struct xfs_imap			imap;
 	struct xfs_mount		*mp = bs->cur->bc_mp;
 	struct xfs_dinode		*dip;
 	struct xfs_buf			*bp;
 	xfs_ino_t			fsino;
-	xfs_agino_t			nr_inodes;
-	xfs_agino_t			agino;
+	unsigned int			nr_inodes;
 	xfs_agino_t			chunkino;
 	xfs_agino_t			clusterino;
 	xfs_agblock_t			agbno;
@@ -212,60 +212,71 @@ xchk_iallocbt_check_freemask(
 	nr_inodes = min_t(unsigned int, XFS_INODES_PER_CHUNK,
 			mp->m_inodes_per_cluster);
 
-	for (agino = irec->ir_startino;
-	     agino < irec->ir_startino + XFS_INODES_PER_CHUNK;
-	     agino += mp->m_inodes_per_cluster) {
-		fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
-		chunkino = agino - irec->ir_startino;
-		agbno = XFS_AGINO_TO_AGBNO(mp, agino);
-
-		/* Compute the holemask mask for this cluster. */
-		for (clusterino = 0, holemask = 0; clusterino < nr_inodes;
-		     clusterino += XFS_INODES_PER_HOLEMASK_BIT)
-			holemask |= XFS_INOBT_MASK((chunkino + clusterino) /
-					XFS_INODES_PER_HOLEMASK_BIT);
-
-		/* The whole cluster must be a hole or not a hole. */
-		ir_holemask = (irec->ir_holemask & holemask);
-		if (ir_holemask != holemask && ir_holemask != 0) {
-			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
-			continue;
-		}
+	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
+	chunkino = agino - irec->ir_startino;
+	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
 
-		/* If any part of this is a hole, skip it. */
-		if (ir_holemask) {
-			xchk_xref_is_not_owned_by(bs->sc, agbno,
-					mp->m_blocks_per_cluster,
-					&XFS_RMAP_OINFO_INODES);
-			continue;
-		}
+	/* Compute the holemask mask for this cluster. */
+	for (clusterino = 0, holemask = 0; clusterino < nr_inodes;
+	     clusterino += XFS_INODES_PER_HOLEMASK_BIT)
+		holemask |= XFS_INOBT_MASK((chunkino + clusterino) /
+				XFS_INODES_PER_HOLEMASK_BIT);
+
+	/* The whole cluster must be a hole or not a hole. */
+	ir_holemask = (irec->ir_holemask & holemask);
+	if (ir_holemask != holemask && ir_holemask != 0) {
+		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+		return 0;
+	}
 
-		xchk_xref_is_owned_by(bs->sc, agbno, mp->m_blocks_per_cluster,
+	/* If any part of this is a hole, skip it. */
+	if (ir_holemask) {
+		xchk_xref_is_not_owned_by(bs->sc, agbno,
+				mp->m_blocks_per_cluster,
 				&XFS_RMAP_OINFO_INODES);
+		return 0;
+	}
 
-		/* Grab the inode cluster buffer. */
-		imap.im_blkno = XFS_AGB_TO_DADDR(mp, bs->cur->bc_private.a.agno,
-				agbno);
-		imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
-		imap.im_boffset = 0;
-
-		error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap,
-				&dip, &bp, 0, 0);
-		if (!xchk_btree_xref_process_error(bs->sc, bs->cur, 0,
-				&error))
-			continue;
-
-		/* Which inodes are free? */
-		for (clusterino = 0; clusterino < nr_inodes; clusterino++) {
-			error = xchk_iallocbt_check_cluster_freemask(bs,
-					fsino, chunkino, clusterino, irec, bp);
-			if (error) {
-				xfs_trans_brelse(bs->cur->bc_tp, bp);
-				return error;
-			}
-		}
+	xchk_xref_is_owned_by(bs->sc, agbno, mp->m_blocks_per_cluster,
+			&XFS_RMAP_OINFO_INODES);
+
+	/* Grab the inode cluster buffer. */
+	imap.im_blkno = XFS_AGB_TO_DADDR(mp, bs->cur->bc_private.a.agno, agbno);
+	imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
+	imap.im_boffset = 0;
 
-		xfs_trans_brelse(bs->cur->bc_tp, bp);
+	error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap, &dip, &bp, 0, 0);
+	if (!xchk_btree_xref_process_error(bs->sc, bs->cur, 0, &error))
+		return 0;
+
+	/* Which inodes are free? */
+	for (clusterino = 0; clusterino < nr_inodes; clusterino++) {
+		error = xchk_iallocbt_check_cluster_freemask(bs, fsino,
+				chunkino, clusterino, irec, bp);
+		if (error)
+			break;
+	}
+
+	xfs_trans_brelse(bs->cur->bc_tp, bp);
+	return error;
+}
+
+/* Make sure the free mask is consistent with what the inodes think. */
+STATIC int
+xchk_iallocbt_check_freemask(
+	struct xchk_btree		*bs,
+	struct xfs_inobt_rec_incore	*irec)
+{
+	struct xfs_mount		*mp = bs->cur->bc_mp;
+	xfs_agino_t			agino;
+	int				error = 0;
+
+	for (agino = irec->ir_startino;
+	     agino < irec->ir_startino + XFS_INODES_PER_CHUNK;
+	     agino += mp->m_inodes_per_cluster) {
+		error = xchk_iallocbt_check_cluster(bs, irec, agino);
+		if (error)
+			break;
 	}
 
 	return error;

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/7] xfs: clean up the inode cluster checking in the inobt scrub
  2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
                   ` (3 preceding siblings ...)
  2019-01-08 20:33 ` [PATCH 4/7] xfs: hoist inode cluster checks out of loop Darrick J. Wong
@ 2019-01-08 20:33 ` Darrick J. Wong
  2019-01-08 20:33 ` [PATCH 6/7] xfs: scrub big block inode btrees correctly Darrick J. Wong
  2019-01-08 20:33 ` [PATCH 7/7] xfs: consolidate scrub dinode mapping code into a single function Darrick J. Wong
  6 siblings, 0 replies; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:33 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster

From: Darrick J. Wong <darrick.wong@oracle.com>

The code to check inobt records against inode clusters is a mess of
poorly named variables and unnecessary parameters.  Clean the
unnecessary inode number parameters out of _check_cluster_freemask in
favor of computing them inside the function instead of making the caller
do it.  In xchk_iallocbt_check_cluster, rename the variables to make it
more obvious just what chunk_ino and cluster_ino represent.

Add a tracepoint to make it easier to track each inode cluster as we
scrub it.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/scrub/ialloc.c |  165 ++++++++++++++++++++++++++++++++-----------------
 fs/xfs/scrub/trace.h  |   45 +++++++++++++
 2 files changed, 152 insertions(+), 58 deletions(-)


diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 0ce793d92995..708f6607db71 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -134,41 +134,69 @@ xchk_iallocbt_freecount(
 	return hweight64(freemask);
 }
 
-/* Check a particular inode with ir_free. */
+/*
+ * Check that an inode's allocation status matches ir_free in the inobt
+ * record.  First we try querying the in-core inode state, and if the inode
+ * isn't loaded we examine the on-disk inode directly.
+ *
+ * Since there can be 1:M and M:1 mappings between inobt records and inode
+ * clusters, we pass in the inode location information as an inobt record;
+ * the index of an inode cluster within the inobt record (as well as the
+ * cluster buffer itself); and the index of the inode within the cluster.
+ *
+ * @irec is the inobt record.
+ * @cluster_base is the inode offset of the cluster within the @irec.
+ * @cluster_bp is the cluster buffer.
+ * @cluster_index is the inode offset within the inode cluster.
+ */
 STATIC int
-xchk_iallocbt_check_cluster_freemask(
+xchk_iallocbt_check_cluster_ifree(
 	struct xchk_btree		*bs,
-	xfs_ino_t			fsino,
-	xfs_agino_t			chunkino,
-	xfs_agino_t			clusterino,
 	struct xfs_inobt_rec_incore	*irec,
-	struct xfs_buf			*bp)
+	unsigned int			cluster_base,
+	struct xfs_buf			*cluster_bp,
+	unsigned int			cluster_index)
 {
-	struct xfs_dinode		*dip;
 	struct xfs_mount		*mp = bs->cur->bc_mp;
-	bool				inode_is_free = false;
+	struct xfs_dinode		*dip;
+	xfs_ino_t			fsino;
+	xfs_agino_t			agino;
+	unsigned int			offset;
+	bool				irec_free;
+	bool				ino_inuse;
 	bool				freemask_ok;
-	bool				inuse;
-	int				error = 0;
+	int				error;
 
 	if (xchk_should_terminate(bs->sc, &error))
 		return error;
 
-	dip = xfs_buf_offset(bp, clusterino * mp->m_sb.sb_inodesize);
+	/*
+	 * Given an inobt record, an offset of a cluster within the record, and
+	 * an offset of an inode within a cluster, compute which fs inode we're
+	 * talking about and the offset of that inode within the buffer.
+	 */
+	agino = irec->ir_startino + cluster_base + cluster_index;
+	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
+	offset = cluster_index * mp->m_sb.sb_inodesize;
+	if (offset >= BBTOB(cluster_bp->b_length)) {
+		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+		goto out;
+	}
+	dip = xfs_buf_offset(cluster_bp, offset);
+	irec_free = (irec->ir_free & XFS_INOBT_MASK(cluster_base +
+						    cluster_index));
+
 	if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC ||
-	    (dip->di_version >= 3 &&
-	     be64_to_cpu(dip->di_ino) != fsino + clusterino)) {
+	    (dip->di_version >= 3 && be64_to_cpu(dip->di_ino) != fsino)) {
 		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
 		goto out;
 	}
 
-	if (irec->ir_free & XFS_INOBT_MASK(chunkino + clusterino))
-		inode_is_free = true;
-	error = xfs_icache_inode_is_allocated(mp, bs->cur->bc_tp,
-			fsino + clusterino, &inuse);
+	error = xfs_icache_inode_is_allocated(mp, bs->cur->bc_tp, fsino,
+			&ino_inuse);
 	if (error == -ENODATA) {
 		/* Not cached, just read the disk buffer */
-		freemask_ok = inode_is_free ^ !!(dip->di_mode);
+		freemask_ok = irec_free ^ !!(dip->di_mode);
 		if (!bs->sc->try_harder && !freemask_ok)
 			return -EDEADLOCK;
 	} else if (error < 0) {
@@ -180,7 +208,7 @@ xchk_iallocbt_check_cluster_freemask(
 		goto out;
 	} else {
 		/* Inode is all there. */
-		freemask_ok = inode_is_free ^ inuse;
+		freemask_ok = irec_free ^ ino_inuse;
 	}
 	if (!freemask_ok)
 		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
@@ -188,43 +216,57 @@ xchk_iallocbt_check_cluster_freemask(
 	return 0;
 }
 
-/* Check an inode cluster. */
+/*
+ * Check that the holemask and freemask of a hypothetical inode cluster match
+ * what's actually on disk.  If sparse inodes are enabled, the cluster does
+ * not actually have to map to inodes if the corresponding holemask bit is set.
+ *
+ * @cluster_base is the first inode in the cluster within the @irec.
+ */
 STATIC int
 xchk_iallocbt_check_cluster(
 	struct xchk_btree		*bs,
 	struct xfs_inobt_rec_incore	*irec,
-	xfs_agino_t			agino)
+	unsigned int			cluster_base)
 {
 	struct xfs_imap			imap;
 	struct xfs_mount		*mp = bs->cur->bc_mp;
 	struct xfs_dinode		*dip;
-	struct xfs_buf			*bp;
-	xfs_ino_t			fsino;
+	struct xfs_buf			*cluster_bp;
 	unsigned int			nr_inodes;
-	xfs_agino_t			chunkino;
-	xfs_agino_t			clusterino;
+	xfs_agnumber_t			agno = bs->cur->bc_private.a.agno;
 	xfs_agblock_t			agbno;
-	uint16_t			holemask;
+	unsigned int			cluster_index;
+	uint16_t			cluster_mask = 0;
 	uint16_t			ir_holemask;
 	int				error = 0;
 
-	/* Make sure the freemask matches the inode records. */
 	nr_inodes = min_t(unsigned int, XFS_INODES_PER_CHUNK,
 			mp->m_inodes_per_cluster);
 
-	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
-	chunkino = agino - irec->ir_startino;
-	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
+	/* Map this inode cluster */
+	agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino + cluster_base);
 
-	/* Compute the holemask mask for this cluster. */
-	for (clusterino = 0, holemask = 0; clusterino < nr_inodes;
-	     clusterino += XFS_INODES_PER_HOLEMASK_BIT)
-		holemask |= XFS_INOBT_MASK((chunkino + clusterino) /
+	/* Compute a bitmask for this cluster that can be used for holemask. */
+	for (cluster_index = 0;
+	     cluster_index < nr_inodes;
+	     cluster_index += XFS_INODES_PER_HOLEMASK_BIT)
+		cluster_mask |= XFS_INOBT_MASK((cluster_base + cluster_index) /
 				XFS_INODES_PER_HOLEMASK_BIT);
 
+	ir_holemask = (irec->ir_holemask & cluster_mask);
+	imap.im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
+	imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
+	imap.im_boffset = 0;
+
+	trace_xchk_iallocbt_check_cluster(mp, agno, irec->ir_startino,
+			imap.im_blkno, imap.im_len, cluster_base, nr_inodes,
+			cluster_mask, ir_holemask,
+			XFS_INO_TO_OFFSET(mp, irec->ir_startino +
+					  cluster_base));
+
 	/* The whole cluster must be a hole or not a hole. */
-	ir_holemask = (irec->ir_holemask & holemask);
-	if (ir_holemask != holemask && ir_holemask != 0) {
+	if (ir_holemask != cluster_mask && ir_holemask != 0) {
 		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
 		return 0;
 	}
@@ -241,40 +283,47 @@ xchk_iallocbt_check_cluster(
 			&XFS_RMAP_OINFO_INODES);
 
 	/* Grab the inode cluster buffer. */
-	imap.im_blkno = XFS_AGB_TO_DADDR(mp, bs->cur->bc_private.a.agno, agbno);
-	imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
-	imap.im_boffset = 0;
-
-	error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap, &dip, &bp, 0, 0);
+	error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap, &dip, &cluster_bp,
+			0, 0);
 	if (!xchk_btree_xref_process_error(bs->sc, bs->cur, 0, &error))
-		return 0;
+		return error;
 
-	/* Which inodes are free? */
-	for (clusterino = 0; clusterino < nr_inodes; clusterino++) {
-		error = xchk_iallocbt_check_cluster_freemask(bs, fsino,
-				chunkino, clusterino, irec, bp);
+	/* Check free status of each inode within this cluster. */
+	for (cluster_index = 0; cluster_index < nr_inodes; cluster_index++) {
+		error = xchk_iallocbt_check_cluster_ifree(bs, irec,
+				cluster_base, cluster_bp, cluster_index);
 		if (error)
 			break;
 	}
 
-	xfs_trans_brelse(bs->cur->bc_tp, bp);
+	xfs_trans_brelse(bs->cur->bc_tp, cluster_bp);
 	return error;
 }
 
-/* Make sure the free mask is consistent with what the inodes think. */
+/*
+ * For all the inode clusters that could map to this inobt record, make sure
+ * that the holemask makes sense and that the allocation status of each inode
+ * matches the freemask.
+ */
 STATIC int
-xchk_iallocbt_check_freemask(
+xchk_iallocbt_check_clusters(
 	struct xchk_btree		*bs,
 	struct xfs_inobt_rec_incore	*irec)
 {
-	struct xfs_mount		*mp = bs->cur->bc_mp;
-	xfs_agino_t			agino;
+	unsigned int			cluster_base;
 	int				error = 0;
 
-	for (agino = irec->ir_startino;
-	     agino < irec->ir_startino + XFS_INODES_PER_CHUNK;
-	     agino += mp->m_inodes_per_cluster) {
-		error = xchk_iallocbt_check_cluster(bs, irec, agino);
+	/*
+	 * For the common case where this inobt record maps to multiple inode
+	 * clusters this will call _check_cluster for each cluster.
+	 *
+	 * For the case that multiple inobt records map to a single cluster,
+	 * this will call _check_cluster once.
+	 */
+	for (cluster_base = 0;
+	     cluster_base < XFS_INODES_PER_CHUNK;
+	     cluster_base += bs->sc->mp->m_inodes_per_cluster) {
+		error = xchk_iallocbt_check_cluster(bs, irec, cluster_base);
 		if (error)
 			break;
 	}
@@ -415,7 +464,7 @@ xchk_iallocbt_rec(
 
 		if (!xchk_iallocbt_chunk(bs, &irec, agino, len))
 			goto out;
-		goto check_freemask;
+		goto check_clusters;
 	}
 
 	/* Check each chunk of a sparse inode cluster. */
@@ -441,8 +490,8 @@ xchk_iallocbt_rec(
 	    holecount + irec.ir_count != XFS_INODES_PER_CHUNK)
 		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
 
-check_freemask:
-	error = xchk_iallocbt_check_freemask(bs, &irec);
+check_clusters:
+	error = xchk_iallocbt_check_clusters(bs, &irec);
 	if (error)
 		goto out;
 
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index 8344b14031ef..3c83e8b3b39c 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -545,6 +545,51 @@ TRACE_EVENT(xchk_xref_error,
 		  __entry->ret_ip)
 );
 
+TRACE_EVENT(xchk_iallocbt_check_cluster,
+	TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+		 xfs_agino_t startino, xfs_daddr_t map_daddr,
+		 unsigned short map_len, unsigned int chunk_ino,
+		 unsigned int nr_inodes, uint16_t cluster_mask,
+		 uint16_t holemask, unsigned int cluster_ino),
+	TP_ARGS(mp, agno, startino, map_daddr, map_len, chunk_ino, nr_inodes,
+		cluster_mask, holemask, cluster_ino),
+	TP_STRUCT__entry(
+		__field(dev_t, dev)
+		__field(xfs_agnumber_t, agno)
+		__field(xfs_agino_t, startino)
+		__field(xfs_daddr_t, map_daddr)
+		__field(unsigned short, map_len)
+		__field(unsigned int, chunk_ino)
+		__field(unsigned int, nr_inodes)
+		__field(unsigned int, cluster_ino)
+		__field(uint16_t, cluster_mask)
+		__field(uint16_t, holemask)
+	),
+	TP_fast_assign(
+		__entry->dev = mp->m_super->s_dev;
+		__entry->agno = agno;
+		__entry->startino = startino;
+		__entry->map_daddr = map_daddr;
+		__entry->map_len = map_len;
+		__entry->chunk_ino = chunk_ino;
+		__entry->nr_inodes = nr_inodes;
+		__entry->cluster_mask = cluster_mask;
+		__entry->holemask = holemask;
+		__entry->cluster_ino = cluster_ino;
+	),
+	TP_printk("dev %d:%d agno %d startino %u daddr 0x%llx len %d chunkino %u nr_inodes %u cluster_mask 0x%x holemask 0x%x cluster_ino %u",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+		  __entry->agno,
+		  __entry->startino,
+		  __entry->map_daddr,
+		  __entry->map_len,
+		  __entry->chunk_ino,
+		  __entry->nr_inodes,
+		  __entry->cluster_mask,
+		  __entry->holemask,
+		  __entry->cluster_ino)
+)
+
 /* repair tracepoints */
 #if IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR)
 

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/7] xfs: scrub big block inode btrees correctly
  2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
                   ` (4 preceding siblings ...)
  2019-01-08 20:33 ` [PATCH 5/7] xfs: clean up the inode cluster checking in the inobt scrub Darrick J. Wong
@ 2019-01-08 20:33 ` Darrick J. Wong
  2019-01-09 13:32   ` Brian Foster
  2019-01-08 20:33 ` [PATCH 7/7] xfs: consolidate scrub dinode mapping code into a single function Darrick J. Wong
  6 siblings, 1 reply; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:33 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster

From: Darrick J. Wong <darrick.wong@oracle.com>

Teach scrub how to handle the case that there are one or more inobt
records covering a given inode cluster.  This fixes the operation on big
block filesystems (e.g. 64k blocks, 512 byte inodes).

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/scrub/ialloc.c |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)


diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 708f6607db71..1929d79ea6b3 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -162,6 +162,7 @@ xchk_iallocbt_check_cluster_ifree(
 	xfs_ino_t			fsino;
 	xfs_agino_t			agino;
 	unsigned int			offset;
+	unsigned int			cluster_buf_base;
 	bool				irec_free;
 	bool				ino_inuse;
 	bool				freemask_ok;
@@ -174,10 +175,17 @@ xchk_iallocbt_check_cluster_ifree(
 	 * Given an inobt record, an offset of a cluster within the record, and
 	 * an offset of an inode within a cluster, compute which fs inode we're
 	 * talking about and the offset of that inode within the buffer.
+	 *
+	 * Be careful about inobt records that don't align with the start of
+	 * the inode buffer when block sizes are large enough to hold multiple
+	 * inode chunks.  When this happens, cluster_base will be zero but
+	 * ir_startino can be large enough to make cluster_buf_base nonzero.
 	 */
 	agino = irec->ir_startino + cluster_base + cluster_index;
 	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
-	offset = cluster_index * mp->m_sb.sb_inodesize;
+	cluster_buf_base = XFS_INO_TO_OFFSET(mp, irec->ir_startino);
+	ASSERT(cluster_buf_base == 0 || cluster_base == 0);
+	offset = (cluster_buf_base + cluster_index) * mp->m_sb.sb_inodesize;
 	if (offset >= BBTOB(cluster_bp->b_length)) {
 		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
 		goto out;

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/7] xfs: consolidate scrub dinode mapping code into a single function
  2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
                   ` (5 preceding siblings ...)
  2019-01-08 20:33 ` [PATCH 6/7] xfs: scrub big block inode btrees correctly Darrick J. Wong
@ 2019-01-08 20:33 ` Darrick J. Wong
  2019-01-09 13:33   ` Brian Foster
  6 siblings, 1 reply; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-08 20:33 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, bfoster

From: Darrick J. Wong <darrick.wong@oracle.com>

Move all the confusing dinode mapping code that's split between
xchk_iallocbt_check_cluster and xchk_iallocbt_check_cluster_ifree into
the first function so that it's clearer how we find the dinode for a
given inode.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/scrub/ialloc.c |   48 +++++++++++++++++++++++++++---------------------
 1 file changed, 27 insertions(+), 21 deletions(-)


diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 1929d79ea6b3..663cc8a98fc9 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -146,7 +146,7 @@ xchk_iallocbt_freecount(
  *
  * @irec is the inobt record.
  * @cluster_base is the inode offset of the cluster within the @irec.
- * @cluster_bp is the cluster buffer.
+ * @dip is the on-disk inode.
  * @cluster_index is the inode offset within the inode cluster.
  */
 STATIC int
@@ -154,15 +154,12 @@ xchk_iallocbt_check_cluster_ifree(
 	struct xchk_btree		*bs,
 	struct xfs_inobt_rec_incore	*irec,
 	unsigned int			cluster_base,
-	struct xfs_buf			*cluster_bp,
+	struct xfs_dinode		*dip,
 	unsigned int			cluster_index)
 {
 	struct xfs_mount		*mp = bs->cur->bc_mp;
-	struct xfs_dinode		*dip;
 	xfs_ino_t			fsino;
 	xfs_agino_t			agino;
-	unsigned int			offset;
-	unsigned int			cluster_buf_base;
 	bool				irec_free;
 	bool				ino_inuse;
 	bool				freemask_ok;
@@ -174,23 +171,10 @@ xchk_iallocbt_check_cluster_ifree(
 	/*
 	 * Given an inobt record, an offset of a cluster within the record, and
 	 * an offset of an inode within a cluster, compute which fs inode we're
-	 * talking about and the offset of that inode within the buffer.
-	 *
-	 * Be careful about inobt records that don't align with the start of
-	 * the inode buffer when block sizes are large enough to hold multiple
-	 * inode chunks.  When this happens, cluster_base will be zero but
-	 * ir_startino can be large enough to make cluster_buf_base nonzero.
+	 * talking about.
 	 */
 	agino = irec->ir_startino + cluster_base + cluster_index;
 	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
-	cluster_buf_base = XFS_INO_TO_OFFSET(mp, irec->ir_startino);
-	ASSERT(cluster_buf_base == 0 || cluster_base == 0);
-	offset = (cluster_buf_base + cluster_index) * mp->m_sb.sb_inodesize;
-	if (offset >= BBTOB(cluster_bp->b_length)) {
-		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
-		goto out;
-	}
-	dip = xfs_buf_offset(cluster_bp, offset);
 	irec_free = (irec->ir_free & XFS_INOBT_MASK(cluster_base +
 						    cluster_index));
 
@@ -262,10 +246,23 @@ xchk_iallocbt_check_cluster(
 		cluster_mask |= XFS_INOBT_MASK((cluster_base + cluster_index) /
 				XFS_INODES_PER_HOLEMASK_BIT);
 
+	/*
+	 * Map the first inode of this cluster to a buffer and offset.
+	 * Be careful about inobt records that don't align with the start of
+	 * the inode buffer when block sizes are large enough to hold multiple
+	 * inode chunks.  When this happens, cluster_base will be zero but
+	 * ir_startino can be large enough to make im_boffset nonzero.
+	 */
 	ir_holemask = (irec->ir_holemask & cluster_mask);
 	imap.im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
 	imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
-	imap.im_boffset = 0;
+	imap.im_boffset = XFS_INO_TO_OFFSET(mp, irec->ir_startino);
+
+	if (imap.im_boffset != 0 && cluster_base != 0) {
+		ASSERT(imap.im_boffset == 0 || cluster_base == 0);
+		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+		return 0;
+	}
 
 	trace_xchk_iallocbt_check_cluster(mp, agno, irec->ir_startino,
 			imap.im_blkno, imap.im_len, cluster_base, nr_inodes,
@@ -298,10 +295,19 @@ xchk_iallocbt_check_cluster(
 
 	/* Check free status of each inode within this cluster. */
 	for (cluster_index = 0; cluster_index < nr_inodes; cluster_index++) {
+		struct xfs_dinode	*dip;
+
+		if (imap.im_boffset >= BBTOB(cluster_bp->b_length)) {
+			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+			break;
+		}
+
+		dip = xfs_buf_offset(cluster_bp, imap.im_boffset);
 		error = xchk_iallocbt_check_cluster_ifree(bs, irec,
-				cluster_base, cluster_bp, cluster_index);
+				cluster_base, dip, cluster_index);
 		if (error)
 			break;
+		imap.im_boffset += mp->m_sb.sb_inodesize;
 	}
 
 	xfs_trans_brelse(bs->cur->bc_tp, cluster_bp);

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/7] xfs: check the ir_startino alignment directly
  2019-01-08 20:32 ` [PATCH 2/7] xfs: check the ir_startino alignment directly Darrick J. Wong
@ 2019-01-09 13:32   ` Brian Foster
  2019-01-09 16:37     ` Darrick J. Wong
  0 siblings, 1 reply; 13+ messages in thread
From: Brian Foster @ 2019-01-09 13:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Jan 08, 2019 at 12:32:47PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> In xchk_iallocbt_rec, check the alignment of ir_startino by converting
> the inode cluster block alignment into units of inodes instead of the
> other way around (converting ir_startino to blocks).  This prevents us
> from tripping over off-by-one errors in ir_startino which are obscured
> by the inode -> block conversion.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/scrub/ialloc.c |   56 ++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 50 insertions(+), 6 deletions(-)
> 
> 
> diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
> index fd431682db0b..1c6fef9b3799 100644
> --- a/fs/xfs/scrub/ialloc.c
> +++ b/fs/xfs/scrub/ialloc.c
> @@ -265,6 +265,53 @@ xchk_iallocbt_check_freemask(
>  	return error;
>  }
>  
> +/*
> + * Make sure this inode btree record is aligned properly.  Because a fs block
> + * contains multiple inodes, we check that the inobt record is aligned to the
> + * correct inode, not just the correct block on disk.  This results in a finer
> + * grained corruption check.
> + */
> +STATIC void
> +xchk_iallocbt_rec_alignment(
> +	struct xchk_btree		*bs,
> +	struct xfs_inobt_rec_incore	*irec)
> +{
> +	struct xfs_mount		*mp = bs->sc->mp;
> +
> +	/*
> +	 * finobt records have different positioning requirements than inobt
> +	 * records: each finobt record must have a corresponding inobt record.
> +	 * That is checked in the xref function, so for now we only catch the
> +	 * obvious case where the record isn't at all aligned properly.
> +	 *
> +	 * Note that if a fs block contains more than a single chunk of inodes,
> +	 * we will have finobt records only for those chunks containing free
> +	 * inodes, and therefore expect chunk alignment of finobt records.
> +	 * Otherwise, we expect that the finobt record is aligned to the
> +	 * cluster alignment as told by the superblock.
> +	 */
> +	if (bs->cur->bc_btnum == XFS_BTNUM_FINO) {
> +		unsigned int	imask;
> +
> +		imask = min_t(unsigned int, XFS_INODES_PER_CHUNK,
> +				mp->m_cluster_align_inodes) - 1;
> +		if (irec->ir_startino & imask)
> +			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> +		return;
> +	}
> +

Don't we also need this large FSB alignment fixup for inobt records, or
am I still confused? :/ I.e., if ->m_cluster_align_inodes is 128 and
irec is the second inobt record in a block..

Brian

> +	/* inobt records must be aligned to cluster and inoalignmnt size. */
> +	if (irec->ir_startino & (mp->m_cluster_align_inodes - 1)) {
> +		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> +		return;
> +	}
> +
> +	if (irec->ir_startino & (mp->m_inodes_per_cluster - 1)) {
> +		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> +		return;
> +	}
> +}
> +
>  /* Scrub an inobt/finobt record. */
>  STATIC int
>  xchk_iallocbt_rec(
> @@ -277,7 +324,6 @@ xchk_iallocbt_rec(
>  	uint64_t			holes;
>  	xfs_agnumber_t			agno = bs->cur->bc_private.a.agno;
>  	xfs_agino_t			agino;
> -	xfs_agblock_t			agbno;
>  	xfs_extlen_t			len;
>  	int				holecount;
>  	int				i;
> @@ -304,11 +350,9 @@ xchk_iallocbt_rec(
>  		goto out;
>  	}
>  
> -	/* Make sure this record is aligned to cluster and inoalignmnt size. */
> -	agbno = XFS_AGINO_TO_AGBNO(mp, irec.ir_startino);
> -	if ((agbno & (mp->m_cluster_align - 1)) ||
> -	    (agbno & (mp->m_blocks_per_cluster - 1)))
> -		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> +	xchk_iallocbt_rec_alignment(bs, &irec);
> +	if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
> +		goto out;
>  
>  	iabt->inodes += irec.ir_count;
>  
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 6/7] xfs: scrub big block inode btrees correctly
  2019-01-08 20:33 ` [PATCH 6/7] xfs: scrub big block inode btrees correctly Darrick J. Wong
@ 2019-01-09 13:32   ` Brian Foster
  0 siblings, 0 replies; 13+ messages in thread
From: Brian Foster @ 2019-01-09 13:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Jan 08, 2019 at 12:33:12PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Teach scrub how to handle the case that there are one or more inobt
> records covering a given inode cluster.  This fixes the operation on big
> block filesystems (e.g. 64k blocks, 512 byte inodes).
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/scrub/ialloc.c |   10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> 
> diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
> index 708f6607db71..1929d79ea6b3 100644
> --- a/fs/xfs/scrub/ialloc.c
> +++ b/fs/xfs/scrub/ialloc.c
> @@ -162,6 +162,7 @@ xchk_iallocbt_check_cluster_ifree(
>  	xfs_ino_t			fsino;
>  	xfs_agino_t			agino;
>  	unsigned int			offset;
> +	unsigned int			cluster_buf_base;
>  	bool				irec_free;
>  	bool				ino_inuse;
>  	bool				freemask_ok;
> @@ -174,10 +175,17 @@ xchk_iallocbt_check_cluster_ifree(
>  	 * Given an inobt record, an offset of a cluster within the record, and
>  	 * an offset of an inode within a cluster, compute which fs inode we're
>  	 * talking about and the offset of that inode within the buffer.
> +	 *
> +	 * Be careful about inobt records that don't align with the start of
> +	 * the inode buffer when block sizes are large enough to hold multiple
> +	 * inode chunks.  When this happens, cluster_base will be zero but
> +	 * ir_startino can be large enough to make cluster_buf_base nonzero.
>  	 */
>  	agino = irec->ir_startino + cluster_base + cluster_index;
>  	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
> -	offset = cluster_index * mp->m_sb.sb_inodesize;
> +	cluster_buf_base = XFS_INO_TO_OFFSET(mp, irec->ir_startino);
> +	ASSERT(cluster_buf_base == 0 || cluster_base == 0);
> +	offset = (cluster_buf_base + cluster_index) * mp->m_sb.sb_inodesize;
>  	if (offset >= BBTOB(cluster_bp->b_length)) {
>  		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
>  		goto out;
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 7/7] xfs: consolidate scrub dinode mapping code into a single function
  2019-01-08 20:33 ` [PATCH 7/7] xfs: consolidate scrub dinode mapping code into a single function Darrick J. Wong
@ 2019-01-09 13:33   ` Brian Foster
  0 siblings, 0 replies; 13+ messages in thread
From: Brian Foster @ 2019-01-09 13:33 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Jan 08, 2019 at 12:33:18PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Move all the confusing dinode mapping code that's split between
> xchk_iallocbt_check_cluster and xchk_iallocbt_check_cluster_ifree into
> the first function so that it's clearer how we find the dinode for a
> given inode.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/scrub/ialloc.c |   48 +++++++++++++++++++++++++++---------------------
>  1 file changed, 27 insertions(+), 21 deletions(-)
> 
> 
> diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
> index 1929d79ea6b3..663cc8a98fc9 100644
> --- a/fs/xfs/scrub/ialloc.c
> +++ b/fs/xfs/scrub/ialloc.c
> @@ -146,7 +146,7 @@ xchk_iallocbt_freecount(
>   *
>   * @irec is the inobt record.
>   * @cluster_base is the inode offset of the cluster within the @irec.
> - * @cluster_bp is the cluster buffer.
> + * @dip is the on-disk inode.
>   * @cluster_index is the inode offset within the inode cluster.
>   */
>  STATIC int
> @@ -154,15 +154,12 @@ xchk_iallocbt_check_cluster_ifree(
>  	struct xchk_btree		*bs,
>  	struct xfs_inobt_rec_incore	*irec,
>  	unsigned int			cluster_base,
> -	struct xfs_buf			*cluster_bp,
> +	struct xfs_dinode		*dip,
>  	unsigned int			cluster_index)
>  {

It doesn't seem like there's any need to pass both cluster_base and
cluster_index here either just to calculate agino, which is all this
function cares about. Can we calculate the index relative to startino in
the caller and pass that so this function has no reason to care about
inode clusters at all?

With that cleaned up:

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  	struct xfs_mount		*mp = bs->cur->bc_mp;
> -	struct xfs_dinode		*dip;
>  	xfs_ino_t			fsino;
>  	xfs_agino_t			agino;
> -	unsigned int			offset;
> -	unsigned int			cluster_buf_base;
>  	bool				irec_free;
>  	bool				ino_inuse;
>  	bool				freemask_ok;
> @@ -174,23 +171,10 @@ xchk_iallocbt_check_cluster_ifree(
>  	/*
>  	 * Given an inobt record, an offset of a cluster within the record, and
>  	 * an offset of an inode within a cluster, compute which fs inode we're
> -	 * talking about and the offset of that inode within the buffer.
> -	 *
> -	 * Be careful about inobt records that don't align with the start of
> -	 * the inode buffer when block sizes are large enough to hold multiple
> -	 * inode chunks.  When this happens, cluster_base will be zero but
> -	 * ir_startino can be large enough to make cluster_buf_base nonzero.
> +	 * talking about.
>  	 */
>  	agino = irec->ir_startino + cluster_base + cluster_index;
>  	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
> -	cluster_buf_base = XFS_INO_TO_OFFSET(mp, irec->ir_startino);
> -	ASSERT(cluster_buf_base == 0 || cluster_base == 0);
> -	offset = (cluster_buf_base + cluster_index) * mp->m_sb.sb_inodesize;
> -	if (offset >= BBTOB(cluster_bp->b_length)) {
> -		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> -		goto out;
> -	}
> -	dip = xfs_buf_offset(cluster_bp, offset);
>  	irec_free = (irec->ir_free & XFS_INOBT_MASK(cluster_base +
>  						    cluster_index));
>  
> @@ -262,10 +246,23 @@ xchk_iallocbt_check_cluster(
>  		cluster_mask |= XFS_INOBT_MASK((cluster_base + cluster_index) /
>  				XFS_INODES_PER_HOLEMASK_BIT);
>  
> +	/*
> +	 * Map the first inode of this cluster to a buffer and offset.
> +	 * Be careful about inobt records that don't align with the start of
> +	 * the inode buffer when block sizes are large enough to hold multiple
> +	 * inode chunks.  When this happens, cluster_base will be zero but
> +	 * ir_startino can be large enough to make im_boffset nonzero.
> +	 */
>  	ir_holemask = (irec->ir_holemask & cluster_mask);
>  	imap.im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
>  	imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster);
> -	imap.im_boffset = 0;
> +	imap.im_boffset = XFS_INO_TO_OFFSET(mp, irec->ir_startino);
> +
> +	if (imap.im_boffset != 0 && cluster_base != 0) {
> +		ASSERT(imap.im_boffset == 0 || cluster_base == 0);
> +		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> +		return 0;
> +	}
>  
>  	trace_xchk_iallocbt_check_cluster(mp, agno, irec->ir_startino,
>  			imap.im_blkno, imap.im_len, cluster_base, nr_inodes,
> @@ -298,10 +295,19 @@ xchk_iallocbt_check_cluster(
>  
>  	/* Check free status of each inode within this cluster. */
>  	for (cluster_index = 0; cluster_index < nr_inodes; cluster_index++) {
> +		struct xfs_dinode	*dip;
> +
> +		if (imap.im_boffset >= BBTOB(cluster_bp->b_length)) {
> +			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> +			break;
> +		}
> +
> +		dip = xfs_buf_offset(cluster_bp, imap.im_boffset);
>  		error = xchk_iallocbt_check_cluster_ifree(bs, irec,
> -				cluster_base, cluster_bp, cluster_index);
> +				cluster_base, dip, cluster_index);
>  		if (error)
>  			break;
> +		imap.im_boffset += mp->m_sb.sb_inodesize;
>  	}
>  
>  	xfs_trans_brelse(bs->cur->bc_tp, cluster_bp);
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/7] xfs: check the ir_startino alignment directly
  2019-01-09 13:32   ` Brian Foster
@ 2019-01-09 16:37     ` Darrick J. Wong
  2019-01-09 16:48       ` Brian Foster
  0 siblings, 1 reply; 13+ messages in thread
From: Darrick J. Wong @ 2019-01-09 16:37 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Wed, Jan 09, 2019 at 08:32:26AM -0500, Brian Foster wrote:
> On Tue, Jan 08, 2019 at 12:32:47PM -0800, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > In xchk_iallocbt_rec, check the alignment of ir_startino by converting
> > the inode cluster block alignment into units of inodes instead of the
> > other way around (converting ir_startino to blocks).  This prevents us
> > from tripping over off-by-one errors in ir_startino which are obscured
> > by the inode -> block conversion.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  fs/xfs/scrub/ialloc.c |   56 ++++++++++++++++++++++++++++++++++++++++++++-----
> >  1 file changed, 50 insertions(+), 6 deletions(-)
> > 
> > 
> > diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
> > index fd431682db0b..1c6fef9b3799 100644
> > --- a/fs/xfs/scrub/ialloc.c
> > +++ b/fs/xfs/scrub/ialloc.c
> > @@ -265,6 +265,53 @@ xchk_iallocbt_check_freemask(
> >  	return error;
> >  }
> >  
> > +/*
> > + * Make sure this inode btree record is aligned properly.  Because a fs block
> > + * contains multiple inodes, we check that the inobt record is aligned to the
> > + * correct inode, not just the correct block on disk.  This results in a finer
> > + * grained corruption check.
> > + */
> > +STATIC void
> > +xchk_iallocbt_rec_alignment(
> > +	struct xchk_btree		*bs,
> > +	struct xfs_inobt_rec_incore	*irec)
> > +{
> > +	struct xfs_mount		*mp = bs->sc->mp;
> > +
> > +	/*
> > +	 * finobt records have different positioning requirements than inobt
> > +	 * records: each finobt record must have a corresponding inobt record.
> > +	 * That is checked in the xref function, so for now we only catch the
> > +	 * obvious case where the record isn't at all aligned properly.
> > +	 *
> > +	 * Note that if a fs block contains more than a single chunk of inodes,
> > +	 * we will have finobt records only for those chunks containing free
> > +	 * inodes, and therefore expect chunk alignment of finobt records.
> > +	 * Otherwise, we expect that the finobt record is aligned to the
> > +	 * cluster alignment as told by the superblock.
> > +	 */
> > +	if (bs->cur->bc_btnum == XFS_BTNUM_FINO) {
> > +		unsigned int	imask;
> > +
> > +		imask = min_t(unsigned int, XFS_INODES_PER_CHUNK,
> > +				mp->m_cluster_align_inodes) - 1;
> > +		if (irec->ir_startino & imask)
> > +			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > +		return;
> > +	}
> > +
> 
> Don't we also need this large FSB alignment fixup for inobt records, or
> am I still confused? :/ I.e., if ->m_cluster_align_inodes is 128 and
> irec is the second inobt record in a block..

The logic added in the next patch checks that either an inobt record is
aligned to m_cluster_align_inodes, or that the record covers inodes that
are immediately after the previous inobt record.  In theory that should
fix our handling of the large FSB case, though I've only tested it on
qemu arm boxen.

--D

> Brian
> 
> > +	/* inobt records must be aligned to cluster and inoalignmnt size. */
> > +	if (irec->ir_startino & (mp->m_cluster_align_inodes - 1)) {
> > +		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > +		return;
> > +	}
> > +
> > +	if (irec->ir_startino & (mp->m_inodes_per_cluster - 1)) {
> > +		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > +		return;
> > +	}
> > +}
> > +
> >  /* Scrub an inobt/finobt record. */
> >  STATIC int
> >  xchk_iallocbt_rec(
> > @@ -277,7 +324,6 @@ xchk_iallocbt_rec(
> >  	uint64_t			holes;
> >  	xfs_agnumber_t			agno = bs->cur->bc_private.a.agno;
> >  	xfs_agino_t			agino;
> > -	xfs_agblock_t			agbno;
> >  	xfs_extlen_t			len;
> >  	int				holecount;
> >  	int				i;
> > @@ -304,11 +350,9 @@ xchk_iallocbt_rec(
> >  		goto out;
> >  	}
> >  
> > -	/* Make sure this record is aligned to cluster and inoalignmnt size. */
> > -	agbno = XFS_AGINO_TO_AGBNO(mp, irec.ir_startino);
> > -	if ((agbno & (mp->m_cluster_align - 1)) ||
> > -	    (agbno & (mp->m_blocks_per_cluster - 1)))
> > -		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > +	xchk_iallocbt_rec_alignment(bs, &irec);
> > +	if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
> > +		goto out;
> >  
> >  	iabt->inodes += irec.ir_count;
> >  
> > 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/7] xfs: check the ir_startino alignment directly
  2019-01-09 16:37     ` Darrick J. Wong
@ 2019-01-09 16:48       ` Brian Foster
  0 siblings, 0 replies; 13+ messages in thread
From: Brian Foster @ 2019-01-09 16:48 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Wed, Jan 09, 2019 at 08:37:44AM -0800, Darrick J. Wong wrote:
> On Wed, Jan 09, 2019 at 08:32:26AM -0500, Brian Foster wrote:
> > On Tue, Jan 08, 2019 at 12:32:47PM -0800, Darrick J. Wong wrote:
> > > From: Darrick J. Wong <darrick.wong@oracle.com>
> > > 
> > > In xchk_iallocbt_rec, check the alignment of ir_startino by converting
> > > the inode cluster block alignment into units of inodes instead of the
> > > other way around (converting ir_startino to blocks).  This prevents us
> > > from tripping over off-by-one errors in ir_startino which are obscured
> > > by the inode -> block conversion.
> > > 
> > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > > ---
> > >  fs/xfs/scrub/ialloc.c |   56 ++++++++++++++++++++++++++++++++++++++++++++-----
> > >  1 file changed, 50 insertions(+), 6 deletions(-)
> > > 
> > > 
> > > diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
> > > index fd431682db0b..1c6fef9b3799 100644
> > > --- a/fs/xfs/scrub/ialloc.c
> > > +++ b/fs/xfs/scrub/ialloc.c
> > > @@ -265,6 +265,53 @@ xchk_iallocbt_check_freemask(
> > >  	return error;
> > >  }
> > >  
> > > +/*
> > > + * Make sure this inode btree record is aligned properly.  Because a fs block
> > > + * contains multiple inodes, we check that the inobt record is aligned to the
> > > + * correct inode, not just the correct block on disk.  This results in a finer
> > > + * grained corruption check.
> > > + */
> > > +STATIC void
> > > +xchk_iallocbt_rec_alignment(
> > > +	struct xchk_btree		*bs,
> > > +	struct xfs_inobt_rec_incore	*irec)
> > > +{
> > > +	struct xfs_mount		*mp = bs->sc->mp;
> > > +
> > > +	/*
> > > +	 * finobt records have different positioning requirements than inobt
> > > +	 * records: each finobt record must have a corresponding inobt record.
> > > +	 * That is checked in the xref function, so for now we only catch the
> > > +	 * obvious case where the record isn't at all aligned properly.
> > > +	 *
> > > +	 * Note that if a fs block contains more than a single chunk of inodes,
> > > +	 * we will have finobt records only for those chunks containing free
> > > +	 * inodes, and therefore expect chunk alignment of finobt records.
> > > +	 * Otherwise, we expect that the finobt record is aligned to the
> > > +	 * cluster alignment as told by the superblock.
> > > +	 */
> > > +	if (bs->cur->bc_btnum == XFS_BTNUM_FINO) {
> > > +		unsigned int	imask;
> > > +
> > > +		imask = min_t(unsigned int, XFS_INODES_PER_CHUNK,
> > > +				mp->m_cluster_align_inodes) - 1;
> > > +		if (irec->ir_startino & imask)
> > > +			xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > > +		return;
> > > +	}
> > > +
> > 
> > Don't we also need this large FSB alignment fixup for inobt records, or
> > am I still confused? :/ I.e., if ->m_cluster_align_inodes is 128 and
> > irec is the second inobt record in a block..
> 
> The logic added in the next patch checks that either an inobt record is
> aligned to m_cluster_align_inodes, or that the record covers inodes that
> are immediately after the previous inobt record.  In theory that should
> fix our handling of the large FSB case, though I've only tested it on
> qemu arm boxen.
> 

Ah right, that comes later. Thanks...

Reviewed-by: Brian Foster <bfoster@redhat.com>

> --D
> 
> > Brian
> > 
> > > +	/* inobt records must be aligned to cluster and inoalignmnt size. */
> > > +	if (irec->ir_startino & (mp->m_cluster_align_inodes - 1)) {
> > > +		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > > +		return;
> > > +	}
> > > +
> > > +	if (irec->ir_startino & (mp->m_inodes_per_cluster - 1)) {
> > > +		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > > +		return;
> > > +	}
> > > +}
> > > +
> > >  /* Scrub an inobt/finobt record. */
> > >  STATIC int
> > >  xchk_iallocbt_rec(
> > > @@ -277,7 +324,6 @@ xchk_iallocbt_rec(
> > >  	uint64_t			holes;
> > >  	xfs_agnumber_t			agno = bs->cur->bc_private.a.agno;
> > >  	xfs_agino_t			agino;
> > > -	xfs_agblock_t			agbno;
> > >  	xfs_extlen_t			len;
> > >  	int				holecount;
> > >  	int				i;
> > > @@ -304,11 +350,9 @@ xchk_iallocbt_rec(
> > >  		goto out;
> > >  	}
> > >  
> > > -	/* Make sure this record is aligned to cluster and inoalignmnt size. */
> > > -	agbno = XFS_AGINO_TO_AGBNO(mp, irec.ir_startino);
> > > -	if ((agbno & (mp->m_cluster_align - 1)) ||
> > > -	    (agbno & (mp->m_blocks_per_cluster - 1)))
> > > -		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
> > > +	xchk_iallocbt_rec_alignment(bs, &irec);
> > > +	if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
> > > +		goto out;
> > >  
> > >  	iabt->inodes += irec.ir_count;
> > >  
> > > 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2019-01-09 16:48 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-08 20:32 [PATCH v2 0/7] xfs: inode scrubber fixes Darrick J. Wong
2019-01-08 20:32 ` [PATCH 1/7] xfs: never try to scrub more than 64 inodes per inobt record Darrick J. Wong
2019-01-08 20:32 ` [PATCH 2/7] xfs: check the ir_startino alignment directly Darrick J. Wong
2019-01-09 13:32   ` Brian Foster
2019-01-09 16:37     ` Darrick J. Wong
2019-01-09 16:48       ` Brian Foster
2019-01-08 20:32 ` [PATCH 3/7] xfs: check inobt record alignment on big block filesystems Darrick J. Wong
2019-01-08 20:33 ` [PATCH 4/7] xfs: hoist inode cluster checks out of loop Darrick J. Wong
2019-01-08 20:33 ` [PATCH 5/7] xfs: clean up the inode cluster checking in the inobt scrub Darrick J. Wong
2019-01-08 20:33 ` [PATCH 6/7] xfs: scrub big block inode btrees correctly Darrick J. Wong
2019-01-09 13:32   ` Brian Foster
2019-01-08 20:33 ` [PATCH 7/7] xfs: consolidate scrub dinode mapping code into a single function Darrick J. Wong
2019-01-09 13:33   ` Brian Foster

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.