]> www.infradead.org Git - users/hch/misc.git/commitdiff
xfs: scrub each rtgroup's portion of the rtbitmap separately
authorDarrick J. Wong <djwong@kernel.org>
Wed, 29 May 2024 04:11:24 +0000 (21:11 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 24 Jul 2024 05:33:40 +0000 (22:33 -0700)
Create a new scrub type code so that userspace can scrub each rtgroup's
portion of the rtbitmap file separately.  This reduces the long tail
latency that results from scanning the entire bitmap all at once, and
prepares us for future patchsets, wherein we'll need to be able to lock
a specific rtgroup so that we can rebuild that rtgroup's part of the
rtbitmap contents from the rtgroup's rmap btree.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/libxfs/xfs_fs.h
fs/xfs/libxfs/xfs_health.h
fs/xfs/scrub/common.h
fs/xfs/scrub/health.c
fs/xfs/scrub/rtbitmap.c
fs/xfs/scrub/rtbitmap.h
fs/xfs/scrub/scrub.c
fs/xfs/scrub/scrub.h
fs/xfs/scrub/stats.c
fs/xfs/scrub/trace.h
fs/xfs/xfs_health.c

index 0dfc277d664992387654163032b436037cb76d29..4a704432d924f8893d4bdb03e06b1d55d4113ea8 100644 (file)
@@ -737,9 +737,10 @@ struct xfs_scrub_metadata {
 #define XFS_SCRUB_TYPE_DIRTREE 28      /* directory tree structure */
 #define XFS_SCRUB_TYPE_METAPATH        29      /* metadata directory tree paths */
 #define XFS_SCRUB_TYPE_RGSUPER 30      /* realtime superblock */
+#define XFS_SCRUB_TYPE_RGBITMAP        31      /* realtime group bitmap */
 
 /* Number of scrub subcommands. */
-#define XFS_SCRUB_TYPE_NR      31
+#define XFS_SCRUB_TYPE_NR      32
 
 /*
  * This special type code only applies to the vectored scrub implementation.
@@ -985,6 +986,7 @@ struct xfs_rtgroup_geometry {
        __u64 rg_reserved[13];  /* o: zero */
 };
 #define XFS_RTGROUP_GEOM_SICK_SUPER    (1U << 0)  /* superblock */
+#define XFS_RTGROUP_GEOM_SICK_BITMAP   (1U << 1)  /* rtbitmap for this group */
 
 /*
  * ioctl commands that are used by Linux filesystems
index f088406324f995d2f4dfee227c55778ec26f4c27..5a35d4e7b0f0aa0b2154b1adf2c9e96d8d32403b 100644 (file)
@@ -70,6 +70,7 @@ struct xfs_rtgroup;
 
 /* Observable health issues for realtime group metadata. */
 #define XFS_SICK_RG_SUPER      (1 << 0)  /* rt group superblock */
+#define XFS_SICK_RG_BITMAP     (1 << 1)  /* rt group part of rtbitmap */
 
 /* Observable health issues for AG metadata. */
 #define XFS_SICK_AG_SB         (1 << 0)  /* superblock */
@@ -116,7 +117,8 @@ struct xfs_rtgroup;
 #define XFS_SICK_RT_PRIMARY    (XFS_SICK_RT_BITMAP | \
                                 XFS_SICK_RT_SUMMARY)
 
-#define XFS_SICK_RG_PRIMARY    (XFS_SICK_RG_SUPER)
+#define XFS_SICK_RG_PRIMARY    (XFS_SICK_RG_SUPER | \
+                                XFS_SICK_RG_BITMAP)
 
 #define XFS_SICK_AG_PRIMARY    (XFS_SICK_AG_SB | \
                                 XFS_SICK_AG_AGF | \
