Commit 1196f3f5 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: report block map corruption errors to the health tracking system

Whenever we encounter a corrupt block mapping, we should report that to
the health monitoring system for later reporting.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent de6077ec
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "xfs_refcount.h" #include "xfs_refcount.h"
#include "xfs_icache.h" #include "xfs_icache.h"
#include "xfs_iomap.h" #include "xfs_iomap.h"
#include "xfs_health.h"
struct kmem_cache *xfs_bmap_intent_cache; struct kmem_cache *xfs_bmap_intent_cache;
...@@ -960,6 +961,7 @@ xfs_bmap_add_attrfork_local( ...@@ -960,6 +961,7 @@ xfs_bmap_add_attrfork_local(
/* should only be called for types that support local format data */ /* should only be called for types that support local format data */
ASSERT(0); ASSERT(0);
xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -1143,6 +1145,7 @@ xfs_iread_bmbt_block( ...@@ -1143,6 +1145,7 @@ xfs_iread_bmbt_block(
(unsigned long long)ip->i_ino); (unsigned long long)ip->i_ino);
xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block, xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block,
sizeof(*block), __this_address); sizeof(*block), __this_address);
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -1158,6 +1161,7 @@ xfs_iread_bmbt_block( ...@@ -1158,6 +1161,7 @@ xfs_iread_bmbt_block(
xfs_inode_verifier_error(ip, -EFSCORRUPTED, xfs_inode_verifier_error(ip, -EFSCORRUPTED,
"xfs_iread_extents(2)", frp, "xfs_iread_extents(2)", frp,
sizeof(*frp), fa); sizeof(*frp), fa);
xfs_bmap_mark_sick(ip, whichfork);
return xfs_bmap_complain_bad_rec(ip, whichfork, fa, return xfs_bmap_complain_bad_rec(ip, whichfork, fa,
&new); &new);
} }
...@@ -1213,6 +1217,8 @@ xfs_iread_extents( ...@@ -1213,6 +1217,8 @@ xfs_iread_extents(
smp_store_release(&ifp->if_needextents, 0); smp_store_release(&ifp->if_needextents, 0);
return 0; return 0;
out: out:
if (xfs_metadata_is_sick(error))
xfs_bmap_mark_sick(ip, whichfork);
xfs_iext_destroy(ifp); xfs_iext_destroy(ifp);
return error; return error;
} }
...@@ -1292,6 +1298,7 @@ xfs_bmap_last_before( ...@@ -1292,6 +1298,7 @@ xfs_bmap_last_before(
break; break;
default: default:
ASSERT(0); ASSERT(0);
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -3900,12 +3907,16 @@ xfs_bmapi_read( ...@@ -3900,12 +3907,16 @@ xfs_bmapi_read(
ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK | XFS_BMAPI_ENTIRE))); ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK | XFS_BMAPI_ENTIRE)));
xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL); xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
if (WARN_ON_ONCE(!ifp)) if (WARN_ON_ONCE(!ifp)) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
}
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) || if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
}
if (xfs_is_shutdown(mp)) if (xfs_is_shutdown(mp))
return -EIO; return -EIO;
...@@ -4386,6 +4397,7 @@ xfs_bmapi_write( ...@@ -4386,6 +4397,7 @@ xfs_bmapi_write(
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) || if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) { XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -4613,9 +4625,11 @@ xfs_bmapi_convert_delalloc( ...@@ -4613,9 +4625,11 @@ xfs_bmapi_convert_delalloc(
error = -ENOSPC; error = -ENOSPC;
if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK))
goto out_finish; 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; goto out_finish;
}
XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, bma.length)); XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, bma.length));
XFS_STATS_INC(mp, xs_xstrat_quick); XFS_STATS_INC(mp, xs_xstrat_quick);
...@@ -4674,6 +4688,7 @@ xfs_bmapi_remap( ...@@ -4674,6 +4688,7 @@ xfs_bmapi_remap(
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) || if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) { XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -5286,8 +5301,10 @@ __xfs_bunmapi( ...@@ -5286,8 +5301,10 @@ __xfs_bunmapi(
whichfork = xfs_bmapi_whichfork(flags); whichfork = xfs_bmapi_whichfork(flags);
ASSERT(whichfork != XFS_COW_FORK); ASSERT(whichfork != XFS_COW_FORK);
ifp = xfs_ifork_ptr(ip, whichfork); ifp = xfs_ifork_ptr(ip, whichfork);
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp))) if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp))) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
}
if (xfs_is_shutdown(mp)) if (xfs_is_shutdown(mp))
return -EIO; return -EIO;
...@@ -5757,6 +5774,7 @@ xfs_bmap_collapse_extents( ...@@ -5757,6 +5774,7 @@ xfs_bmap_collapse_extents(
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) || if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) { XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -5872,6 +5890,7 @@ xfs_bmap_insert_extents( ...@@ -5872,6 +5890,7 @@ xfs_bmap_insert_extents(
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) || if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) { XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -5975,6 +5994,7 @@ xfs_bmap_split_extent( ...@@ -5975,6 +5994,7 @@ xfs_bmap_split_extent(
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) || if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) { XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -6157,8 +6177,10 @@ xfs_bmap_finish_one( ...@@ -6157,8 +6177,10 @@ xfs_bmap_finish_one(
bmap->br_startoff, bmap->br_blockcount, bmap->br_startoff, bmap->br_blockcount,
bmap->br_state); bmap->br_state);
if (WARN_ON_ONCE(bi->bi_whichfork != XFS_DATA_FORK)) if (WARN_ON_ONCE(bi->bi_whichfork != XFS_DATA_FORK)) {
xfs_bmap_mark_sick(bi->bi_owner, bi->bi_whichfork);
return -EFSCORRUPTED; return -EFSCORRUPTED;
}
if (XFS_TEST_ERROR(false, tp->t_mountp, if (XFS_TEST_ERROR(false, tp->t_mountp,
XFS_ERRTAG_BMAP_FINISH_ONE)) XFS_ERRTAG_BMAP_FINISH_ONE))
...@@ -6176,6 +6198,7 @@ xfs_bmap_finish_one( ...@@ -6176,6 +6198,7 @@ xfs_bmap_finish_one(
break; break;
default: default:
ASSERT(0); ASSERT(0);
xfs_bmap_mark_sick(bi->bi_owner, bi->bi_whichfork);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
} }
......
...@@ -159,6 +159,7 @@ void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick, ...@@ -159,6 +159,7 @@ void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick,
unsigned int *checked); unsigned int *checked);
void xfs_health_unmount(struct xfs_mount *mp); void xfs_health_unmount(struct xfs_mount *mp);
void xfs_bmap_mark_sick(struct xfs_inode *ip, int whichfork);
/* Now some helpers. */ /* Now some helpers. */
......
...@@ -481,3 +481,29 @@ xfs_bulkstat_health( ...@@ -481,3 +481,29 @@ xfs_bulkstat_health(
bs->bs_sick |= m->ioctl_mask; 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);
}
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "xfs_dquot_item.h" #include "xfs_dquot_item.h"
#include "xfs_dquot.h" #include "xfs_dquot.h"
#include "xfs_reflink.h" #include "xfs_reflink.h"
#include "xfs_health.h"
#define XFS_ALLOC_ALIGN(mp, off) \ #define XFS_ALLOC_ALIGN(mp, off) \
(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log) (((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
...@@ -45,6 +46,7 @@ xfs_alert_fsblock_zero( ...@@ -45,6 +46,7 @@ xfs_alert_fsblock_zero(
(unsigned long long)imap->br_startoff, (unsigned long long)imap->br_startoff,
(unsigned long long)imap->br_blockcount, (unsigned long long)imap->br_blockcount,
imap->br_state); imap->br_state);
xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
...@@ -99,8 +101,10 @@ xfs_bmbt_to_iomap( ...@@ -99,8 +101,10 @@ xfs_bmbt_to_iomap(
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
struct xfs_buftarg *target = xfs_inode_buftarg(ip); 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); return xfs_alert_fsblock_zero(ip, imap);
}
if (imap->br_startblock == HOLESTARTBLOCK) { if (imap->br_startblock == HOLESTARTBLOCK) {
iomap->addr = IOMAP_NULL_ADDR; iomap->addr = IOMAP_NULL_ADDR;
...@@ -325,8 +329,10 @@ xfs_iomap_write_direct( ...@@ -325,8 +329,10 @@ xfs_iomap_write_direct(
goto out_unlock; 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); error = xfs_alert_fsblock_zero(ip, imap);
}
out_unlock: out_unlock:
*seq = xfs_iomap_inode_sequence(ip, 0); *seq = xfs_iomap_inode_sequence(ip, 0);
...@@ -639,8 +645,10 @@ xfs_iomap_write_unwritten( ...@@ -639,8 +645,10 @@ xfs_iomap_write_unwritten(
if (error) if (error)
return 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); return xfs_alert_fsblock_zero(ip, &imap);
}
if ((numblks_fsb = imap.br_blockcount) == 0) { if ((numblks_fsb = imap.br_blockcount) == 0) {
/* /*
...@@ -986,6 +994,7 @@ xfs_buffered_write_iomap_begin( ...@@ -986,6 +994,7 @@ xfs_buffered_write_iomap_begin(
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(&ip->i_df)) || if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(&ip->i_df)) ||
XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) { XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto out_unlock; goto out_unlock;
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "xfs_iomap.h" #include "xfs_iomap.h"
#include "xfs_ag.h" #include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
#include "xfs_health.h"
/* /*
* Copy on Write of Shared Blocks * Copy on Write of Shared Blocks
...@@ -1227,8 +1228,10 @@ xfs_reflink_remap_extent( ...@@ -1227,8 +1228,10 @@ xfs_reflink_remap_extent(
* extent if they're both holes or both the same physical extent. * extent if they're both holes or both the same physical extent.
*/ */
if (dmap->br_startblock == smap.br_startblock) { if (dmap->br_startblock == smap.br_startblock) {
if (dmap->br_state != smap.br_state) if (dmap->br_state != smap.br_state) {
xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
}
goto out_cancel; goto out_cancel;
} }
...@@ -1391,6 +1394,7 @@ xfs_reflink_remap_blocks( ...@@ -1391,6 +1394,7 @@ xfs_reflink_remap_blocks(
ASSERT(nimaps == 1 && imap.br_startoff == srcoff); ASSERT(nimaps == 1 && imap.br_startoff == srcoff);
if (imap.br_startblock == DELAYSTARTBLOCK) { if (imap.br_startblock == DELAYSTARTBLOCK) {
ASSERT(imap.br_startblock != DELAYSTARTBLOCK); ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
xfs_bmap_mark_sick(src, XFS_DATA_FORK);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment