diff mbox series

[3/9] xfs: report block map corruption errors to the health tracking system

Message ID 157375557349.3692735.15868119551132443897.stgit@magnolia (mailing list archive)
State Superseded
Headers show
Series xfs: report corruption to the health trackers | expand

Commit Message

Darrick J. Wong Nov. 14, 2019, 6:19 p.m. UTC
From: Darrick J. Wong <darrick.wong@oracle.com>

Whenever we encounter a corrupt block mapping, we should report that to
the health monitoring system for later reporting.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_bmap.c   |   39 +++++++++++++++++++++++++++++++++------
 fs/xfs/libxfs/xfs_health.h |    1 +
 fs/xfs/xfs_health.c        |   26 ++++++++++++++++++++++++++
 fs/xfs/xfs_iomap.c         |   15 +++++++++++----
 4 files changed, 71 insertions(+), 10 deletions(-)

Comments

Brian Foster Nov. 20, 2019, 2:21 p.m. UTC | #1
On Thu, Nov 14, 2019 at 10:19:33AM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Whenever we encounter a corrupt block mapping, we should report that to
> the health monitoring system for later reporting.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_bmap.c   |   39 +++++++++++++++++++++++++++++++++------
>  fs/xfs/libxfs/xfs_health.h |    1 +
>  fs/xfs/xfs_health.c        |   26 ++++++++++++++++++++++++++
>  fs/xfs/xfs_iomap.c         |   15 +++++++++++----
>  4 files changed, 71 insertions(+), 10 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 4acc6e37c31d..c4674fb0bfb4 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -35,7 +35,7 @@
>  #include "xfs_refcount.h"
>  #include "xfs_icache.h"
>  #include "xfs_iomap.h"
> -
> +#include "xfs_health.h"
>  
>  kmem_zone_t		*xfs_bmap_free_item_zone;
>  
> @@ -732,6 +732,7 @@ xfs_bmap_extents_to_btree(
>  	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
>  	abp = xfs_btree_get_bufl(mp, tp, args.fsbno);
>  	if (XFS_IS_CORRUPT(mp, !abp)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		error = -EFSCORRUPTED;
>  		goto out_unreserve_dquot;
>  	}
> @@ -1021,6 +1022,7 @@ xfs_bmap_add_attrfork_local(
>  
>  	/* should only be called for types that support local format data */
>  	ASSERT(0);
> +	xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
>  	return -EFSCORRUPTED;
>  }

Is it really the attr fork that's corrupt if we get here?

>  
> @@ -1090,6 +1092,7 @@ xfs_bmap_add_attrfork(
>  	if (XFS_IFORK_Q(ip))
>  		goto trans_cancel;
>  	if (XFS_IS_CORRUPT(mp, ip->i_d.di_anextents != 0)) {
> +		xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);

Similar question here given we haven't added the fork yet. di_anextents
is at least related I suppose, but it's not clear that
scrubbing/repairing the attr fork is what needs to happen.

>  		error = -EFSCORRUPTED;
>  		goto trans_cancel;
>  	}
...
> @@ -1239,6 +1244,7 @@ xfs_iread_extents(
>  	if (XFS_IS_CORRUPT(mp,
>  			   XFS_IFORK_FORMAT(ip, whichfork) !=
>  			   XFS_DINODE_FMT_BTREE)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		error = -EFSCORRUPTED;
>  		goto out;
>  	}
> @@ -1254,6 +1260,7 @@ xfs_iread_extents(
>  
>  	if (XFS_IS_CORRUPT(mp,
>  			   ir.loaded != XFS_IFORK_NEXTENTS(ip, whichfork))) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		error = -EFSCORRUPTED;
>  		goto out;
>  	}
> @@ -1262,6 +1269,8 @@ xfs_iread_extents(
>  	ifp->if_flags |= XFS_IFEXTENTS;
>  	return 0;
>  out:
> +	if (xfs_metadata_is_sick(error))
> +		xfs_bmap_mark_sick(ip, whichfork);
>  	xfs_iext_destroy(ifp);
>  	return error;
>  }

Duplicate calls in xfs_iread_extents()?

Brian

> @@ -1344,6 +1353,7 @@ xfs_bmap_last_before(
>  		break;
>  	default:
>  		ASSERT(0);
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -1443,8 +1453,11 @@ xfs_bmap_last_offset(
>  	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL)
>  		return 0;
>  
> -	if (XFS_IS_CORRUPT(ip->i_mount, !xfs_ifork_has_extents(ip, whichfork)))
> +	if (XFS_IS_CORRUPT(ip->i_mount,
> +	    !xfs_ifork_has_extents(ip, whichfork))) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
>  	if (error || is_empty)
> @@ -3905,6 +3918,7 @@ xfs_bmapi_read(
>  
>  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
>  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -3935,6 +3949,7 @@ xfs_bmapi_read(
>  		xfs_alert(mp, "%s: inode %llu missing fork %d",
>  				__func__, ip->i_ino, whichfork);
>  #endif /* DEBUG */
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -4414,6 +4429,7 @@ xfs_bmapi_write(
>  
>  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
>  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -4621,9 +4637,11 @@ xfs_bmapi_convert_delalloc(
>  	error = -ENOSPC;
>  	if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK))
>  		goto out_finish;
> -	error = -EFSCORRUPTED;
> -	if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock)))
> +	if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock))) {
> +		xfs_bmap_mark_sick(ip, whichfork);
> +		error = -EFSCORRUPTED;
>  		goto out_finish;
> +	}
>  
>  	XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, bma.length));
>  	XFS_STATS_INC(mp, xs_xstrat_quick);
> @@ -4681,6 +4699,7 @@ xfs_bmapi_remap(
>  
>  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
>  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -5319,8 +5338,10 @@ __xfs_bunmapi(
>  	whichfork = xfs_bmapi_whichfork(flags);
>  	ASSERT(whichfork != XFS_COW_FORK);
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
> -	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)))
> +	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork))) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
> +	}
>  	if (XFS_FORCED_SHUTDOWN(mp))
>  		return -EIO;
>  
> @@ -5815,6 +5836,7 @@ xfs_bmap_collapse_extents(
>  
>  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
>  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -5932,6 +5954,7 @@ xfs_bmap_insert_extents(
>  
>  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
>  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -6038,6 +6061,7 @@ xfs_bmap_split_extent_at(
>  
>  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
>  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
>  	}
>  
> @@ -6253,8 +6277,10 @@ xfs_bmap_finish_one(
>  			XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
>  			ip->i_ino, whichfork, startoff, *blockcount, state);
>  
> -	if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK))
> +	if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK)) {
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		return -EFSCORRUPTED;
> +	}
>  
>  	if (XFS_TEST_ERROR(false, tp->t_mountp,
>  			XFS_ERRTAG_BMAP_FINISH_ONE))
> @@ -6272,6 +6298,7 @@ xfs_bmap_finish_one(
>  		break;
>  	default:
>  		ASSERT(0);
> +		xfs_bmap_mark_sick(ip, whichfork);
>  		error = -EFSCORRUPTED;
>  	}
>  
> diff --git a/fs/xfs/libxfs/xfs_health.h b/fs/xfs/libxfs/xfs_health.h
> index ce8954a10c66..25b61180b562 100644
> --- a/fs/xfs/libxfs/xfs_health.h
> +++ b/fs/xfs/libxfs/xfs_health.h
> @@ -138,6 +138,7 @@ void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick,
>  		unsigned int *checked);
>  
>  void xfs_health_unmount(struct xfs_mount *mp);
> +void xfs_bmap_mark_sick(struct xfs_inode *ip, int whichfork);
>  
>  /* Now some helpers. */
>  
> diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
> index 36c32b108b39..5e5de5338476 100644
> --- a/fs/xfs/xfs_health.c
> +++ b/fs/xfs/xfs_health.c
> @@ -452,3 +452,29 @@ xfs_bulkstat_health(
>  			bs->bs_sick |= m->ioctl_mask;
>  	}
>  }
> +
> +/* Mark a block mapping sick. */
> +void
> +xfs_bmap_mark_sick(
> +	struct xfs_inode	*ip,
> +	int			whichfork)
> +{
> +	unsigned int		mask;
> +
> +	switch (whichfork) {
> +	case XFS_DATA_FORK:
> +		mask = XFS_SICK_INO_BMBTD;
> +		break;
> +	case XFS_ATTR_FORK:
> +		mask = XFS_SICK_INO_BMBTA;
> +		break;
> +	case XFS_COW_FORK:
> +		mask = XFS_SICK_INO_BMBTC;
> +		break;
> +	default:
> +		ASSERT(0);
> +		return;
> +	}
> +
> +	xfs_inode_mark_sick(ip, mask);
> +}
> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> index 28e2d1f37267..c1befb899911 100644
> --- a/fs/xfs/xfs_iomap.c
> +++ b/fs/xfs/xfs_iomap.c
> @@ -27,7 +27,7 @@
>  #include "xfs_dquot_item.h"
>  #include "xfs_dquot.h"
>  #include "xfs_reflink.h"
> -
> +#include "xfs_health.h"
>  
>  #define XFS_ALLOC_ALIGN(mp, off) \
>  	(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
> @@ -59,8 +59,10 @@ xfs_bmbt_to_iomap(
>  	struct xfs_mount	*mp = ip->i_mount;
>  	struct xfs_buftarg	*target = xfs_inode_buftarg(ip);
>  
> -	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock)))
> +	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) {
> +		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
>  		return xfs_alert_fsblock_zero(ip, imap);
> +	}
>  
>  	if (imap->br_startblock == HOLESTARTBLOCK) {
>  		iomap->addr = IOMAP_NULL_ADDR;
> @@ -277,8 +279,10 @@ xfs_iomap_write_direct(
>  		goto out_unlock;
>  	}
>  
> -	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock)))
> +	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) {
> +		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
>  		error = xfs_alert_fsblock_zero(ip, imap);
> +	}
>  
>  out_unlock:
>  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> @@ -598,8 +602,10 @@ xfs_iomap_write_unwritten(
>  		if (error)
>  			return error;
>  
> -		if (unlikely(!xfs_valid_startblock(ip, imap.br_startblock)))
> +		if (unlikely(!xfs_valid_startblock(ip, imap.br_startblock))) {
> +			xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
>  			return xfs_alert_fsblock_zero(ip, &imap);
> +		}
>  
>  		if ((numblks_fsb = imap.br_blockcount) == 0) {
>  			/*
> @@ -858,6 +864,7 @@ xfs_buffered_write_iomap_begin(
>  
>  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, XFS_DATA_FORK)) ||
>  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> +		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
>  		error = -EFSCORRUPTED;
>  		goto out_unlock;
>  	}
>
Darrick J. Wong Nov. 20, 2019, 4:57 p.m. UTC | #2
On Wed, Nov 20, 2019 at 09:21:19AM -0500, Brian Foster wrote:
> On Thu, Nov 14, 2019 at 10:19:33AM -0800, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > Whenever we encounter a corrupt block mapping, we should report that to
> > the health monitoring system for later reporting.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  fs/xfs/libxfs/xfs_bmap.c   |   39 +++++++++++++++++++++++++++++++++------
> >  fs/xfs/libxfs/xfs_health.h |    1 +
> >  fs/xfs/xfs_health.c        |   26 ++++++++++++++++++++++++++
> >  fs/xfs/xfs_iomap.c         |   15 +++++++++++----
> >  4 files changed, 71 insertions(+), 10 deletions(-)
> > 
> > 
> > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> > index 4acc6e37c31d..c4674fb0bfb4 100644
> > --- a/fs/xfs/libxfs/xfs_bmap.c
> > +++ b/fs/xfs/libxfs/xfs_bmap.c
> > @@ -35,7 +35,7 @@
> >  #include "xfs_refcount.h"
> >  #include "xfs_icache.h"
> >  #include "xfs_iomap.h"
> > -
> > +#include "xfs_health.h"
> >  
> >  kmem_zone_t		*xfs_bmap_free_item_zone;
> >  
> > @@ -732,6 +732,7 @@ xfs_bmap_extents_to_btree(
> >  	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
> >  	abp = xfs_btree_get_bufl(mp, tp, args.fsbno);
> >  	if (XFS_IS_CORRUPT(mp, !abp)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		error = -EFSCORRUPTED;
> >  		goto out_unreserve_dquot;
> >  	}
> > @@ -1021,6 +1022,7 @@ xfs_bmap_add_attrfork_local(
> >  
> >  	/* should only be called for types that support local format data */
> >  	ASSERT(0);
> > +	xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
> >  	return -EFSCORRUPTED;
> >  }
> 
> Is it really the attr fork that's corrupt if we get here?
> 
> >  
> > @@ -1090,6 +1092,7 @@ xfs_bmap_add_attrfork(
> >  	if (XFS_IFORK_Q(ip))
> >  		goto trans_cancel;
> >  	if (XFS_IS_CORRUPT(mp, ip->i_d.di_anextents != 0)) {
> > +		xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
> 
> Similar question here given we haven't added the fork yet. di_anextents
> is at least related I suppose, but it's not clear that
> scrubbing/repairing the attr fork is what needs to happen.

Hm, you're right, it's scrub/inode*.c that deal with anextents and
aformat, so these ought to mark the inode core sick, not the attr fork.

> >  		error = -EFSCORRUPTED;
> >  		goto trans_cancel;
> >  	}
> ...
> > @@ -1239,6 +1244,7 @@ xfs_iread_extents(
> >  	if (XFS_IS_CORRUPT(mp,
> >  			   XFS_IFORK_FORMAT(ip, whichfork) !=
> >  			   XFS_DINODE_FMT_BTREE)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		error = -EFSCORRUPTED;
> >  		goto out;
> >  	}
> > @@ -1254,6 +1260,7 @@ xfs_iread_extents(
> >  
> >  	if (XFS_IS_CORRUPT(mp,
> >  			   ir.loaded != XFS_IFORK_NEXTENTS(ip, whichfork))) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		error = -EFSCORRUPTED;
> >  		goto out;
> >  	}
> > @@ -1262,6 +1269,8 @@ xfs_iread_extents(
> >  	ifp->if_flags |= XFS_IFEXTENTS;
> >  	return 0;
> >  out:
> > +	if (xfs_metadata_is_sick(error))
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  	xfs_iext_destroy(ifp);
> >  	return error;
> >  }
> 
> Duplicate calls in xfs_iread_extents()?

Oops, yeah.

> Brian
> 
> > @@ -1344,6 +1353,7 @@ xfs_bmap_last_before(
> >  		break;
> >  	default:
> >  		ASSERT(0);
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -1443,8 +1453,11 @@ xfs_bmap_last_offset(
> >  	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL)
> >  		return 0;
> >  
> > -	if (XFS_IS_CORRUPT(ip->i_mount, !xfs_ifork_has_extents(ip, whichfork)))
> > +	if (XFS_IS_CORRUPT(ip->i_mount,
> > +	    !xfs_ifork_has_extents(ip, whichfork))) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> > +	}
> >  
> >  	error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
> >  	if (error || is_empty)
> > @@ -3905,6 +3918,7 @@ xfs_bmapi_read(
> >  
> >  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
> >  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -3935,6 +3949,7 @@ xfs_bmapi_read(
> >  		xfs_alert(mp, "%s: inode %llu missing fork %d",
> >  				__func__, ip->i_ino, whichfork);
> >  #endif /* DEBUG */
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -4414,6 +4429,7 @@ xfs_bmapi_write(
> >  
> >  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
> >  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -4621,9 +4637,11 @@ xfs_bmapi_convert_delalloc(
> >  	error = -ENOSPC;
> >  	if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK))
> >  		goto out_finish;
> > -	error = -EFSCORRUPTED;
> > -	if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock)))
> > +	if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock))) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> > +		error = -EFSCORRUPTED;
> >  		goto out_finish;
> > +	}
> >  
> >  	XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, bma.length));
> >  	XFS_STATS_INC(mp, xs_xstrat_quick);
> > @@ -4681,6 +4699,7 @@ xfs_bmapi_remap(
> >  
> >  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
> >  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -5319,8 +5338,10 @@ __xfs_bunmapi(
> >  	whichfork = xfs_bmapi_whichfork(flags);
> >  	ASSERT(whichfork != XFS_COW_FORK);
> >  	ifp = XFS_IFORK_PTR(ip, whichfork);
> > -	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)))
> > +	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork))) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> > +	}
> >  	if (XFS_FORCED_SHUTDOWN(mp))
> >  		return -EIO;
> >  
> > @@ -5815,6 +5836,7 @@ xfs_bmap_collapse_extents(
> >  
> >  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
> >  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -5932,6 +5954,7 @@ xfs_bmap_insert_extents(
> >  
> >  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
> >  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -6038,6 +6061,7 @@ xfs_bmap_split_extent_at(
> >  
> >  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
> >  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> >  	}
> >  
> > @@ -6253,8 +6277,10 @@ xfs_bmap_finish_one(
> >  			XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
> >  			ip->i_ino, whichfork, startoff, *blockcount, state);
> >  
> > -	if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK))
> > +	if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK)) {
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		return -EFSCORRUPTED;
> > +	}
> >  
> >  	if (XFS_TEST_ERROR(false, tp->t_mountp,
> >  			XFS_ERRTAG_BMAP_FINISH_ONE))
> > @@ -6272,6 +6298,7 @@ xfs_bmap_finish_one(
> >  		break;
> >  	default:
> >  		ASSERT(0);
> > +		xfs_bmap_mark_sick(ip, whichfork);
> >  		error = -EFSCORRUPTED;
> >  	}
> >  
> > diff --git a/fs/xfs/libxfs/xfs_health.h b/fs/xfs/libxfs/xfs_health.h
> > index ce8954a10c66..25b61180b562 100644
> > --- a/fs/xfs/libxfs/xfs_health.h
> > +++ b/fs/xfs/libxfs/xfs_health.h
> > @@ -138,6 +138,7 @@ void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick,
> >  		unsigned int *checked);
> >  
> >  void xfs_health_unmount(struct xfs_mount *mp);
> > +void xfs_bmap_mark_sick(struct xfs_inode *ip, int whichfork);
> >  
> >  /* Now some helpers. */
> >  
> > diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
> > index 36c32b108b39..5e5de5338476 100644
> > --- a/fs/xfs/xfs_health.c
> > +++ b/fs/xfs/xfs_health.c
> > @@ -452,3 +452,29 @@ xfs_bulkstat_health(
> >  			bs->bs_sick |= m->ioctl_mask;
> >  	}
> >  }
> > +
> > +/* Mark a block mapping sick. */
> > +void
> > +xfs_bmap_mark_sick(
> > +	struct xfs_inode	*ip,
> > +	int			whichfork)
> > +{
> > +	unsigned int		mask;
> > +
> > +	switch (whichfork) {
> > +	case XFS_DATA_FORK:
> > +		mask = XFS_SICK_INO_BMBTD;
> > +		break;
> > +	case XFS_ATTR_FORK:
> > +		mask = XFS_SICK_INO_BMBTA;
> > +		break;
> > +	case XFS_COW_FORK:
> > +		mask = XFS_SICK_INO_BMBTC;
> > +		break;
> > +	default:
> > +		ASSERT(0);
> > +		return;
> > +	}
> > +
> > +	xfs_inode_mark_sick(ip, mask);
> > +}
> > diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> > index 28e2d1f37267..c1befb899911 100644
> > --- a/fs/xfs/xfs_iomap.c
> > +++ b/fs/xfs/xfs_iomap.c
> > @@ -27,7 +27,7 @@
> >  #include "xfs_dquot_item.h"
> >  #include "xfs_dquot.h"
> >  #include "xfs_reflink.h"
> > -
> > +#include "xfs_health.h"
> >  
> >  #define XFS_ALLOC_ALIGN(mp, off) \
> >  	(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
> > @@ -59,8 +59,10 @@ xfs_bmbt_to_iomap(
> >  	struct xfs_mount	*mp = ip->i_mount;
> >  	struct xfs_buftarg	*target = xfs_inode_buftarg(ip);
> >  
> > -	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock)))
> > +	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) {
> > +		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
> >  		return xfs_alert_fsblock_zero(ip, imap);
> > +	}
> >  
> >  	if (imap->br_startblock == HOLESTARTBLOCK) {
> >  		iomap->addr = IOMAP_NULL_ADDR;
> > @@ -277,8 +279,10 @@ xfs_iomap_write_direct(
> >  		goto out_unlock;
> >  	}
> >  
> > -	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock)))
> > +	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) {
> > +		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
> >  		error = xfs_alert_fsblock_zero(ip, imap);
> > +	}
> >  
> >  out_unlock:
> >  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> > @@ -598,8 +602,10 @@ xfs_iomap_write_unwritten(
> >  		if (error)
> >  			return error;
> >  
> > -		if (unlikely(!xfs_valid_startblock(ip, imap.br_startblock)))
> > +		if (unlikely(!xfs_valid_startblock(ip, imap.br_startblock))) {
> > +			xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
> >  			return xfs_alert_fsblock_zero(ip, &imap);
> > +		}
> >  
> >  		if ((numblks_fsb = imap.br_blockcount) == 0) {
> >  			/*
> > @@ -858,6 +864,7 @@ xfs_buffered_write_iomap_begin(
> >  
> >  	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, XFS_DATA_FORK)) ||
> >  	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
> > +		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
> >  		error = -EFSCORRUPTED;
> >  		goto out_unlock;
> >  	}
> > 
>
diff mbox series

Patch

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 4acc6e37c31d..c4674fb0bfb4 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -35,7 +35,7 @@ 
 #include "xfs_refcount.h"
 #include "xfs_icache.h"
 #include "xfs_iomap.h"
-
+#include "xfs_health.h"
 
 kmem_zone_t		*xfs_bmap_free_item_zone;
 
@@ -732,6 +732,7 @@  xfs_bmap_extents_to_btree(
 	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
 	abp = xfs_btree_get_bufl(mp, tp, args.fsbno);
 	if (XFS_IS_CORRUPT(mp, !abp)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		error = -EFSCORRUPTED;
 		goto out_unreserve_dquot;
 	}
@@ -1021,6 +1022,7 @@  xfs_bmap_add_attrfork_local(
 
 	/* should only be called for types that support local format data */
 	ASSERT(0);
+	xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
 	return -EFSCORRUPTED;
 }
 
@@ -1090,6 +1092,7 @@  xfs_bmap_add_attrfork(
 	if (XFS_IFORK_Q(ip))
 		goto trans_cancel;
 	if (XFS_IS_CORRUPT(mp, ip->i_d.di_anextents != 0)) {
+		xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
 		error = -EFSCORRUPTED;
 		goto trans_cancel;
 	}
@@ -1192,6 +1195,7 @@  xfs_iread_bmbt_block(
 				(unsigned long long)ip->i_ino);
 		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block,
 				sizeof(*block), __this_address);
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -1207,6 +1211,7 @@  xfs_iread_bmbt_block(
 			xfs_inode_verifier_error(ip, -EFSCORRUPTED,
 					"xfs_iread_extents(2)", frp,
 					sizeof(*frp), fa);
+			xfs_bmap_mark_sick(ip, whichfork);
 			return -EFSCORRUPTED;
 		}
 		xfs_iext_insert(ip, &ir->icur, &new,
@@ -1239,6 +1244,7 @@  xfs_iread_extents(
 	if (XFS_IS_CORRUPT(mp,
 			   XFS_IFORK_FORMAT(ip, whichfork) !=
 			   XFS_DINODE_FMT_BTREE)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		error = -EFSCORRUPTED;
 		goto out;
 	}
@@ -1254,6 +1260,7 @@  xfs_iread_extents(
 
 	if (XFS_IS_CORRUPT(mp,
 			   ir.loaded != XFS_IFORK_NEXTENTS(ip, whichfork))) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		error = -EFSCORRUPTED;
 		goto out;
 	}
@@ -1262,6 +1269,8 @@  xfs_iread_extents(
 	ifp->if_flags |= XFS_IFEXTENTS;
 	return 0;
 out:
+	if (xfs_metadata_is_sick(error))
+		xfs_bmap_mark_sick(ip, whichfork);
 	xfs_iext_destroy(ifp);
 	return error;
 }
@@ -1344,6 +1353,7 @@  xfs_bmap_last_before(
 		break;
 	default:
 		ASSERT(0);
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -1443,8 +1453,11 @@  xfs_bmap_last_offset(
 	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL)
 		return 0;
 
-	if (XFS_IS_CORRUPT(ip->i_mount, !xfs_ifork_has_extents(ip, whichfork)))
+	if (XFS_IS_CORRUPT(ip->i_mount,
+	    !xfs_ifork_has_extents(ip, whichfork))) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
+	}
 
 	error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
 	if (error || is_empty)
@@ -3905,6 +3918,7 @@  xfs_bmapi_read(
 
 	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -3935,6 +3949,7 @@  xfs_bmapi_read(
 		xfs_alert(mp, "%s: inode %llu missing fork %d",
 				__func__, ip->i_ino, whichfork);
 #endif /* DEBUG */
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -4414,6 +4429,7 @@  xfs_bmapi_write(
 
 	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -4621,9 +4637,11 @@  xfs_bmapi_convert_delalloc(
 	error = -ENOSPC;
 	if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK))
 		goto out_finish;
-	error = -EFSCORRUPTED;
-	if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock)))
+	if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock))) {
+		xfs_bmap_mark_sick(ip, whichfork);
+		error = -EFSCORRUPTED;
 		goto out_finish;
+	}
 
 	XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, bma.length));
 	XFS_STATS_INC(mp, xs_xstrat_quick);
