]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: separate the marking of sick and checked metadata
authorDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:31:01 +0000 (12:31 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:31:01 +0000 (12:31 -0800)
Split the setting of the sick and checked masks into separate functions
as part of preparing to add the ability for regular runtime fs code
(i.e. not scrub) to mark metadata structures sick when corruptions are
found.  Improve the documentation of libxfs' requirements for helper
behavior.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_health.h
fs/xfs/scrub/health.c
fs/xfs/xfs_health.c
fs/xfs/xfs_trace.h

index 2bfe2dc404a19335e611d2c4db954be67a2bb413..bec7adf9fcf7c537e6779cbd88e71e492b65372f 100644 (file)
@@ -111,24 +111,45 @@ struct xfs_fsop_geom;
                                 XFS_SICK_INO_DIR_ZAPPED | \
                                 XFS_SICK_INO_SYMLINK_ZAPPED)
 
-/* These functions must be provided by the xfs implementation. */
+/*
+ * These functions must be provided by the xfs implementation.  Function
+ * behavior with respect to the first argument should be as follows:
+ *
+ * xfs_*_mark_sick:        Set the sick flags and do not set checked flags.
+ *                         Runtime code should call this upon encountering
+ *                         a corruption.
+ *
+ * xfs_*_mark_corrupt:     Set the sick and checked flags simultaneously.
+ *                         Fsck tools should call this when corruption is
+ *                         found.
+ *
+ * xfs_*_mark_healthy:     Clear the sick flags and set the checked flags.
+ *                         Fsck tools should call this after correcting errors.
+ *
+ * xfs_*_measure_sickness: Return the sick and check status in the provided
+ *                         out parameters.
+ */
 
 void xfs_fs_mark_sick(struct xfs_mount *mp, unsigned int mask);
+void xfs_fs_mark_corrupt(struct xfs_mount *mp, unsigned int mask);
 void xfs_fs_mark_healthy(struct xfs_mount *mp, unsigned int mask);
 void xfs_fs_measure_sickness(struct xfs_mount *mp, unsigned int *sick,
                unsigned int *checked);
 
 void xfs_rt_mark_sick(struct xfs_mount *mp, unsigned int mask);
+void xfs_rt_mark_corrupt(struct xfs_mount *mp, unsigned int mask);
 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_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);
 void xfs_ag_measure_sickness(struct xfs_perag *pag, unsigned int *sick,
                unsigned int *checked);
 
 void xfs_inode_mark_sick(struct xfs_inode *ip, unsigned int mask);
+void xfs_inode_mark_corrupt(struct xfs_inode *ip, unsigned int mask);
 void xfs_inode_mark_healthy(struct xfs_inode *ip, unsigned int mask);
 void xfs_inode_measure_sickness(struct xfs_inode *ip, unsigned int *sick,
                unsigned int *checked);
index 34519fbc2d40b8a910d198c9eec99e60b9c1801a..c682c7093353455c84a768c6ab0f74e59402cc9a 100644 (file)
@@ -175,7 +175,7 @@ xchk_update_health(
        case XHG_AG:
                pag = xfs_perag_get(sc->mp, sc->sm->sm_agno);
                if (bad)
-                       xfs_ag_mark_sick(pag, sc->sick_mask);
+                       xfs_ag_mark_corrupt(pag, sc->sick_mask);
                else
                        xfs_ag_mark_healthy(pag, sc->sick_mask);
                xfs_perag_put(pag);
@@ -184,19 +184,19 @@ xchk_update_health(
                if (!sc->ip)
                        return;
                if (bad)
-                       xfs_inode_mark_sick(sc->ip, sc->sick_mask);
+                       xfs_inode_mark_corrupt(sc->ip, sc->sick_mask);
                else
                        xfs_inode_mark_healthy(sc->ip, sc->sick_mask);
                break;
        case XHG_FS:
                if (bad)
-                       xfs_fs_mark_sick(sc->mp, sc->sick_mask);
+                       xfs_fs_mark_corrupt(sc->mp, sc->sick_mask);
                else
                        xfs_fs_mark_healthy(sc->mp, sc->sick_mask);
                break;
        case XHG_RT:
                if (bad)
-                       xfs_rt_mark_sick(sc->mp, sc->sick_mask);
+                       xfs_rt_mark_corrupt(sc->mp, sc->sick_mask);
                else
                        xfs_rt_mark_healthy(sc->mp, sc->sick_mask);
                break;
index 111c27a6b1079a5e77372daa953b462d536a1d58..e727a46a95a453de1de0241f8b03cd7d5fe79dec 100644 (file)
@@ -96,6 +96,20 @@ xfs_fs_mark_sick(
        ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
        trace_xfs_fs_mark_sick(mp, mask);
 
+       spin_lock(&mp->m_sb_lock);
+       mp->m_fs_sick |= mask;
+       spin_unlock(&mp->m_sb_lock);
+}
+
+/* Mark per-fs metadata as having been checked and found unhealthy by fsck. */
+void
+xfs_fs_mark_corrupt(
+       struct xfs_mount        *mp,
+       unsigned int            mask)
+{
+       ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
+       trace_xfs_fs_mark_corrupt(mp, mask);
+
        spin_lock(&mp->m_sb_lock);
        mp->m_fs_sick |= mask;
        mp->m_fs_checked |= mask;
@@ -139,6 +153,20 @@ xfs_rt_mark_sick(
        ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY));
        trace_xfs_rt_mark_sick(mp, mask);
 
+       spin_lock(&mp->m_sb_lock);
+       mp->m_rt_sick |= mask;
+       spin_unlock(&mp->m_sb_lock);
+}
+
+/* Mark realtime metadata as having been checked and found unhealthy by fsck. */
+void
+xfs_rt_mark_corrupt(
+       struct xfs_mount        *mp,
+       unsigned int            mask)
+{
+       ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY));
+       trace_xfs_rt_mark_corrupt(mp, mask);
+
        spin_lock(&mp->m_sb_lock);
        mp->m_rt_sick |= mask;
        mp->m_rt_checked |= mask;
