summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-10-08 14:02:19 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-12-15 17:29:01 -0800
commitac91eff420073c90fdaf800c2996c36b7a5469a1 (patch)
tree75c4b6fe82cf1b63169f342bfafad394b85abe82
parent5b0524a7bdc4c6ed987dbb2cc6c364f3c865bb51 (diff)
xfs: refactor stale buffer scanning for repairs
In an upcoming patch, we will need to be able to look for buffers containing xattr metadata without necessarily being able to walk the xattr 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>
-rw-r--r--fs/xfs/scrub/repair.c67
-rw-r--r--fs/xfs/scrub/repair.h19
2 files changed, 67 insertions, 19 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 52113fbb0eaf..cdf4995b079c 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -918,6 +918,47 @@ xrep_put_freelist(
return 0;
}
+/*
+ * Compute the maximum length of a buffer cache scan (in units of sectors),
+ * given a quantity of fs blocks.
+ */
+xfs_daddr_t
+xrep_max_buf_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_buf_scan_advance(
+ struct xfs_mount *mp,
+ struct xrep_buf_scan *scan)
+{
+ scan->__sector_count += scan->daddr_step;
+ while (scan->__sector_count <= scan->max_sectors) {
+ struct xfs_buf *bp;
+
+ bp = xfs_buf_incore(mp->m_ddev_targp, scan->daddr,
+ scan->__sector_count, XBF_BCACHE_SCAN);
+ if (bp)
+ 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
xrep_agextent_reap_binval(
@@ -946,26 +987,14 @@ xrep_agextent_reap_binval(
* of any plausible size.
*/
for (; agbno < agbno_next; agbno++) {
- 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 - agbno,
- xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX));
-
- for (fsbcount = 1; fsbcount < max_fsbs; fsbcount++) {
- xfs_daddr_t daddr;
-
- daddr = XFS_AGB_TO_DADDR(mp, agno, agbno);
- bp = xfs_buf_incore(mp->m_ddev_targp, daddr,
- XFS_FSB_TO_BB(mp, fsbcount),
- XBF_BCACHE_SCAN);
- if (!bp)
- continue;
+ struct xrep_buf_scan scan = {
+ .daddr = XFS_AGB_TO_DADDR(mp, agno, agbno),
+ .max_sectors = xrep_max_buf_sectors(mp,
+ agbno_next - agbno),
+ .daddr_step = XFS_FSB_TO_BB(mp, 1),
+ };
+ while ((bp = xrep_buf_scan_advance(mp, &scan)) != NULL) {
xfs_trans_bjoin(sc->tp, bp);
xfs_trans_binval(sc->tp, bp);
}
diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h
index 97fa0e2c5a79..b46e91676621 100644
--- a/fs/xfs/scrub/repair.h
+++ b/fs/xfs/scrub/repair.h
@@ -88,6 +88,25 @@ int xrep_ag_init(struct xfs_scrub *sc, struct xfs_perag *pag,
int xrep_revalidate_allocbt(struct xfs_scrub *sc);
int xrep_revalidate_iallocbt(struct xfs_scrub *sc);
+/* Buffer cache scan context. */
+struct xrep_buf_scan {
+ /* 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_max_buf_sectors(struct xfs_mount *mp, xfs_extlen_t fsblocks);
+struct xfs_buf *xrep_buf_scan_advance(struct xfs_mount *mp,
+ struct xrep_buf_scan *scan);
+
/* Metadata repairers */
int xrep_probe(struct xfs_scrub *sc);