]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: report block map corruption errors to the health tracking system
authorDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:31:51 +0000 (12:31 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:31:51 +0000 (12:31 -0800)
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 <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_health.h
fs/xfs/xfs_health.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_reflink.c

index 68ab22a2a4530a73b8f56a396e7a0afad8d359f8..7e632f13af07390895f9ba1d2cf3297792e7835c 100644 (file)
@@ -36,6 +36,7 @@
 #include "xfs_refcount.h"
 #include "xfs_icache.h"
 #include "xfs_iomap.h"
+#include "xfs_health.h"
 
 struct kmem_cache              *xfs_bmap_intent_cache;
 
@@ -960,6 +961,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;
 }
 
@@ -1143,6 +1145,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;
        }
 
@@ -1158,6 +1161,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 xfs_bmap_complain_bad_rec(ip, whichfork, fa,
                                        &new);
                }
@@ -1213,6 +1217,8 @@ xfs_iread_extents(
        smp_store_release(&ifp->if_needextents, 0);
        return 0;
 out:
+       if (xfs_metadata_is_sick(error))
+               xfs_bmap_mark_sick(ip, whichfork);
        xfs_iext_destroy(ifp);
        return error;
 }
@@ -1292,6 +1298,7 @@ xfs_bmap_last_before(
                break;
        default:
                ASSERT(0);
+               xfs_bmap_mark_sick(ip, whichfork);
                return -EFSCORRUPTED;
        }
 
@@ -3900,12 +3907,16 @@ xfs_bmapi_read(
        ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK | XFS_BMAPI_ENTIRE)));
        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;
+       }
 
        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;
+       }
 
        if (xfs_is_shutdown(mp))
                return -EIO;
@@ -4386,6 +4397,7 @@ xfs_bmapi_write(
 
        if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+               xfs_bmap_mark_sick(ip, whichfork);
                return -EFSCORRUPTED;
        }
 
@@ -4613,9 +4625,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);
@@ -4674,6 +4688,7 @@ xfs_bmapi_remap(
 
        if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+               xfs_bmap_mark_sick(ip, whichfork);
                return -EFSCORRUPTED;
        }
 
@@ -5286,8 +5301,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(ifp)))
+       if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp))) {
+               xfs_bmap_mark_sick(ip, whichfork);
                return -EFSCORRUPTED;
+       }
        if (xfs_is_shutdown(mp))
                return -EIO;
 
@@ -5757,6 +5774,7 @@ xfs_bmap_collapse_extents(
 
        if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+               xfs_bmap_mark_sick(ip, whichfork);
                return -EFSCORRUPTED;
        }
 
@@ -5872,6 +5890,7 @@ xfs_bmap_insert_extents(
 
        if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+               xfs_bmap_mark_sick(ip, whichfork);
                return -EFSCORRUPTED;
        }
 
@@ -5975,6 +5994,7 @@ xfs_bmap_split_extent(
 
        if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(ifp)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+               xfs_bmap_mark_sick(ip, whichfork);
                return -EFSCORRUPTED;
        }
 
@@ -6157,8 +6177,10 @@ xfs_bmap_finish_one(
                        bmap->br_startoff, bmap->br_blockcount,
                        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;
+       }
 
        if (XFS_TEST_ERROR(false, tp->t_mountp,
                        XFS_ERRTAG_BMAP_FINISH_ONE))
@@ -6176,6 +6198,7 @@ xfs_bmap_finish_one(
                break;
        default:
                ASSERT(0);
+               xfs_bmap_mark_sick(bi->bi_owner, bi->bi_whichfork);
                error = -EFSCORRUPTED;
        }
 
index fb3f2b49087de686e1526f5ca323a3df1303beed..3c8fd060744f2c76170b7ab35af72f84f0c08fa6 100644 (file)
@@ -159,6 +159,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. */
 
index 91a29a8610f60ee8a21d5e45e50075589e12bba9..349360a708b48887fa139abdedaa100bb9929f9f 100644 (file)
@@ -481,3 +481,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);
+}
index 055cdec2e9ad6425da57886f6556b7ae38c26f2d..4087af7f3c9f3f39bf9ab078e2b7946cfe4a7187 100644 (file)
@@ -27,6 +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)
@@ -45,6 +46,7 @@ xfs_alert_fsblock_zero(
                (unsigned long long)imap->br_startoff,
                (unsigned long long)imap->br_blockcount,
                imap->br_state);
+       xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
        return -EFSCORRUPTED;
 }
 
@@ -99,8 +101,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;
@@ -325,8 +329,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:
        *seq = xfs_iomap_inode_sequence(ip, 0);
@@ -639,8 +645,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) {
                        /*
@@ -986,6 +994,7 @@ xfs_buffered_write_iomap_begin(
 
        if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(&ip->i_df)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
+               xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
                error = -EFSCORRUPTED;
                goto out_unlock;
        }
index e64ef2a293b69beff953337db549fb81ad90fe2e..cd9a00fd16e7c367acb23b0b9b2ce88b789664e4 100644 (file)
@@ -29,6 +29,7 @@
 #include "xfs_iomap.h"
 #include "xfs_ag.h"
 #include "xfs_ag_resv.h"
+#include "xfs_health.h"
 
 /*
  * Copy on Write of Shared Blocks
@@ -1227,8 +1228,10 @@ xfs_reflink_remap_extent(
         * extent if they're both holes or both the same physical extent.
         */
        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;
+               }
                goto out_cancel;
        }
 
@@ -1391,6 +1394,7 @@ xfs_reflink_remap_blocks(
                ASSERT(nimaps == 1 && imap.br_startoff == srcoff);
                if (imap.br_startblock == DELAYSTARTBLOCK) {
                        ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
+                       xfs_bmap_mark_sick(src, XFS_DATA_FORK);
                        error = -EFSCORRUPTED;
                        break;
                }