@@ -4681,6 +4699,7 @@  xfs_bmapi_remap(
 
 	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -5319,8 +5338,10 @@  __xfs_bunmapi(
 	whichfork = xfs_bmapi_whichfork(flags);
 	ASSERT(whichfork != XFS_COW_FORK);
 	ifp = XFS_IFORK_PTR(ip, whichfork);
-	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)))
+	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork))) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
+	}
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return -EIO;
 
@@ -5815,6 +5836,7 @@  xfs_bmap_collapse_extents(
 
 	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -5932,6 +5954,7 @@  xfs_bmap_insert_extents(
 
 	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -6038,6 +6061,7 @@  xfs_bmap_split_extent_at(
 
 	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, whichfork)) ||
 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
 	}
 
@@ -6253,8 +6277,10 @@  xfs_bmap_finish_one(
 			XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
 			ip->i_ino, whichfork, startoff, *blockcount, state);
 
-	if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK))
+	if (WARN_ON_ONCE(whichfork != XFS_DATA_FORK)) {
+		xfs_bmap_mark_sick(ip, whichfork);
 		return -EFSCORRUPTED;
+	}
 
 	if (XFS_TEST_ERROR(false, tp->t_mountp,
 			XFS_ERRTAG_BMAP_FINISH_ONE))
@@ -6272,6 +6298,7 @@  xfs_bmap_finish_one(
 		break;
 	default:
 		ASSERT(0);
+		xfs_bmap_mark_sick(ip, whichfork);
 		error = -EFSCORRUPTED;
 	}
 
diff --git a/fs/xfs/libxfs/xfs_health.h b/fs/xfs/libxfs/xfs_health.h
index ce8954a10c66..25b61180b562 100644
--- a/fs/xfs/libxfs/xfs_health.h
+++ b/fs/xfs/libxfs/xfs_health.h
@@ -138,6 +138,7 @@  void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick,
 		unsigned int *checked);
 
 void xfs_health_unmount(struct xfs_mount *mp);
+void xfs_bmap_mark_sick(struct xfs_inode *ip, int whichfork);
 
 /* Now some helpers. */
 
diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
index 36c32b108b39..5e5de5338476 100644
--- a/fs/xfs/xfs_health.c
+++ b/fs/xfs/xfs_health.c
@@ -452,3 +452,29 @@  xfs_bulkstat_health(
 			bs->bs_sick |= m->ioctl_mask;
 	}
 }
+
+/* Mark a block mapping sick. */
+void
+xfs_bmap_mark_sick(
+	struct xfs_inode	*ip,
+	int			whichfork)
+{
+	unsigned int		mask;
+
+	switch (whichfork) {
+	case XFS_DATA_FORK:
+		mask = XFS_SICK_INO_BMBTD;
+		break;
+	case XFS_ATTR_FORK:
+		mask = XFS_SICK_INO_BMBTA;
+		break;
+	case XFS_COW_FORK:
+		mask = XFS_SICK_INO_BMBTC;
+		break;
+	default:
+		ASSERT(0);
+		return;
+	}
+
+	xfs_inode_mark_sick(ip, mask);
+}
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 28e2d1f37267..c1befb899911 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -27,7 +27,7 @@ 
 #include "xfs_dquot_item.h"
 #include "xfs_dquot.h"
 #include "xfs_reflink.h"
-
+#include "xfs_health.h"
 
 #define XFS_ALLOC_ALIGN(mp, off) \
 	(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
@@ -59,8 +59,10 @@  xfs_bmbt_to_iomap(
 	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_buftarg	*target = xfs_inode_buftarg(ip);
 
-	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock)))
+	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) {
+		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
 		return xfs_alert_fsblock_zero(ip, imap);
+	}
 
 	if (imap->br_startblock == HOLESTARTBLOCK) {
 		iomap->addr = IOMAP_NULL_ADDR;
@@ -277,8 +279,10 @@  xfs_iomap_write_direct(
 		goto out_unlock;
 	}
 
-	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock)))
+	if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) {
+		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
 		error = xfs_alert_fsblock_zero(ip, imap);
+	}
 
 out_unlock:
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -598,8 +602,10 @@  xfs_iomap_write_unwritten(
 		if (error)
 			return error;
 
-		if (unlikely(!xfs_valid_startblock(ip, imap.br_startblock)))
+		if (unlikely(!xfs_valid_startblock(ip, imap.br_startblock))) {
+			xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
 			return xfs_alert_fsblock_zero(ip, &imap);
+		}
 
 		if ((numblks_fsb = imap.br_blockcount) == 0) {
 			/*
@@ -858,6 +864,7 @@  xfs_buffered_write_iomap_begin(
 
 	if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ip, XFS_DATA_FORK)) ||
 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+		xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
 		error = -EFSCORRUPTED;
 		goto out_unlock;
 	}