]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: add rtgroup-based realtime scrubbing context management
authorDarrick J. Wong <djwong@kernel.org>
Mon, 4 Nov 2024 04:19:06 +0000 (20:19 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 5 Nov 2024 21:38:36 +0000 (13:38 -0800)
Create a state tracking structure and helpers to initialize the tracking
structure so that we can check metadata records against the realtime
space management metadata.  Right now this is limited to grabbing the
incore rtgroup object, but we'll eventually add to the tracking
structure the ILOCK state and btree cursors.

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

index c26a3314237a6905dfa6dd4a47ddfb36203cc97c..5cbd94b56582a47cf33668f78532f7b44d106466 100644 (file)
@@ -34,6 +34,7 @@
 #include "xfs_quota.h"
 #include "xfs_exchmaps.h"
 #include "xfs_rtbitmap.h"
+#include "xfs_rtgroup.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
@@ -121,6 +122,17 @@ xchk_process_error(
                        XFS_SCRUB_OFLAG_CORRUPT, __return_address);
 }
 
+bool
+xchk_process_rt_error(
+       struct xfs_scrub        *sc,
+       xfs_rgnumber_t          rgno,
+       xfs_rgblock_t           rgbno,
+       int                     *error)
+{
+       return __xchk_process_error(sc, rgno, rgbno, error,
+                       XFS_SCRUB_OFLAG_CORRUPT, __return_address);
+}
+
 bool
 xchk_xref_process_error(
        struct xfs_scrub        *sc,
@@ -684,6 +696,72 @@ xchk_ag_init(
        return 0;
 }
 
+#ifdef CONFIG_XFS_RT
+/*
+ * For scrubbing a realtime group, grab all the in-core resources we'll need to
+ * check the metadata, which means taking the ILOCK of the realtime group's
+ * metadata inodes.  Callers must not join these inodes to the transaction with
+ * non-zero lockflags or concurrency problems will result.  The @rtglock_flags
+ * argument takes XFS_RTGLOCK_* flags.
+ */
+int
+xchk_rtgroup_init(
+       struct xfs_scrub        *sc,
+       xfs_rgnumber_t          rgno,
+       struct xchk_rt          *sr)
+{
+       ASSERT(sr->rtg == NULL);
+       ASSERT(sr->rtlock_flags == 0);
+
+       sr->rtg = xfs_rtgroup_get(sc->mp, rgno);
+       if (!sr->rtg)
+               return -ENOENT;
+       return 0;
+}
+
+void
+xchk_rtgroup_lock(
+       struct xchk_rt          *sr,
+       unsigned int            rtglock_flags)
+{
+       xfs_rtgroup_lock(sr->rtg, rtglock_flags);
+       sr->rtlock_flags = rtglock_flags;
+}
+
+/*
+ * Unlock the realtime group.  This must be done /after/ committing (or
+ * cancelling) the scrub transaction.
+ */
+static void
+xchk_rtgroup_unlock(
+       struct xchk_rt          *sr)
+{
+       ASSERT(sr->rtg != NULL);
+
+       if (sr->rtlock_flags) {
+               xfs_rtgroup_unlock(sr->rtg, sr->rtlock_flags);
+               sr->rtlock_flags = 0;
+       }
+}
+
+/*
+ * Unlock the realtime group and release its resources.  This must be done
+ * /after/ committing (or cancelling) the scrub transaction.
+ */
+void
+xchk_rtgroup_free(
+       struct xfs_scrub        *sc,
+       struct xchk_rt          *sr)
+{
+       ASSERT(sr->rtg != NULL);
+
+       xchk_rtgroup_unlock(sr);
+
+       xfs_rtgroup_put(sr->rtg);
+       sr->rtg = NULL;
+}
+#endif /* CONFIG_XFS_RT */
+
 /* Per-scrubber setup functions */
 
 void
index b2a81e85ded9cf0f7a48049d8726d0c9ed39fc25..672ed48d4a9fc36e3c71097876a3e928fbd85607 100644 (file)
@@ -12,6 +12,8 @@ void xchk_trans_cancel(struct xfs_scrub *sc);
 
 bool xchk_process_error(struct xfs_scrub *sc, xfs_agnumber_t agno,
                xfs_agblock_t bno, int *error);
+bool xchk_process_rt_error(struct xfs_scrub *sc, xfs_rgnumber_t rgno,
+               xfs_rgblock_t rgbno, int *error);
 bool xchk_fblock_process_error(struct xfs_scrub *sc, int whichfork,
                xfs_fileoff_t offset, int *error);
 
@@ -118,6 +120,34 @@ xchk_ag_init_existing(
        return error == -ENOENT ? -EFSCORRUPTED : error;
 }
 
+#ifdef CONFIG_XFS_RT
+
+/* All the locks we need to check an rtgroup. */
+#define XCHK_RTGLOCK_ALL       (XFS_RTGLOCK_BITMAP)
+
+int xchk_rtgroup_init(struct xfs_scrub *sc, xfs_rgnumber_t rgno,
+               struct xchk_rt *sr);
+
+static inline int
+xchk_rtgroup_init_existing(
+       struct xfs_scrub        *sc,
+       xfs_rgnumber_t          rgno,
+       struct xchk_rt          *sr)
+{
+       int                     error = xchk_rtgroup_init(sc, rgno, sr);
+
+       return error == -ENOENT ? -EFSCORRUPTED : error;
+}
+
+void xchk_rtgroup_lock(struct xchk_rt *sr, unsigned int rtglock_flags);
+void xchk_rtgroup_free(struct xfs_scrub *sc, struct xchk_rt *sr);
+#else
+# define xchk_rtgroup_init(sc, rgno, sr)               (-EFSCORRUPTED)
+# define xchk_rtgroup_init_existing(sc, rgno, sr)      (-EFSCORRUPTED)
+# define xchk_rtgroup_lock(sc, lockflags)              do { } while (0)
+# define xchk_rtgroup_free(sc, sr)                     do { } while (0)
+#endif /* CONFIG_XFS_RT */
+
 int xchk_ag_read_headers(struct xfs_scrub *sc, xfs_agnumber_t agno,
                struct xchk_ag *sa);
 void xchk_ag_btcur_free(struct xchk_ag *sa);
index f80000d775524294de87524e4740a2754470c5af..5fdd00029cd6c05ff803a6f2b4ba75073f134355 100644 (file)
@@ -21,6 +21,7 @@
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
 #include "xfs_refcount_btree.h"
+#include "xfs_rtgroup.h"
 #include "xfs_extent_busy.h"
 #include "xfs_ag.h"
 #include "xfs_ag_resv.h"
@@ -952,6 +953,29 @@ xrep_ag_init(
        return 0;
 }
 
+#ifdef CONFIG_XFS_RT
+/*
+ * Given a reference to a rtgroup structure, lock rtgroup btree inodes and
+ * create btree cursors.  Must only be called to repair a regular rt file.
+ */
+int
+xrep_rtgroup_init(
+       struct xfs_scrub        *sc,
+       struct xfs_rtgroup      *rtg,
+       struct xchk_rt          *sr,
+       unsigned int            rtglock_flags)
+{
+       ASSERT(sr->rtg == NULL);
+
+       xfs_rtgroup_lock(rtg, rtglock_flags);
+       sr->rtlock_flags = rtglock_flags;
+
+       /* Grab our own passive reference from the caller's ref. */
+       sr->rtg = xfs_rtgroup_hold(rtg);
+       return 0;
+}
+#endif /* CONFIG_XFS_RT */
+
 /* Reinitialize the per-AG block reservation for the AG we just fixed. */
 int
 xrep_reset_perag_resv(
index 90f9cb3b5ad8ba92d459fea85a1fdc51438e275d..4052185743910da837cf8263b2f25961988ad455 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "xfs_quota_defs.h"
 
+struct xfs_rtgroup;
 struct xchk_stats_run;
 
 static inline int xrep_notsupported(struct xfs_scrub *sc)
@@ -106,6 +107,12 @@ int xrep_setup_inode(struct xfs_scrub *sc, const struct xfs_imap *imap);
 void xrep_ag_btcur_init(struct xfs_scrub *sc, struct xchk_ag *sa);
 int xrep_ag_init(struct xfs_scrub *sc, struct xfs_perag *pag,
                struct xchk_ag *sa);
+#ifdef CONFIG_XFS_RT
+int xrep_rtgroup_init(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
+               struct xchk_rt *sr, unsigned int rtglock_flags);
+#else
+# define xrep_rtgroup_init(sc, rtg, sr, lockflags)     (-ENOSYS)
+#endif /* CONFIG_XFS_RT */
 
 /* Metadata revalidators */
 
index 1ac33bea6f0a72f64b7a5ac9365e9d3d3911d96e..03770b9f905c3da9f372fa6acc6df6fd5ec72fa3 100644 (file)
@@ -225,6 +225,8 @@ xchk_teardown(
                        xfs_trans_cancel(sc->tp);
                sc->tp = NULL;
        }
+       if (sc->sr.rtg)
+               xchk_rtgroup_free(sc, &sc->sr);
        if (sc->ip) {
                if (sc->ilock_flags)
                        xchk_iunlock(sc, sc->ilock_flags);
@@ -498,6 +500,33 @@ xchk_validate_inputs(
                break;
        case ST_GENERIC:
                break;
+       case ST_RTGROUP:
+               if (sm->sm_ino || sm->sm_gen)
+                       goto out;
+               if (xfs_has_rtgroups(mp)) {
+                       /*
+                        * On a rtgroups filesystem, there won't be an rtbitmap
+                        * or rtsummary file for group 0 unless there's
+                        * actually a realtime volume attached.  However, older
+                        * xfs_scrub always calls the rtbitmap/rtsummary
+                        * scrubbers with sm_agno==0 so transform the error
+                        * code to ENOENT.
+                        */
+                       if (sm->sm_agno >= mp->m_sb.sb_rgcount) {
+                               if (sm->sm_agno == 0)
+                                       error = -ENOENT;
+                               goto out;
+                       }
+               } else {
+                       /*
+                        * Prior to rtgroups, the rtbitmap/rtsummary scrubbers
+                        * accepted sm_agno==0, so we still accept that for
+                        * scrubbing pre-rtgroups filesystems.
+                        */
+                       if (sm->sm_agno != 0)
+                               goto out;
+               }
+               break;
        default:
                goto out;
        }
index c688ff4fc7fc4c5d3344d011b84cd743d4f7ff02..f73c6d0d90a11ab2d13873d2ae3f1688093a8a62 100644 (file)
@@ -74,6 +74,7 @@ enum xchk_type {
        ST_FS,          /* per-FS metadata */
        ST_INODE,       /* per-inode metadata */
        ST_GENERIC,     /* determined by the scrubber */
+       ST_RTGROUP,     /* rtgroup metadata */
 };
 
 struct xchk_meta_ops {
@@ -118,6 +119,15 @@ struct xchk_ag {
        struct xfs_btree_cur    *refc_cur;
 };
 
+/* Inode lock state for the RT volume. */
+struct xchk_rt {
+       /* incore rtgroup, if applicable */
+       struct xfs_rtgroup      *rtg;
+
+       /* XFS_RTGLOCK_* lock state if locked */
+       unsigned int            rtlock_flags;
+};
+
 struct xfs_scrub {
        /* General scrub state. */
        struct xfs_mount                *mp;
@@ -179,6 +189,9 @@ struct xfs_scrub {
 
        /* State tracking for single-AG operations. */
        struct xchk_ag                  sa;
+
+       /* State tracking for realtime operations. */
+       struct xchk_rt                  sr;
 };
 
 /* XCHK state flags grow up from zero, XREP state flags grown down from 2^31 */