xfs: refactor live buffer invalidation for repairs
authorDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:54:29 +0000 (14:54 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:58:48 +0000 (14:58 -0700)
In an upcoming patch, we will need to be able to look for xfs_buf
objects caching file-based metadata blocks without needing to walk the
(possibly corrupt) structures to find all the buffers.  Repair already
has most of the code needed to scan the buffer cache, so hoist these
utility functions.

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

index 0252a3b5b65ac0bf73be1fe5b20b348a7223727d..7ae6253395e72159c4839a0fe5cd985016aab269 100644 (file)
@@ -211,6 +211,48 @@ static inline void xreap_defer_finish_reset(struct xreap_state *rs)
        rs->force_roll = false;
 }
 
+/*
+ * Compute the maximum length of a buffer cache scan (in units of sectors),
+ * given a quantity of fs blocks.
+ */
+xfs_daddr_t
+xrep_bufscan_max_sectors(
+       struct xfs_mount        *mp,
+       xfs_extlen_t            fsblocks)
+{
+       int                     max_fsbs;
+
+       /* Remote xattr values are the largest buffers that we support. */
+       max_fsbs = xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX);
+
+       return XFS_FSB_TO_BB(mp, min_t(xfs_extlen_t, fsblocks, max_fsbs));
+}
+
+/*
+ * Return an incore buffer from a sector scan, or NULL if there are no buffers
+ * left to return.
+ */
+struct xfs_buf *
+xrep_bufscan_advance(
+       struct xfs_mount        *mp,
+       struct xrep_bufscan     *scan)
+{
+       scan->__sector_count += scan->daddr_step;
+       while (scan->__sector_count <= scan->max_sectors) {
+               struct xfs_buf  *bp = NULL;
+               int             error;
+
+               error = xfs_buf_incore(mp->m_ddev_targp, scan->daddr,
+                               scan->__sector_count, XBF_LIVESCAN, &bp);
+               if (!error)
+                       return bp;
+
+               scan->__sector_count += scan->daddr_step;
+       }
+
+       return NULL;
+}
+
 /* Try to invalidate the incore buffers for an extent that we're freeing. */
 STATIC void
 xreap_agextent_binval(
@@ -241,28 +283,15 @@ xreap_agextent_binval(
         * of any plausible size.
         */
        while (bno < agbno_next) {
-               xfs_agblock_t   fsbcount;
-               xfs_agblock_t   max_fsbs;
-
-               /*
-                * Max buffer size is the max remote xattr buffer size, which
-                * is one fs block larger than 64k.
-                */
-               max_fsbs = min_t(xfs_agblock_t, agbno_next - bno,
-                               xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX));
-
-               for (fsbcount = 1; fsbcount <= max_fsbs; fsbcount++) {
-                       struct xfs_buf  *bp = NULL;
-                       xfs_daddr_t     daddr;
-                       int             error;
-
-                       daddr = XFS_AGB_TO_DADDR(mp, agno, bno);
-                       error = xfs_buf_incore(mp->m_ddev_targp, daddr,
-                                       XFS_FSB_TO_BB(mp, fsbcount),
-                                       XBF_LIVESCAN, &bp);
-                       if (error)
-                               continue;
-
+               struct xrep_bufscan     scan = {
+                       .daddr          = XFS_AGB_TO_DADDR(mp, agno, bno),
+                       .max_sectors    = xrep_bufscan_max_sectors(mp,
+                                                       agbno_next - bno),
+                       .daddr_step     = XFS_FSB_TO_BB(mp, 1),
+               };
+               struct xfs_buf  *bp;
+
+               while ((bp = xrep_bufscan_advance(mp, &scan)) != NULL) {
                        xfs_trans_bjoin(sc->tp, bp);
                        xfs_trans_binval(sc->tp, bp);
                        rs->invalidated++;
index 0b69f16dd98f92a7c2ffc90176bbfc7d89cfcc0b..bb09e21fcb1725a5a0a794b1470c5f4f45058f1b 100644 (file)
@@ -14,4 +14,24 @@ int xrep_reap_agblocks(struct xfs_scrub *sc, struct xagb_bitmap *bitmap,
 int xrep_reap_fsblocks(struct xfs_scrub *sc, struct xfsb_bitmap *bitmap,
                const struct xfs_owner_info *oinfo);
 
+/* Buffer cache scan context. */
+struct xrep_bufscan {
+       /* Disk address for the buffers we want to scan. */
+       xfs_daddr_t             daddr;
+
+       /* Maximum number of sectors to scan. */
+       xfs_daddr_t             max_sectors;
+
+       /* Each round, increment the search length by this number of sectors. */
+       xfs_daddr_t             daddr_step;
+
+       /* Internal scan state; initialize to zero. */
+       xfs_daddr_t             __sector_count;
+};
+
+xfs_daddr_t xrep_bufscan_max_sectors(struct xfs_mount *mp,
+               xfs_extlen_t fsblocks);
+struct xfs_buf *xrep_bufscan_advance(struct xfs_mount *mp,
+               struct xrep_bufscan *scan);
+
 #endif /* __XFS_SCRUB_REAP_H__ */