]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: report btree block corruption errors to the health system
authorDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:32:09 +0000 (12:32 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:32:09 +0000 (12:32 -0800)
Whenever we encounter corrupt btree blocks, 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_alloc.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_health.h
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_refcount.c
fs/xfs/libxfs/xfs_rmap.c
fs/xfs/xfs_health.c

index 1cb2569c43cfc7d1d0804e39c38942e777712ebf..2464b64b1cb4e31225c199c53bb9289b811bb5b5 100644 (file)
@@ -275,6 +275,7 @@ xfs_alloc_complain_bad_rec(
        xfs_warn(mp,
                "start block 0x%x block count 0x%x", irec->ar_startblock,
                irec->ar_blockcount);
+       xfs_btree_mark_sick(cur);
        return -EFSCORRUPTED;
 }
 
@@ -2702,6 +2703,7 @@ xfs_exact_minlen_extent_available(
                goto out;
 
        if (*stat == 0) {
+               xfs_btree_mark_sick(cnt_cur);
                error = -EFSCORRUPTED;
                goto out;
        }
index 7e632f13af07390895f9ba1d2cf3297792e7835c..78d2d3393a8630f74a26368cdf906ba6f41f240c 100644 (file)
@@ -368,6 +368,8 @@ xfs_bmap_check_leaf_extents(
                        error = xfs_btree_read_bufl(mp, NULL, bno, &bp,
                                                XFS_BMAP_BTREE_REF,
                                                &xfs_bmbt_buf_ops);
+                       if (xfs_metadata_is_sick(error))
+                               xfs_btree_mark_sick(cur);
                        if (error)
                                goto error_norelse;
                }
@@ -454,6 +456,8 @@ xfs_bmap_check_leaf_extents(
                        error = xfs_btree_read_bufl(mp, NULL, bno, &bp,
                                                XFS_BMAP_BTREE_REF,
                                                &xfs_bmbt_buf_ops);
+                       if (xfs_metadata_is_sick(error))
+                               xfs_btree_mark_sick(cur);
                        if (error)
                                goto error_norelse;
                }
@@ -568,6 +572,8 @@ xfs_bmap_btree_to_extents(
 #endif
        error = xfs_btree_read_bufl(mp, tp, cbno, &cbp, XFS_BMAP_BTREE_REF,
                                &xfs_bmbt_buf_ops);
+       if (xfs_metadata_is_sick(error))
+               xfs_btree_mark_sick(cur);
        if (error)
                return error;
        cblock = XFS_BUF_TO_BLOCK(cbp);
index 1adfc35c99c90af4a363525a811b8840e5548c2f..a4784e56b58961c1765822a29d14e0ab4c62f891 100644 (file)
@@ -27,6 +27,7 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_rmap_btree.h"
 #include "xfs_refcount_btree.h"
+#include "xfs_health.h"
 
 /*
  * Btree magic numbers.
@@ -177,6 +178,7 @@ xfs_btree_check_lblock(
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK)) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
+               xfs_btree_mark_sick(cur);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -243,6 +245,7 @@ xfs_btree_check_sblock(
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BTREE_CHECK_SBLOCK)) {
                if (bp)
                        trace_xfs_btree_corrupt(bp, _RET_IP_);
+               xfs_btree_mark_sick(cur);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -318,6 +321,7 @@ xfs_btree_check_ptr(
                                level, index);
        }
 
+       xfs_btree_mark_sick(cur);
        return -EFSCORRUPTED;
 }
 
@@ -498,6 +502,8 @@ xfs_btree_dup_cursor(
                                                   xfs_buf_daddr(bp), mp->m_bsize,
                                                   0, &bp,
                                                   cur->bc_ops->buf_ops);
+                       if (xfs_metadata_is_sick(error))
+                               xfs_btree_mark_sick(new);
                        if (error) {
                                xfs_btree_del_cursor(new, error);
                                *ncur = NULL;
@@ -1351,6 +1357,8 @@ xfs_btree_read_buf_block(
        error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,
                                   mp->m_bsize, flags, bpp,
                                   cur->bc_ops->buf_ops);
+       if (xfs_metadata_is_sick(error))
+               xfs_btree_mark_sick(cur);
        if (error)
                return error;
 
@@ -1661,6 +1669,7 @@ xfs_btree_increment(
                if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
                        goto out0;
                ASSERT(0);
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto error0;
        }
@@ -1754,6 +1763,7 @@ xfs_btree_decrement(
                if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
                        goto out0;
                ASSERT(0);
+               xfs_btree_mark_sick(cur);
                error = -EFSCORRUPTED;
                goto error0;
        }
@@ -1846,6 +1856,7 @@ out_bad:
        *blkp = NULL;
        xfs_buf_mark_corrupt(bp);
        xfs_trans_brelse(cur->bc_tp, bp);
+       xfs_btree_mark_sick(cur);
        return -EFSCORRUPTED;
 }
 
@@ -1892,8 +1903,10 @@ xfs_btree_lookup(
        XFS_BTREE_STATS_INC(cur, lookup);
 
        /* No such thing as a zero-level tree. */
-       if (XFS_IS_CORRUPT(cur->bc_mp, cur->bc_nlevels == 0))
+       if (XFS_IS_CORRUPT(cur->bc_mp, cur->bc_nlevels == 0)) {
+               xfs_btree_mark_sick(cur);
                return -EFSCORRUPTED;
+       }
 
        block = NULL;
        keyno = 0;
@@ -1936,6 +1949,7 @@ xfs_btree_lookup(
                                                        XFS_ERRLEVEL_LOW,
                                                        cur->bc_mp, block,
                                                        sizeof(*block));
+                                       xfs_btree_mark_sick(cur);
                                        return -EFSCORRUPTED;
                                }
 
@@ -4369,12 +4383,16 @@ xfs_btree_visit_block(
         */
        if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
                if (be64_to_cpu(rptr.l) == XFS_DADDR_TO_FSB(cur->bc_mp,
-                                                       xfs_buf_daddr(bp)))
+                                                       xfs_buf_daddr(bp))) {
+                       xfs_btree_mark_sick(cur);
                        return -EFSCORRUPTED;
+               }
        } else {
                if (be32_to_cpu(rptr.s) == xfs_daddr_to_agbno(cur->bc_mp,
-                                                       xfs_buf_daddr(bp)))
+                                                       xfs_buf_daddr(bp))) {
+                       xfs_btree_mark_sick(cur);
                        return -EFSCORRUPTED;
+               }
        }
        return xfs_btree_lookup_get_block(cur, level, &rptr, &block);
 }