index df8388696176b5be26eba3b630a74fb1b77e9ab9..7a782e4b1647d253540a13f1dd2e222425c7a8e0 100644 (file)
@@ -82,10 +82,12 @@ int xchk_setup_metapath(struct xfs_scrub *sc);
 int xchk_setup_rtbitmap(struct xfs_scrub *sc);
 int xchk_setup_rtsummary(struct xfs_scrub *sc);
 int xchk_setup_rgsuperblock(struct xfs_scrub *sc);
+int xchk_setup_rgbitmap(struct xfs_scrub *sc);
 #else
 # define xchk_setup_rtbitmap           xchk_setup_nothing
 # define xchk_setup_rtsummary          xchk_setup_nothing
 # define xchk_setup_rgsuperblock       xchk_setup_nothing
+# define xchk_setup_rgbitmap           xchk_setup_nothing
 #endif
 #ifdef CONFIG_XFS_QUOTA
 int xchk_ino_dqattach(struct xfs_scrub *sc);
@@ -144,6 +146,10 @@ void xchk_rt_unlock(struct xfs_scrub *sc, struct xchk_rt *sr);
 void xchk_rt_unlock_rtbitmap(struct xfs_scrub *sc);
 
 #ifdef CONFIG_XFS_RT
+
+/* All the locks we need to check an rtgroup. */
+#define XCHK_RTGLOCK_ALL       (XFS_RTGLOCK_BITMAP_SHARED)
+
 int xchk_rtgroup_init(struct xfs_scrub *sc, xfs_rgnumber_t rgno,
                struct xchk_rt *sr, unsigned int rtglock_flags);
 void xchk_rtgroup_unlock(struct xfs_scrub *sc, struct xchk_rt *sr);
index 83c52bb0dc7db5baf700a60eff916dd6c47c4b9a..51ba591d8db3ffd49260184ad3301f6bedeaaa16 100644 (file)
@@ -113,6 +113,7 @@ static const struct xchk_health_map type_to_health_flag[XFS_SCRUB_TYPE_NR] = {
        [XFS_SCRUB_TYPE_DIRTREE]        = { XHG_INO, XFS_SICK_INO_DIRTREE },
        [XFS_SCRUB_TYPE_METAPATH]       = { XHG_FS,  XFS_SICK_FS_METAPATH },
        [XFS_SCRUB_TYPE_RGSUPER]        = { XHG_RTGROUP, XFS_SICK_RG_SUPER },
+       [XFS_SCRUB_TYPE_RGBITMAP]       = { XHG_RTGROUP, XFS_SICK_RG_BITMAP },
 };
 
 /* Return the health status mask for this scrub type. */
index a166e53f1b3a47379b190c437d4de50ddcd24c10..fdc1f258962b8de377fcfe982e14f0e9b568b499 100644 (file)
 #include "xfs_bmap.h"
 #include "xfs_bit.h"
 #include "xfs_sb.h"
+#include "xfs_rtgroup.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/repair.h"
 #include "scrub/rtbitmap.h"
 
