All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: darrick.wong@oracle.com
Cc: linux-xfs@vger.kernel.org
Subject: [PATCH 15/16] xfs: cross-reference the block mappings when possible
Date: Fri, 11 Aug 2017 00:11:47 -0700	[thread overview]
Message-ID: <150243550695.29473.2019252707151205272.stgit@magnolia> (raw)
In-Reply-To: <150243541274.29473.1227559008347544526.stgit@magnolia>

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

Use an inode's block mappings to cross-reference inode block counters
and (if possible) cross reference rmapbt records against the bmbt to
ensure that the bmbt isn't missing any records.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/scrub/inode.c |   63 +++++++++++++++++++
 fs/xfs/scrub/rmap.c  |  162 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 224 insertions(+), 1 deletion(-)


diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index 9a689cc..67c9366 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -38,6 +38,8 @@
 #include "xfs_trans_priv.h"
 #include "xfs_reflink.h"
 #include "xfs_rmap.h"
+#include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
@@ -122,6 +124,62 @@ xfs_scrub_inode_xref_rmap(
 	return error;
 }
 
+/* Cross reference the inode fields with the forks. */
+STATIC void
+xfs_scrub_inode_xref_bmap(
+	struct xfs_scrub_context	*sc,
+	struct xfs_dinode		*dip,
+	uint16_t			mode,
+	uint16_t			flags)
+{
+	struct xfs_bmbt_irec		got;
+	struct xfs_ifork		*ifp;
+	struct xfs_mount		*mp = sc->mp;
+	xfs_fileoff_t			lblk;
+	xfs_extnum_t			idx;
+	xfs_extnum_t			nextents;
+	xfs_filblks_t			count;
+	xfs_filblks_t			acount;
+	bool				found;
+	int				error;
+
+	/* Walk all the extents to check nextents/naextents/nblocks. */
+	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_DATA_FORK,
+			&nextents, &count);
+	if (!xfs_scrub_should_xref(sc, &error, NULL))
+		return;
+	xfs_scrub_ino_xref_check_ok(sc, sc->ip->i_ino, NULL,
+			nextents >= be32_to_cpu(dip->di_nextents));
+
+	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
+			&nextents, &acount);
+	if (!xfs_scrub_should_xref(sc, &error, NULL))
+		return;
+	xfs_scrub_ino_xref_check_ok(sc, sc->ip->i_ino, NULL,
+			nextents == be16_to_cpu(dip->di_anextents));
+
+	/* Check nblocks against the inode. */
+	xfs_scrub_ino_xref_check_ok(sc, sc->ip->i_ino, NULL,
+			count + acount == be64_to_cpu(dip->di_nblocks));
+
+	/* Make sure we don't have any written extents after EOF. */
+	if (S_ISREG(mode) && !(flags & XFS_DIFLAG_PREALLOC) &&
+	    (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
+	     dip->di_format == XFS_DINODE_FMT_BTREE)) {
+		lblk = XFS_B_TO_FSB(mp, i_size_read(VFS_I(sc->ip)));
+		ifp = XFS_IFORK_PTR(sc->ip, XFS_DATA_FORK);
+		found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &idx, &got);
+		while (found) {
+			xfs_scrub_fblock_xref_check_ok(sc, XFS_DATA_FORK,
+					got.br_startoff,
+					got.br_startoff < lblk ||
+					got.br_state != XFS_EXT_NORM);
+			lblk = got.br_startoff + got.br_blockcount;
+			found = xfs_iext_get_extent(ifp, ++idx, &got);
+		}
+	}
+}
+
 /* Scrub an inode. */
 int
 xfs_scrub_inode(
@@ -136,7 +194,7 @@ xfs_scrub_inode(
 	size_t				fork_recs;
 	unsigned long long		isize;
 	uint64_t			flags2;
-	uint32_t			nextents;
+	xfs_extnum_t			nextents;
 	uint32_t			extsize;
 	uint32_t			cowextsize;
 	uint16_t			flags;
@@ -371,6 +429,9 @@ xfs_scrub_inode(
 			goto out;
 	}
 
+	/* Cross reference the inode fields with the forks. */
+	xfs_scrub_inode_xref_bmap(sc, dip, mode, flags);
+
 out:
 	if (bp)
 		xfs_trans_brelse(sc->tp, bp);
diff --git a/fs/xfs/scrub/rmap.c b/fs/xfs/scrub/rmap.c
index c11401b..e3129ed 100644
--- a/fs/xfs/scrub/rmap.c
+++ b/fs/xfs/scrub/rmap.c
@@ -29,9 +29,12 @@
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
 #include "xfs_rmap.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
+#include "xfs_bmap_btree.h"
 #include "xfs_refcount.h"
 #include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
@@ -112,6 +115,161 @@ xfs_scrub_rmapbt_xref_refc(
 			crec.rc_refcount == 1);
 }
 
+struct xfs_scrub_rmapbt_xref_bmbt {
+	xfs_fsblock_t		fsb;
+	xfs_extlen_t		len;
+};
+
+/* Is this the bmbt block we're looking for? */
+STATIC int
+xfs_scrub_rmapbt_xref_bmap_find_bmbt_block(
+	struct xfs_btree_cur	*cur,
+	int			level,
+	void			*data)
+{
+	struct xfs_buf		*bp;
+	struct xfs_scrub_rmapbt_xref_bmbt	*x = data;
+	xfs_fsblock_t		fsb;
+
+	xfs_btree_get_block(cur, level, &bp);
+	if (!bp)
+		return 0;
+
+	fsb = XFS_DADDR_TO_FSB(cur->bc_mp, bp->b_bn);
+	if (fsb >= x->fsb && fsb < x->fsb + x->len)
+		return XFS_BTREE_QUERY_RANGE_ABORT;
+	return 0;
+}
+
+/* Try to find a matching bmap extent for this inode data/attr fork rmap. */
+STATIC void
+xfs_scrub_rmapbt_xref_bmap(
+	struct xfs_scrub_btree	*bs,
+	struct xfs_rmap_irec	*irec,
+	bool			is_attr,
+	bool			is_bmbt,
+	bool			is_unwritten)
+{
+	struct xfs_scrub_rmapbt_xref_bmbt	x;
+	struct xfs_bmbt_irec	got;
+	struct xfs_inode	*ip;
+	struct xfs_ifork	*ifp;
+	struct xfs_btree_cur	*cur;
+	xfs_fileoff_t		off;
+	xfs_fileoff_t		endoff;
+	xfs_fsblock_t		fsb;
+	xfs_extnum_t		idx;
+	xfs_agnumber_t		agno;
+	uint			lockflags;
+	bool			found;
+	int			whichfork;
+	int			error;
+	uint8_t			fmt;
+
+	fsb = XFS_AGB_TO_FSB(bs->sc->mp, bs->sc->sa.agno, irec->rm_startblock);
+
+	/*
+	 * We can't access the AGI of a lower AG due to locking rules,
+	 * so skip this check if inodes aren't aligned and the inode is
+	 * in a lower AG.
+	 */
+	agno = XFS_INO_TO_AGNO(bs->sc->mp, irec->rm_owner);
+	if (!xfs_scrub_check_thoroughness(bs->sc,
+			bs->sc->mp->m_inoalign_mask != 0 ||
+			agno >= bs->sc->sa.agno))
+		return;
+
+	/* Grab the inode. */
+	error = xfs_iget(bs->sc->mp, bs->sc->tp, irec->rm_owner, 0, 0, &ip);
+	if (!xfs_scrub_should_xref(bs->sc, &error, NULL))
+		return;
+
+	whichfork = is_attr ? XFS_ATTR_FORK : XFS_DATA_FORK;
+	ifp = XFS_IFORK_PTR(ip, whichfork);
+	lockflags = XFS_IOLOCK_SHARED | XFS_MMAPLOCK_SHARED | XFS_ILOCK_SHARED;
+
+lock_again:
+	/*
+	 * Try to grab the inode lock.  We cannot block here because the
+	 * usual XFS locking order is inode -> AGF, whereas here we have
+	 * the AGF but want an inode.  Blocking here could result in
+	 * deadlock, so we'll take an incomplete check over that.
+	 */
+	if (!xfs_ilock_nowait(ip, lockflags))
+		goto out_rele;
+
+	/* Inode had better have extent maps. */
+	fmt = XFS_IFORK_FORMAT(ip, whichfork);
+	if (!xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+			ifp != NULL &&
+			(fmt == XFS_DINODE_FMT_BTREE ||
+			 fmt == XFS_DINODE_FMT_EXTENTS)))
+		goto out_unlock;
+
+	/* If we haven't loaded the extent list, try to relock with excl. */
+	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+		if (!(lockflags & XFS_ILOCK_EXCL)) {
+			xfs_iunlock(ip, lockflags);
+			lockflags |= XFS_ILOCK_EXCL;
+			lockflags &= ~XFS_ILOCK_SHARED;
+			goto lock_again;
+		}
+		error = xfs_iread_extents(bs->sc->tp, ip, whichfork);
+		if (error)
+			goto out_unlock;
+	}
+
+	/* If this is a bmbt record, see if we can find it. */
+	if (is_bmbt) {
+		x.fsb = fsb;
+		x.len = irec->rm_blockcount;
+		cur = xfs_bmbt_init_cursor(bs->sc->mp, bs->sc->tp, ip,
+				whichfork);
+		error = xfs_btree_visit_blocks(cur,
+				xfs_scrub_rmapbt_xref_bmap_find_bmbt_block,
+				&x);
+		xfs_scrub_btree_xref_check_ok(bs->sc, cur, 0,
+				error == XFS_BTREE_QUERY_RANGE_ABORT);
+		xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR :
+				XFS_BTREE_NOERROR);
+		goto out_unlock;
+	}
+
+	/* Now go make sure we find a bmap extent to cover this rmap. */
+	off = irec->rm_offset;
+	endoff = irec->rm_offset + irec->rm_blockcount - 1;
+	found = xfs_iext_lookup_extent(ip, ifp, off, &idx, &got);
+	xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0, found);
+	while (found) {
+		if (!xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+				got.br_startoff <= off &&
+				got.br_startoff <= endoff))
+			goto out_unlock;
+		xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+				(got.br_state == XFS_EXT_NORM ||
+				 is_unwritten) &&
+				(got.br_state == XFS_EXT_UNWRITTEN ||
+				 !is_unwritten) &&
+				got.br_startblock + (off - got.br_startoff) ==
+				fsb);
+
+		off = got.br_startoff + got.br_blockcount;
+		fsb = got.br_startblock + got.br_blockcount;
+		if (off >= endoff)
+			break;
+		found = xfs_iext_get_extent(ifp, ++idx, &got);
+		xfs_scrub_btree_xref_check_ok(bs->sc, bs->cur, 0,
+				found &&
+				got.br_startoff == off &&
+				got.br_startblock == fsb);
+	}
+
+out_unlock:
+	xfs_iunlock(ip, lockflags);
+out_rele:
+	iput(VFS_I(ip));
+}
+
 /* Scrub an rmapbt record. */
 STATIC int
 xfs_scrub_rmapbt_helper(
@@ -223,6 +381,10 @@ xfs_scrub_rmapbt_helper(
 		xfs_scrub_rmapbt_xref_refc(bs, &irec, non_inode, is_attr,
 				is_bmbt, is_unwritten);
 
+	/* Cross-reference with an inode's bmbt if possible. */
+	if (!non_inode)
+		xfs_scrub_rmapbt_xref_bmap(bs, &irec, is_attr, is_bmbt,
+				is_unwritten);
 out:
 	return error;
 }


  parent reply	other threads:[~2017-08-11  7:11 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-11  7:10 [PATCH v9 00/16] xfs: online scrub xref support Darrick J. Wong
2017-08-11  7:10 ` [PATCH 01/16] xfs: add scrub cross-referencing helpers for the free space btrees Darrick J. Wong
2017-08-11  7:10 ` [PATCH 02/16] xfs: add scrub cross-referencing helpers for the inode btrees Darrick J. Wong
2017-08-11  7:10 ` [PATCH 03/16] xfs: add scrub cross-referencing helpers for the rmap btrees Darrick J. Wong
2017-08-11  7:10 ` [PATCH 04/16] xfs: add scrub cross-referencing helpers for the refcount btrees Darrick J. Wong
2017-08-11  7:10 ` [PATCH 05/16] xfs: set up scrub cross-referencing helpers Darrick J. Wong
2017-08-11  7:10 ` [PATCH 06/16] xfs: check btree block ownership with bnobt/rmapbt when scrubbing btree Darrick J. Wong
2017-08-11  7:10 ` [PATCH 07/16] xfs: scrub should cross-reference with the bnobt Darrick J. Wong
2017-08-11  7:11 ` [PATCH 08/16] xfs: cross-reference bnobt records with cntbt Darrick J. Wong
2017-08-11  7:11 ` [PATCH 09/16] xfs: cross-reference extents with AG header Darrick J. Wong
2017-08-11  7:11 ` [PATCH 10/16] xfs: cross-reference inode btrees during scrub Darrick J. Wong
2017-08-11  7:11 ` [PATCH 11/16] xfs: cross-reference reverse-mapping btree Darrick J. Wong
2017-08-11  7:11 ` [PATCH 12/16] xfs: cross-reference the rmapbt data with the refcountbt Darrick J. Wong
2017-08-11  7:11 ` [PATCH 13/16] xfs: cross-reference refcount btree during scrub Darrick J. Wong
2017-08-11  7:11 ` [PATCH 14/16] xfs: scrub should cross-reference the realtime bitmap Darrick J. Wong
2017-08-11  7:11 ` Darrick J. Wong [this message]
2017-08-11  7:11 ` [PATCH 16/16] xfs: shut off scrub-related error and corruption messages Darrick J. Wong
2017-11-29  1:25 [PATCH v10 00/16] xfs: online scrub xref support Darrick J. Wong
2017-11-29  1:26 ` [PATCH 15/16] xfs: cross-reference the block mappings when possible Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=150243550695.29473.2019252707151205272.stgit@magnolia \
    --to=darrick.wong@oracle.com \
    --cc=linux-xfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.