@@ -5233,6 +5251,7 @@ xfs_btree_goto_left_edge(
                return error;
        if (stat != 0) {
                ASSERT(0);
+               xfs_btree_mark_sick(cur);
                return -EFSCORRUPTED;
        }
 
index 3c8fd060744f2c76170b7ab35af72f84f0c08fa6..8f566a78737fed838845665522583f48a00264d7 100644 (file)
@@ -37,6 +37,7 @@ struct xfs_mount;
 struct xfs_perag;
 struct xfs_inode;
 struct xfs_fsop_geom;
+struct xfs_btree_cur;
 
 /* Observable health issues for metadata spanning the entire filesystem. */
 #define XFS_SICK_FS_COUNTERS   (1 << 0)  /* summary counters */
@@ -160,6 +161,7 @@ void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick,
 
 void xfs_health_unmount(struct xfs_mount *mp);
 void xfs_bmap_mark_sick(struct xfs_inode *ip, int whichfork);
+void xfs_btree_mark_sick(struct xfs_btree_cur *cur);
 
 /* Now some helpers. */
 
index 2531b4c08915d6fd9b12333b355efefe8eda8c23..91584e96f05f6af1a3d21f52c9be192ba72045e6 100644 (file)
@@ -148,6 +148,7 @@ xfs_inobt_complain_bad_rec(
 "start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x",
                irec->ir_startino, irec->ir_count, irec->ir_freecount,
                irec->ir_free, irec->ir_holemask);
+       xfs_btree_mark_sick(cur);
        return -EFSCORRUPTED;
 }
 
