]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: make cow repair somewhat flaky when debugging knob enabled
authorDarrick J. Wong <djwong@kernel.org>
Tue, 14 Jul 2026 06:04:24 +0000 (23:04 -0700)
committerCarlos Maiolino <cem@kernel.org>
Tue, 14 Jul 2026 09:01:47 +0000 (11:01 +0200)
Introduce a new behavior for the cow fork repair code: if the debugging
knob is enabled, we'll pick a random subrange of each cow fork mapping
to mark as bad.  This will exercise the xrep_cow_replace_mapping more
thoroughly.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
fs/xfs/scrub/cow_repair.c

index ca3405a26b641c700488263eeb1c85b9ce19ab16..511a761dca9fe362bebb43ec402cd2abc048cd08 100644 (file)
@@ -224,6 +224,29 @@ xrep_cow_mark_missing_staging_rmap(
                        xfs_gbno_to_fsb(cur->bc_group, rec_bno), rec_len);
 }
 
+/*
+ * Trim the start and end of the current mapping by up to 1/4 of the length
+ * and mark that as "bad" to test the cow fork repair mechanism.
+ */
+static inline int
+xrep_cow_debug_replacement(
+       struct xrep_cow         *xc)
+{
+       xfs_fsblock_t           fsbno = xc->irec.br_startblock;
+       xfs_extlen_t            len = xc->irec.br_blockcount;
+       uint32_t                trim;
+
+       /* get_random_u32_below requires a nonzero argument */
+       trim = len > 4 ? get_random_u32_below(len / 4) : 0;
+       len -= trim;
+
+       trim = len > 4 ? get_random_u32_below(len / 4) : 0;
+       fsbno += trim;
+       len -= trim;
+
+       return xrep_cow_mark_file_range(xc, fsbno, len);
+}
+
 /*
  * Find any part of the CoW fork mapping that isn't a single-owner CoW staging
  * extent and mark the corresponding part of the file range in the bitmap.
@@ -293,8 +316,9 @@ xrep_cow_find_bad(
         * If userspace is forcing us to rebuild the CoW fork or someone turned
         * on the debugging knob, replace everything in the CoW fork.
         */
-       if ((sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) ||
-           XFS_TEST_ERROR(sc->mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR))
+       if (XFS_TEST_ERROR(sc->mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR))
+               error = xrep_cow_debug_replacement(xc);
+       else if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD)
                error = xrep_cow_mark_file_range(xc, xc->irec.br_startblock,
                                xc->irec.br_blockcount);
 
@@ -375,8 +399,9 @@ xrep_cow_find_bad_rt(
         * turned on the debugging knob, replace everything in the
         * CoW fork and then scan for staging extents in the refcountbt.
         */
-       if ((sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) ||
-           XFS_TEST_ERROR(sc->mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR))
+       if (XFS_TEST_ERROR(sc->mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR))
+               error = xrep_cow_debug_replacement(xc);
+       else if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD)
                error = xrep_cow_mark_file_range(xc, xc->irec.br_startblock,
                                xc->irec.br_blockcount);