+static inline void
+xchk_rtbitmap_compute_geometry(
+       struct xfs_mount        *mp,
+       struct xchk_rtbitmap    *rtb)
+{
+       if (mp->m_sb.sb_rblocks == 0)
+               return;
+
+       rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
+       rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
+       rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
+}
+
+/* Set us up with the realtime group metadata locked. */
+int
+xchk_setup_rgbitmap(
+       struct xfs_scrub        *sc)
+{
+       struct xfs_mount        *mp = sc->mp;
+       struct xchk_rgbitmap    *rgb;
+       int                     error;
+
+       rgb = kzalloc(sizeof(struct xchk_rgbitmap), XCHK_GFP_FLAGS);
+       if (!rgb)
+               return -ENOMEM;
+       rgb->sc = sc;
+       sc->buf = rgb;
+
+       error = xchk_trans_alloc(sc, 0);
+       if (error)
+               return error;
+
+       error = xchk_install_live_inode(sc, mp->m_rbmip);
+       if (error)
+               return error;
+
+       error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr,
+                       XCHK_RTGLOCK_ALL);
+       if (error)
+               return error;
+
+       /*
+        * Now that we've locked the rtbitmap, we can't race with growfsrt
+        * trying to expand the bitmap or change the size of the rt volume.
+        * Hence it is safe to compute and check the geometry values.
+        */
+       xchk_rtbitmap_compute_geometry(mp, &rgb->rtb);
+       return 0;
+}
+
 /* Set us up with the realtime metadata locked. */
 int
 xchk_setup_rtbitmap(
@@ -60,11 +111,63 @@ xchk_setup_rtbitmap(
         * trying to expand the bitmap or change the size of the rt volume.
         * Hence it is safe to compute and check the geometry values.
         */
-       if (mp->m_sb.sb_rblocks) {
-               rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
-               rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
-               rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
+       xchk_rtbitmap_compute_geometry(mp, rtb);
+       return 0;
+}
+
+/* Per-rtgroup bitmap contents. */
+
+/* Scrub a free extent record from the realtime bitmap. */
+STATIC int
+xchk_rgbitmap_rec(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       const struct xfs_rtalloc_rec *rec,
+       void                    *priv)
+{
+       struct xchk_rgbitmap    *rgb = priv;
+       struct xfs_scrub        *sc = rgb->sc;
+       xfs_rtblock_t           startblock;
+       xfs_filblks_t           blockcount;
+
+       startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
+       blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+
+       if (!xfs_verify_rtbext(mp, startblock, blockcount))
+               xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
+       return 0;
+}
+
+/* Scrub this group's realtime bitmap. */
+int
+xchk_rgbitmap(
+       struct xfs_scrub        *sc)
+{
+       struct xfs_mount        *mp = sc->mp;
+       struct xfs_rtgroup      *rtg = sc->sr.rtg;
+       struct xchk_rgbitmap    *rgb = sc->buf;
+       xfs_rtblock_t           start, last;
+       xfs_rgblock_t           last_rgbno = rtg->rtg_blockcount - 1;
+       int                     error;
+
+       /* Sanity check the realtime bitmap size. */
+       if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rtb.rbmblocks)) {
+               xchk_ino_set_corrupt(sc, sc->ip->i_ino);
+               return 0;
        }
+
+       /*
+        * Check only the portion of the rtbitmap that corresponds to this
+        * realtime group.
+        */
+       start = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, 0);
+       last = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, last_rgbno);
+
+       error = xfs_rtalloc_query_range(mp, sc->tp, xfs_rtb_to_rtx(mp, start),
+                       xfs_rtb_to_rtx(mp, last), xchk_rgbitmap_rec, rgb);
+       if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
+               return error;
+
        return 0;
 }
 
@@ -193,6 +296,13 @@ xchk_rtbitmap(
        if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
                return error;
 
+       /*
+        * Each rtgroup checks its portion of the rt bitmap, so if we don't
+        * have that feature, we have to check the bitmap contents now.
+        */
+       if (xfs_has_rtgroups(mp))
+               return 0;
+
        error = xfs_rtalloc_query_all(mp, sc->tp, xchk_rtbitmap_rec, sc);
        if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
                return error;
index 85304ff019e1dceabadf86cdef47a5bec489ca62..f659f0e76b4fae7dc033d00ce3fab559199eb37e 100644 (file)
@@ -13,6 +13,12 @@ struct xchk_rtbitmap {
        unsigned int            resblks;
 };
 
+struct xchk_rgbitmap {
+       struct xfs_scrub        *sc;
+
+       struct xchk_rtbitmap    rtb;
+};
+
 #ifdef CONFIG_XFS_ONLINE_REPAIR
 int xrep_setup_rtbitmap(struct xfs_scrub *sc, struct xchk_rtbitmap *rtb);
 #else
index f3b3d1dae1ddf03277be02fd6640bef1199c0a2f..4e9b44a91d5295fa171e9054482a7e878d1749f2 100644 (file)
@@ -460,6 +460,13 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
                .has    = xfs_has_rtsb,
                .repair = xrep_rgsuperblock,
        },
