xfs: online checking of the free rt extent count
authorDarrick J. Wong <djwong@kernel.org>
Mon, 7 Nov 2022 01:03:19 +0000 (17:03 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 16 Nov 2022 23:25:03 +0000 (15:25 -0800)
Teach the summary count checker to count the number of free realtime
extents and compare that to the superblock copy.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/scrub/fscounters.c
fs/xfs/scrub/scrub.h

index eeb36ac2c6d2cf27e4f720ef8647998c24525980..4777e7b89fdc69527fbb31d65801acf693e4af4f 100644 (file)
@@ -14,6 +14,8 @@
 #include "xfs_health.h"
 #include "xfs_btree.h"
 #include "xfs_ag.h"
+#include "xfs_rtalloc.h"
+#include "xfs_inode.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
  * our tolerance for mismatch between expected and actual counter values.
  */
 
+struct xchk_fscounters {
+       struct xfs_scrub        *sc;
+       uint64_t                icount;
+       uint64_t                ifree;
+       uint64_t                fdblocks;
+       uint64_t                frextents;
+       unsigned long long      icount_min;
+       unsigned long long      icount_max;
+};
+
 /*
  * Since the expected value computation is lockless but only browses incore
  * values, the percpu counters should be fairly close to each other.  However,
@@ -120,6 +132,7 @@ xchk_setup_fscounters(
        if (!sc->buf)
                return -ENOMEM;
        fsc = sc->buf;
+       fsc->sc = sc;
 
        xfs_icount_range(sc->mp, &fsc->icount_min, &fsc->icount_max);
 
@@ -281,6 +294,59 @@ retry:
        return 0;
 }
 
+#ifdef CONFIG_XFS_RT
+STATIC int
+xchk_fscount_add_frextent(
+       struct xfs_mount                *mp,
+       struct xfs_trans                *tp,
+       const struct xfs_rtalloc_rec    *rec,
+       void                            *priv)
+{
+       struct xchk_fscounters          *fsc = priv;
+       int                             error = 0;
+
+       fsc->frextents += rec->ar_extcount;
+
+       xchk_should_terminate(fsc->sc, &error);
+       return error;
+}
+
+/* Calculate the number of free realtime extents from the realtime bitmap. */
+STATIC int
+xchk_fscount_count_frextents(
+       struct xfs_scrub        *sc,
+       struct xchk_fscounters  *fsc)
+{
+       struct xfs_mount        *mp = sc->mp;
+       int                     error;
+
+       fsc->frextents = 0;
+       if (!xfs_has_realtime(mp))
+               return 0;
+
+       xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
+       error = xfs_rtalloc_query_all(sc->mp, sc->tp,
+                       xchk_fscount_add_frextent, fsc);
+       if (error) {
+               xchk_set_incomplete(sc);
+               goto out_unlock;
+       }
+
+out_unlock:
+       xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
+       return error;
+}
+#else
+STATIC int
+xchk_fscount_count_frextents(
+       struct xfs_scrub        *sc,
+       struct xchk_fscounters  *fsc)
+{
+       fsc->frextents = 0;
+       return 0;
+}
+#endif /* CONFIG_XFS_RT */
+
 /*
  * Part 2: Comparing filesystem summary counters.  All we have to do here is
  * sum the percpu counters and compare them to what we've observed.
@@ -352,16 +418,17 @@ xchk_fscounters(
 {
        struct xfs_mount        *mp = sc->mp;
        struct xchk_fscounters  *fsc = sc->buf;
-       int64_t                 icount, ifree, fdblocks;
+       int64_t                 icount, ifree, fdblocks, frextents;
        int                     error;
 
        /* Snapshot the percpu counters. */
        icount = percpu_counter_sum(&mp->m_icount);
        ifree = percpu_counter_sum(&mp->m_ifree);
        fdblocks = percpu_counter_sum(&mp->m_fdblocks);
+       frextents = percpu_counter_sum(&mp->m_frextents);
 
        /* No negative values, please! */
-       if (icount < 0 || ifree < 0 || fdblocks < 0)
+       if (icount < 0 || ifree < 0 || fdblocks < 0 || frextents < 0)
                xchk_set_corrupt(sc);
 
        /* See if icount is obviously wrong. */
@@ -372,6 +439,10 @@ xchk_fscounters(
        if (fdblocks > mp->m_sb.sb_dblocks)
                xchk_set_corrupt(sc);
 
+       /* See if frextents is obviously wrong. */
+       if (frextents > mp->m_sb.sb_rextents)
+               xchk_set_corrupt(sc);
+
        /*
         * If ifree exceeds icount by more than the minimum variance then
         * something's probably wrong with the counters.
@@ -386,6 +457,13 @@ xchk_fscounters(
        if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)
                return 0;
 
+       /* Count the free extents counter for rt volumes. */
+       error = xchk_fscount_count_frextents(sc, fsc);
+       if (!xchk_process_error(sc, 0, XFS_SB_BLOCK(mp), &error))
+               return error;
+       if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)
+               return 0;
+
        /* Compare the in-core counters with whatever we counted. */
        if (!xchk_fscount_within_range(sc, icount, &mp->m_icount, fsc->icount))
                xchk_set_corrupt(sc);
@@ -397,5 +475,9 @@ xchk_fscounters(
                        fsc->fdblocks))
                xchk_set_corrupt(sc);
 
+       if (!xchk_fscount_within_range(sc, frextents, &mp->m_frextents,
+                       fsc->frextents))
+               xchk_set_corrupt(sc);
+
        return 0;
 }
index a0f097b8acb0a2f970abe5fd5a239d91b03e20a1..b4d391b4c938521e5850870c9e10c860c99d0cc9 100644 (file)
@@ -169,12 +169,4 @@ void xchk_xref_is_used_rt_space(struct xfs_scrub *sc, xfs_rtblock_t rtbno,
 # define xchk_xref_is_used_rt_space(sc, rtbno, len) do { } while (0)
 #endif
 
-struct xchk_fscounters {
-       uint64_t                icount;
-       uint64_t                ifree;
-       uint64_t                fdblocks;
-       unsigned long long      icount_min;
-       unsigned long long      icount_max;
-};
-
 #endif /* __XFS_SCRUB_SCRUB_H__ */