@@ -182,6 +210,20 @@ xfs_ag_mark_sick(
        ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
        trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask);
 
+       spin_lock(&pag->pag_state_lock);
+       pag->pag_sick |= mask;
+       spin_unlock(&pag->pag_state_lock);
+}
+
+/* Mark per-ag metadata as having been checked and found unhealthy by fsck. */
+void
+xfs_ag_mark_corrupt(
+       struct xfs_perag        *pag,
+       unsigned int            mask)
+{
+       ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
+       trace_xfs_ag_mark_corrupt(pag->pag_mount, pag->pag_agno, mask);
+
        spin_lock(&pag->pag_state_lock);
        pag->pag_sick |= mask;
        pag->pag_checked |= mask;
@@ -225,6 +267,29 @@ xfs_inode_mark_sick(
        ASSERT(!(mask & ~(XFS_SICK_INO_PRIMARY | XFS_SICK_INO_ZAPPED)));
        trace_xfs_inode_mark_sick(ip, mask);
 
+       spin_lock(&ip->i_flags_lock);
+       ip->i_sick |= mask;
+       spin_unlock(&ip->i_flags_lock);
+
+       /*
+        * Keep this inode around so we don't lose the sickness report.  Scrub
+        * grabs inodes with DONTCACHE assuming that most inode are ok, which
+        * is not the case here.
+        */
+       spin_lock(&VFS_I(ip)->i_lock);
+       VFS_I(ip)->i_state &= ~I_DONTCACHE;
+       spin_unlock(&VFS_I(ip)->i_lock);
+}
+
+/* Mark inode metadata as having been checked and found unhealthy by fsck. */
+void
+xfs_inode_mark_corrupt(
+       struct xfs_inode        *ip,
+       unsigned int            mask)
+{
+       ASSERT(!(mask & ~(XFS_SICK_INO_PRIMARY | XFS_SICK_INO_ZAPPED)));
+       trace_xfs_inode_mark_corrupt(ip, mask);
+
        spin_lock(&ip->i_flags_lock);
        ip->i_sick |= mask;
        ip->i_checked |= mask;
index c7e57efe0356662187f1cc3d2b53436a1f019264..667ecae469ccb1906973a85e35470d45c21f2589 100644 (file)
@@ -3926,9 +3926,11 @@ DEFINE_EVENT(xfs_fs_corrupt_class, name, \
        TP_PROTO(struct xfs_mount *mp, unsigned int flags), \
        TP_ARGS(mp, flags))
 DEFINE_FS_CORRUPT_EVENT(xfs_fs_mark_sick);
+DEFINE_FS_CORRUPT_EVENT(xfs_fs_mark_corrupt);
 DEFINE_FS_CORRUPT_EVENT(xfs_fs_mark_healthy);
 DEFINE_FS_CORRUPT_EVENT(xfs_fs_unfixed_corruption);
 DEFINE_FS_CORRUPT_EVENT(xfs_rt_mark_sick);
+DEFINE_FS_CORRUPT_EVENT(xfs_rt_mark_corrupt);
 DEFINE_FS_CORRUPT_EVENT(xfs_rt_mark_healthy);
 DEFINE_FS_CORRUPT_EVENT(xfs_rt_unfixed_corruption);
 
@@ -3955,6 +3957,7 @@ DEFINE_EVENT(xfs_ag_corrupt_class, name,  \
                 unsigned int flags), \
        TP_ARGS(mp, agno, flags))
 DEFINE_AG_CORRUPT_EVENT(xfs_ag_mark_sick);
+DEFINE_AG_CORRUPT_EVENT(xfs_ag_mark_corrupt);
 DEFINE_AG_CORRUPT_EVENT(xfs_ag_mark_healthy);
 DEFINE_AG_CORRUPT_EVENT(xfs_ag_unfixed_corruption);
 
@@ -3980,6 +3983,7 @@ DEFINE_EVENT(xfs_inode_corrupt_class, name,       \
        TP_PROTO(struct xfs_inode *ip, unsigned int flags), \
        TP_ARGS(ip, flags))
 DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_sick);
+DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_corrupt);
 DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_healthy);
 
 TRACE_EVENT(xfs_iwalk_ag,