]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: allow queued realtime intents to drain before scrubbing
authorDarrick J. Wong <djwong@kernel.org>
Sun, 11 Aug 2024 06:26:01 +0000 (08:26 +0200)
committerChristoph Hellwig <hch@lst.de>
Mon, 12 Aug 2024 11:53:00 +0000 (13:53 +0200)
When a writer thread executes a chain of log intent items for the
realtime volume, the ILOCKs taken during each step are for each rt
metadata file, not the entire rt volume itself.  Although scrub takes
all rt metadata ILOCKs, this isn't sufficient to guard against scrub
checking the rt volume while that writer thread is in the middle of
finishing a chain because there's no higher level locking primitive
guarding the realtime volume.

When there's a collision, cross-referencing between data structures
(e.g. rtrmapbt and rtrefcountbt) yields false corruption events; if
repair is running, this results in incorrect repairs, which is
catastrophic.

Fix this by adding to the mount structure the same drain that we use to
protect scrub against concurrent AG updates, but this time for the
realtime volume.

[Contains a few cleanups from hch]

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

index 147af633d8b79f40eb7deef12fc4ce1d9b1f41c5..daa85708985a9feb47840ab259687d496a760c6b 100644 (file)
@@ -753,10 +753,8 @@ xchk_rtgroup_lock(
                 * assume that holding its ILOCK will suffice to coordinate
                 * with any rt intent chains involving this inode.
                 */
-               if (sc->ip && !xfs_is_metadata_inode(sc->ip)) {
-                       sr->rtlock_flags = rtglock_flags;
-                       return 0;
-               }
+               if (sc->ip && !xfs_is_metadata_inode(sc->ip))
+                       break;
 
                /*
                 * Decide if the rt group is quiet enough for all metadata to
@@ -777,21 +775,23 @@ xchk_rtgroup_lock(
                 * Obviously, this should be slanted against scrub and in favor
                 * of runtime threads.
                 */
-               if (!xfs_rtgroup_intent_busy(sr->rtg)) {
-                       sr->rtlock_flags = rtglock_flags;
-                       return 0;
-               }
+               if (!xfs_rtgroup_intent_busy(sr->rtg))
+                       break;
 
                xfs_rtgroup_unlock(sr->rtg, rtglock_flags);
 
                if (!(sc->flags & XCHK_FSGATES_DRAIN))
                        return -ECHRNG;
                error = xfs_rtgroup_intent_drain(sr->rtg);
-               if (error == -ERESTARTSYS)
-                       error = -EINTR;
-       } while (!error);
+               if (error) {
+                       if (error == -ERESTARTSYS)
+                               error = -EINTR;
+                       return error;
+               }
+       } while (1);
 
-       return error;
+       sr->rtlock_flags = rtglock_flags;
+       return 0;
 }
 
 /*