index 7df52daa22cf29ddf27d14abd0eced63064cc817..c7fda1a4950ae98ee24cd79f888f25ffcf82279b 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_refcount.h"
 #include "xfs_rmap.h"
 #include "xfs_ag.h"
+#include "xfs_health.h"
 
 struct kmem_cache      *xfs_refcount_intent_cache;
 
@@ -156,6 +157,7 @@ xfs_refcount_complain_bad_rec(
        xfs_warn(mp,
                "Start block 0x%x, block count 0x%x, references 0x%x",
                irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
+       xfs_btree_mark_sick(cur);
        return -EFSCORRUPTED;
 }
 
@@ -1889,8 +1891,10 @@ xfs_refcount_recover_extent(
        struct xfs_refcount_recovery    *rr;
 
        if (XFS_IS_CORRUPT(cur->bc_mp,
-                          be32_to_cpu(rec->refc.rc_refcount) != 1))
+                          be32_to_cpu(rec->refc.rc_refcount) != 1)) {
+               xfs_btree_mark_sick(cur);
                return -EFSCORRUPTED;
+       }
 
        rr = kmalloc(sizeof(struct xfs_refcount_recovery),
                        GFP_KERNEL | __GFP_NOFAIL);
index 0bd1f47b2c2b26f618c42567f9de86fa7feb8429..8c4d30a0febbaf59ba52e29c336b6fe7126496ef 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_error.h"
 #include "xfs_inode.h"
 #include "xfs_ag.h"
+#include "xfs_health.h"
 
 struct kmem_cache      *xfs_rmap_intent_cache;
 
@@ -56,8 +57,10 @@ xfs_rmap_lookup_le(
        error = xfs_rmap_get_rec(cur, irec, &get_stat);
        if (error)
                return error;
-       if (!get_stat)
+       if (!get_stat) {
+               xfs_btree_mark_sick(cur);
                return -EFSCORRUPTED;
+       }
 
        return 0;
 }
@@ -277,6 +280,7 @@ xfs_rmap_complain_bad_rec(
                "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
                irec->rm_owner, irec->rm_flags, irec->rm_startblock,
                irec->rm_blockcount);
+       xfs_btree_mark_sick(cur);
        return -EFSCORRUPTED;
 }
 
index 349360a708b48887fa139abdedaa100bb9929f9f..e9338c05ea23766e25cc34b147e4c4876db2cffd 100644 (file)
@@ -14,6 +14,7 @@
 #include "xfs_trace.h"
 #include "xfs_health.h"
 #include "xfs_ag.h"
+#include "xfs_btree.h"
 
 /*
  * Warn about metadata corruption that we detected but haven't fixed, and
@@ -507,3 +508,40 @@ xfs_bmap_mark_sick(
 
        xfs_inode_mark_sick(ip, mask);
 }
+
+/* Record observations of btree corruption with the health tracking system. */
+void
+xfs_btree_mark_sick(
+       struct xfs_btree_cur            *cur)
+{
+       unsigned int                    mask;
+
+       switch (cur->bc_btnum) {
+       case XFS_BTNUM_BMAP:
+               xfs_bmap_mark_sick(cur->bc_ino.ip, cur->bc_ino.whichfork);
+               return;
+       case XFS_BTNUM_BNO:
+               mask = XFS_SICK_AG_BNOBT;
+               break;
+       case XFS_BTNUM_CNT:
+               mask = XFS_SICK_AG_CNTBT;
+               break;
+       case XFS_BTNUM_INO:
+               mask = XFS_SICK_AG_INOBT;
+               break;
+       case XFS_BTNUM_FINO:
+               mask = XFS_SICK_AG_FINOBT;
+               break;
+       case XFS_BTNUM_RMAP:
+               mask = XFS_SICK_AG_RMAPBT;
+               break;
+       case XFS_BTNUM_REFC:
+               mask = XFS_SICK_AG_REFCNTBT;
+               break;
+       default:
+               ASSERT(0);
+               return;
+       }
+
+       xfs_ag_mark_sick(cur->bc_ag.pag, mask);
+}