+       [XFS_SCRUB_TYPE_RGBITMAP] = {   /* realtime group bitmap */
+               .type   = ST_RTGROUP,
+               .setup  = xchk_setup_rgbitmap,
+               .scrub  = xchk_rgbitmap,
+               .has    = xfs_has_rtgroups,
+               .repair = xrep_notsupported,
+       },
 };
 
 static int
index e37fe1cda6b389b9c7bfea2af8e37c40b4088377..89c39059ba1e78e610dc3de9d8be8334d82c90eb 100644 (file)
@@ -277,10 +277,12 @@ int xchk_metapath(struct xfs_scrub *sc);
 int xchk_rtbitmap(struct xfs_scrub *sc);
 int xchk_rtsummary(struct xfs_scrub *sc);
 int xchk_rgsuperblock(struct xfs_scrub *sc);
+int xchk_rgbitmap(struct xfs_scrub *sc);
 #else
 # define xchk_rtbitmap         xchk_nothing
 # define xchk_rtsummary                xchk_nothing
 # define xchk_rgsuperblock     xchk_nothing
+# define xchk_rgbitmap         xchk_nothing
 #endif
 #ifdef CONFIG_XFS_QUOTA
 int xchk_quota(struct xfs_scrub *sc);
index a476c7b2ab75973ba5bd6754bebd7f493181ecf7..72fdf6b422639c775e2cb1bfe9ffb3445409970a 100644 (file)
@@ -82,6 +82,7 @@ static const char *name_map[XFS_SCRUB_TYPE_NR] = {
        [XFS_SCRUB_TYPE_DIRTREE]        = "dirtree",
        [XFS_SCRUB_TYPE_METAPATH]       = "metapath",
        [XFS_SCRUB_TYPE_RGSUPER]        = "rgsuper",
+       [XFS_SCRUB_TYPE_RGBITMAP]       = "rgbitmap",
 };
 
 /* Format the scrub stats into a text buffer, similar to pcp style. */
index d4d0e8ceeeb7b8ebb4a9b9975a34d2ebde514ad4..213a260088c19dec974153c4615b5eae1a6234c7 100644 (file)
@@ -72,6 +72,7 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_DIRTREE);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_BARRIER);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_METAPATH);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RGSUPER);
+TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RGBITMAP);
 
 #define XFS_SCRUB_TYPE_STRINGS \
        { XFS_SCRUB_TYPE_PROBE,         "probe" }, \
@@ -105,7 +106,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RGSUPER);
        { XFS_SCRUB_TYPE_DIRTREE,       "dirtree" }, \
        { XFS_SCRUB_TYPE_BARRIER,       "barrier" }, \
        { XFS_SCRUB_TYPE_METAPATH,      "metapath" }, \
-       { XFS_SCRUB_TYPE_RGSUPER,       "rgsuper" }
+       { XFS_SCRUB_TYPE_RGSUPER,       "rgsuper" }, \
+       { XFS_SCRUB_TYPE_RGBITMAP,      "rgbitmap" }
 
 #define XFS_SCRUB_FLAG_STRINGS \
        { XFS_SCRUB_IFLAG_REPAIR,               "repair" }, \
index 77287079fd3ffc7a8a4f2aa3a6ea0ac96b2b6526..0539b64bdcfc44ec69631671fc75cf629987db5d 100644 (file)
@@ -549,6 +549,7 @@ xfs_ag_geom_health(
 
 static const struct ioctl_sick_map rtgroup_map[] = {
        { XFS_SICK_RG_SUPER,    XFS_RTGROUP_GEOM_SICK_SUPER },
+       { XFS_SICK_RG_BITMAP,   XFS_RTGROUP_GEOM_SICK_BITMAP },
        { 0, 0 },
 };