xfs: capture realtime CoW staging extents when rebuilding rt rmapbt

Walk the realtime refcount btree to find the CoW staging extents when
we're rebuilding the realtime rmap btree.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong
2024-11-20 16:21:13 -08:00
parent 477493082f
commit fe2efe9508
3 changed files with 141 additions and 0 deletions

View File

@@ -50,6 +50,7 @@ xrep_trans_commit(
struct xbitmap;
struct xagb_bitmap;
struct xrgb_bitmap;
struct xfsb_bitmap;
int xrep_fix_freelist(struct xfs_scrub *sc, int alloc_flags);

37
fs/xfs/scrub/rgb_bitmap.h Normal file
View File

@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2020-2024 Oracle. All Rights Reserved.
* Author: Darrick J. Wong <djwong@kernel.org>
*/
#ifndef __XFS_SCRUB_RGB_BITMAP_H__
#define __XFS_SCRUB_RGB_BITMAP_H__
/* Bitmaps, but for type-checked for xfs_rgblock_t */
struct xrgb_bitmap {
struct xbitmap32 rgbitmap;
};
static inline void xrgb_bitmap_init(struct xrgb_bitmap *bitmap)
{
xbitmap32_init(&bitmap->rgbitmap);
}
static inline void xrgb_bitmap_destroy(struct xrgb_bitmap *bitmap)
{
xbitmap32_destroy(&bitmap->rgbitmap);
}
static inline int xrgb_bitmap_set(struct xrgb_bitmap *bitmap,
xfs_rgblock_t start, xfs_extlen_t len)
{
return xbitmap32_set(&bitmap->rgbitmap, start, len);
}
static inline int xrgb_bitmap_walk(struct xrgb_bitmap *bitmap,
xbitmap32_walk_fn fn, void *priv)
{
return xbitmap32_walk(&bitmap->rgbitmap, fn, priv);
}
#endif /* __XFS_SCRUB_RGB_BITMAP_H__ */

View File

@@ -30,6 +30,7 @@
#include "xfs_rtalloc.h"
#include "xfs_ag.h"
#include "xfs_rtgroup.h"
#include "xfs_refcount.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
@@ -38,6 +39,7 @@
#include "scrub/repair.h"
#include "scrub/bitmap.h"
#include "scrub/fsb_bitmap.h"
#include "scrub/rgb_bitmap.h"
#include "scrub/xfile.h"
#include "scrub/xfarray.h"
#include "scrub/iscan.h"
@@ -423,6 +425,100 @@ xrep_rtrmap_scan_ag(
return error;
}
struct xrep_rtrmap_stash_run {
struct xrep_rtrmap *rr;
uint64_t owner;
};
static int
xrep_rtrmap_stash_run(
uint32_t start,
uint32_t len,
void *priv)
{
struct xrep_rtrmap_stash_run *rsr = priv;
struct xrep_rtrmap *rr = rsr->rr;
xfs_rgblock_t rgbno = start;
return xrep_rtrmap_stash(rr, rgbno, len, rsr->owner, 0, 0);
}
/*
* Emit rmaps for every extent of bits set in the bitmap. Caller must ensure
* that the ranges are in units of FS blocks.
*/
STATIC int
xrep_rtrmap_stash_bitmap(
struct xrep_rtrmap *rr,
struct xrgb_bitmap *bitmap,
const struct xfs_owner_info *oinfo)
{
struct xrep_rtrmap_stash_run rsr = {
.rr = rr,
.owner = oinfo->oi_owner,
};
return xrgb_bitmap_walk(bitmap, xrep_rtrmap_stash_run, &rsr);
}
/* Record a CoW staging extent. */
STATIC int
xrep_rtrmap_walk_cowblocks(
struct xfs_btree_cur *cur,
const struct xfs_refcount_irec *irec,
void *priv)
{
struct xrgb_bitmap *bitmap = priv;
if (!xfs_refcount_check_domain(irec) ||
irec->rc_domain != XFS_REFC_DOMAIN_COW)
return -EFSCORRUPTED;
return xrgb_bitmap_set(bitmap, irec->rc_startblock,
irec->rc_blockcount);
}
/*
* Collect rmaps for the blocks containing the refcount btree, and all CoW
* staging extents.
*/
STATIC int
xrep_rtrmap_find_refcount_rmaps(
struct xrep_rtrmap *rr)
{
struct xrgb_bitmap cow_blocks; /* COWBIT */
struct xfs_refcount_irec low = {
.rc_startblock = 0,
.rc_domain = XFS_REFC_DOMAIN_COW,
};
struct xfs_refcount_irec high = {
.rc_startblock = -1U,
.rc_domain = XFS_REFC_DOMAIN_COW,
};
struct xfs_scrub *sc = rr->sc;
int error;
if (!xfs_has_rtreflink(sc->mp))
return 0;
xrgb_bitmap_init(&cow_blocks);
/* Collect rmaps for CoW staging extents. */
error = xfs_refcount_query_range(sc->sr.refc_cur, &low, &high,
xrep_rtrmap_walk_cowblocks, &cow_blocks);
if (error)
goto out_bitmap;
/* Generate rmaps for everything. */
error = xrep_rtrmap_stash_bitmap(rr, &cow_blocks, &XFS_RMAP_OINFO_COW);
if (error)
goto out_bitmap;
out_bitmap:
xrgb_bitmap_destroy(&cow_blocks);
return error;
}
/* Count and check all collected records. */
STATIC int
xrep_rtrmap_check_record(
@@ -460,6 +556,13 @@ xrep_rtrmap_find_rmaps(
return error;
}
/* Find CoW staging extents. */
xrep_rtgroup_btcur_init(sc, &sc->sr);
error = xrep_rtrmap_find_refcount_rmaps(rr);
xchk_rtgroup_btcur_free(&sc->sr);
if (error)
return error;
/*
* Set up for a potentially lengthy filesystem scan by reducing our
* transaction resource usage for the duration. Specifically: