On Thu, Nov 14, 2019 at 10:19:33AM -0800, Darrick J. Wong wrote: > From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> > > 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@xxxxxxxxxx> > --- > 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; > } >