]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: report ag header corruption errors to the health tracking system
authorDarrick J. Wong <djwong@kernel.org>
Mon, 22 Apr 2024 17:00:54 +0000 (10:00 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 3 Jun 2024 18:37:36 +0000 (11:37 -0700)
Source kernel commit: de6077ec4198b9313c6e09e4c6acbe9179d057c1

Whenever we encounter a corrupt AG header, we should report that to the
health monitoring system for later reporting.  Buffer readers that don't
respond to corruption events with a _mark_sick call can be detected with
the following script:

#!/bin/bash

# Detect missing calls to xfs_*_mark_sick

filter=cat
tty -s && filter=less

git grep -A10  -E '( = xfs_trans_read_buf| = xfs_buf_read\()' fs/xfs/*.[ch] fs/xfs/libxfs/*.[ch] | awk '
BEGIN {
ignore = 0;
lineno = 0;
delete lines;
}
{
if ($0 == "--") {
if (!ignore) {
for (i = 0; i < lineno; i++) {
print(lines[i]);
}
printf("--\n");
}
delete lines;
lineno = 0;
ignore = 0;
} else if ($0 ~ /mark_sick/) {
ignore = 1;
} else {
lines[lineno++] = $0;
}
}
' | $filter

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
libxfs/util.c
libxfs/xfs_alloc.c
libxfs/xfs_health.h
libxfs/xfs_ialloc.c
libxfs/xfs_sb.c

index 26339171ff82e84230c4055ca3c40cfcc7ff9a32..c30d83a8d6fba527b7be8178b8b32467d7f9becd 100644 (file)
@@ -729,3 +729,6 @@ xfs_fs_mark_healthy(
 
 void xfs_ag_geom_health(struct xfs_perag *pag, struct xfs_ag_geometry *ageo) { }
 void xfs_fs_mark_sick(struct xfs_mount *mp, unsigned int mask) { }
+void xfs_agno_mark_sick(struct xfs_mount *mp, xfs_agnumber_t agno,
+               unsigned int mask) { }
+void xfs_ag_mark_sick(struct xfs_perag *pag, unsigned int mask) { }
index 352efbeca9f439eeaa0fc5df0f4878d470a43b8c..1894a0913807d8a5c4d9eaf851be3e30717b2f86 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 #include "xfs_bmap.h"
+#include "xfs_health.h"
 
 struct kmem_cache      *xfs_extfree_item_cache;
 
@@ -751,6 +752,8 @@ xfs_alloc_read_agfl(
                        mp, tp, mp->m_ddev_targp,
                        XFS_AG_DADDR(mp, pag->pag_agno, XFS_AGFL_DADDR(mp)),
                        XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_agfl_buf_ops);
+       if (xfs_metadata_is_sick(error))
+               xfs_ag_mark_sick(pag, XFS_SICK_AG_AGFL);
        if (error)
                return error;
        xfs_buf_set_ref(bp, XFS_AGFL_REF);
@@ -772,6 +775,7 @@ xfs_alloc_update_counters(
        if (unlikely(be32_to_cpu(agf->agf_freeblks) >
                     be32_to_cpu(agf->agf_length))) {
                xfs_buf_mark_corrupt(agbp);
+               xfs_ag_mark_sick(agbp->b_pag, XFS_SICK_AG_AGF);
                return -EFSCORRUPTED;
        }
 
@@ -3264,6 +3268,8 @@ xfs_read_agf(
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
                        XFS_AG_DADDR(mp, pag->pag_agno, XFS_AGF_DADDR(mp)),
                        XFS_FSS_TO_BB(mp, 1), flags, agfbpp, &xfs_agf_buf_ops);
+       if (xfs_metadata_is_sick(error))
+               xfs_ag_mark_sick(pag, XFS_SICK_AG_AGF);
        if (error)
                return error;
 
index bec7adf9fcf7c537e6779cbd88e71e492b65372f..fb3f2b49087de686e1526f5ca323a3df1303beed 100644 (file)
  * and the "sick" field tells us if that piece was found to need repairs.
  * Therefore we can conclude that for a given sick flag value:
  *
- *  - checked && sick  => metadata needs repair
- *  - checked && !sick => metadata is ok
- *  - !checked         => has not been examined since mount
+ *  - checked && sick   => metadata needs repair
+ *  - checked && !sick  => metadata is ok
+ *  - !checked && sick  => errors have been observed during normal operation,
+ *                         but the metadata has not been checked thoroughly
+ *  - !checked && !sick => has not been examined since mount
  */
 
 struct xfs_mount;
@@ -142,6 +144,8 @@ void xfs_rt_mark_healthy(struct xfs_mount *mp, unsigned int mask);
 void xfs_rt_measure_sickness(struct xfs_mount *mp, unsigned int *sick,
                unsigned int *checked);
 
+void xfs_agno_mark_sick(struct xfs_mount *mp, xfs_agnumber_t agno,
+               unsigned int mask);
 void xfs_ag_mark_sick(struct xfs_perag *pag, unsigned int mask);
 void xfs_ag_mark_corrupt(struct xfs_perag *pag, unsigned int mask);
 void xfs_ag_mark_healthy(struct xfs_perag *pag, unsigned int mask);
@@ -222,4 +226,7 @@ void xfs_fsop_geom_health(struct xfs_mount *mp, struct xfs_fsop_geom *geo);
 void xfs_ag_geom_health(struct xfs_perag *pag, struct xfs_ag_geometry *ageo);
 void xfs_bulkstat_health(struct xfs_inode *ip, struct xfs_bulkstat *bs);
 
+#define xfs_metadata_is_sick(error) \
+       (unlikely((error) == -EFSCORRUPTED || (error) == -EFSBADCRC))
+
 #endif /* __XFS_HEALTH_H__ */
index 5ff09c8c9439ed05c8cd340152ca417b0a8de0af..c801250a33bfa50881655a2d1e0d193d1cccfff6 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_trace.h"
 #include "xfs_rmap.h"
 #include "xfs_ag.h"
+#include "xfs_health.h"
 
 /*
  * Lookup a record by ino in the btree given by cur.
@@ -2599,6 +2600,8 @@ xfs_read_agi(
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
                        XFS_AG_DADDR(mp, pag->pag_agno, XFS_AGI_DADDR(mp)),
                        XFS_FSS_TO_BB(mp, 1), 0, agibpp, &xfs_agi_buf_ops);
+       if (xfs_metadata_is_sick(error))
+               xfs_ag_mark_sick(pag, XFS_SICK_AG_AGI);
        if (error)
                return error;
        if (tp)
index 402f03a557e03ca0e2eb64c459a2d22892d9d184..00b0a937d61e4f31749ade88b8124d4e758b9345 100644 (file)
@@ -1288,6 +1288,8 @@ xfs_sb_read_secondary(
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
                        XFS_AG_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
                        XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_sb_buf_ops);
+       if (xfs_metadata_is_sick(error))
+               xfs_agno_mark_sick(mp, agno, XFS_SICK_AG_SB);
        if (error)
                return error;
        xfs_buf_set_ref(bp, XFS_SSB_REF);