162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2022-2023 Oracle.  All Rights Reserved.
462306a36Sopenharmony_ci * Author: Darrick J. Wong <djwong@kernel.org>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "xfs.h"
762306a36Sopenharmony_ci#include "xfs_fs.h"
862306a36Sopenharmony_ci#include "xfs_shared.h"
962306a36Sopenharmony_ci#include "xfs_format.h"
1062306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1162306a36Sopenharmony_ci#include "xfs_mount.h"
1262306a36Sopenharmony_ci#include "xfs_btree.h"
1362306a36Sopenharmony_ci#include "xfs_log_format.h"
1462306a36Sopenharmony_ci#include "xfs_trans.h"
1562306a36Sopenharmony_ci#include "xfs_sb.h"
1662306a36Sopenharmony_ci#include "xfs_inode.h"
1762306a36Sopenharmony_ci#include "xfs_alloc.h"
1862306a36Sopenharmony_ci#include "xfs_alloc_btree.h"
1962306a36Sopenharmony_ci#include "xfs_ialloc.h"
2062306a36Sopenharmony_ci#include "xfs_ialloc_btree.h"
2162306a36Sopenharmony_ci#include "xfs_rmap.h"
2262306a36Sopenharmony_ci#include "xfs_rmap_btree.h"
2362306a36Sopenharmony_ci#include "xfs_refcount_btree.h"
2462306a36Sopenharmony_ci#include "xfs_extent_busy.h"
2562306a36Sopenharmony_ci#include "xfs_ag.h"
2662306a36Sopenharmony_ci#include "xfs_ag_resv.h"
2762306a36Sopenharmony_ci#include "xfs_quota.h"
2862306a36Sopenharmony_ci#include "xfs_qm.h"
2962306a36Sopenharmony_ci#include "xfs_bmap.h"
3062306a36Sopenharmony_ci#include "xfs_da_format.h"
3162306a36Sopenharmony_ci#include "xfs_da_btree.h"
3262306a36Sopenharmony_ci#include "xfs_attr.h"
3362306a36Sopenharmony_ci#include "xfs_attr_remote.h"
3462306a36Sopenharmony_ci#include "scrub/scrub.h"
3562306a36Sopenharmony_ci#include "scrub/common.h"
3662306a36Sopenharmony_ci#include "scrub/trace.h"
3762306a36Sopenharmony_ci#include "scrub/repair.h"
3862306a36Sopenharmony_ci#include "scrub/bitmap.h"
3962306a36Sopenharmony_ci#include "scrub/reap.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * Disposal of Blocks from Old Metadata
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Now that we've constructed a new btree to replace the damaged one, we want
4562306a36Sopenharmony_ci * to dispose of the blocks that (we think) the old btree was using.
4662306a36Sopenharmony_ci * Previously, we used the rmapbt to collect the extents (bitmap) with the
4762306a36Sopenharmony_ci * rmap owner corresponding to the tree we rebuilt, collected extents for any
4862306a36Sopenharmony_ci * blocks with the same rmap owner that are owned by another data structure
4962306a36Sopenharmony_ci * (sublist), and subtracted sublist from bitmap.  In theory the extents
5062306a36Sopenharmony_ci * remaining in bitmap are the old btree's blocks.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * Unfortunately, it's possible that the btree was crosslinked with other
5362306a36Sopenharmony_ci * blocks on disk.  The rmap data can tell us if there are multiple owners, so
5462306a36Sopenharmony_ci * if the rmapbt says there is an owner of this block other than @oinfo, then
5562306a36Sopenharmony_ci * the block is crosslinked.  Remove the reverse mapping and continue.
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * If there is one rmap record, we can free the block, which removes the
5862306a36Sopenharmony_ci * reverse mapping but doesn't add the block to the free space.  Our repair
5962306a36Sopenharmony_ci * strategy is to hope the other metadata objects crosslinked on this block
6062306a36Sopenharmony_ci * will be rebuilt (atop different blocks), thereby removing all the cross
6162306a36Sopenharmony_ci * links.
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * If there are no rmap records at all, we also free the block.  If the btree
6462306a36Sopenharmony_ci * being rebuilt lives in the free space (bnobt/cntbt/rmapbt) then there isn't
6562306a36Sopenharmony_ci * supposed to be a rmap record and everything is ok.  For other btrees there
6662306a36Sopenharmony_ci * had to have been an rmap entry for the block to have ended up on @bitmap,
6762306a36Sopenharmony_ci * so if it's gone now there's something wrong and the fs will shut down.
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * Note: If there are multiple rmap records with only the same rmap owner as
7062306a36Sopenharmony_ci * the btree we're trying to rebuild and the block is indeed owned by another
7162306a36Sopenharmony_ci * data structure with the same rmap owner, then the block will be in sublist
7262306a36Sopenharmony_ci * and therefore doesn't need disposal.  If there are multiple rmap records
7362306a36Sopenharmony_ci * with only the same rmap owner but the block is not owned by something with
7462306a36Sopenharmony_ci * the same rmap owner, the block will be freed.
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * The caller is responsible for locking the AG headers for the entire rebuild
7762306a36Sopenharmony_ci * operation so that nothing else can sneak in and change the AG state while
7862306a36Sopenharmony_ci * we're not looking.  We must also invalidate any buffers associated with
7962306a36Sopenharmony_ci * @bitmap.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Information about reaping extents after a repair. */
8362306a36Sopenharmony_cistruct xreap_state {
8462306a36Sopenharmony_ci	struct xfs_scrub		*sc;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Reverse mapping owner and metadata reservation type. */
8762306a36Sopenharmony_ci	const struct xfs_owner_info	*oinfo;
8862306a36Sopenharmony_ci	enum xfs_ag_resv_type		resv;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* If true, roll the transaction before reaping the next extent. */
9162306a36Sopenharmony_ci	bool				force_roll;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* Number of deferred reaps attached to the current transaction. */
9462306a36Sopenharmony_ci	unsigned int			deferred;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* Number of invalidated buffers logged to the current transaction. */
9762306a36Sopenharmony_ci	unsigned int			invalidated;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Number of deferred reaps queued during the whole reap sequence. */
10062306a36Sopenharmony_ci	unsigned long long		total_deferred;
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Put a block back on the AGFL. */
10462306a36Sopenharmony_ciSTATIC int
10562306a36Sopenharmony_cixreap_put_freelist(
10662306a36Sopenharmony_ci	struct xfs_scrub	*sc,
10762306a36Sopenharmony_ci	xfs_agblock_t		agbno)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct xfs_buf		*agfl_bp;
11062306a36Sopenharmony_ci	int			error;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* Make sure there's space on the freelist. */
11362306a36Sopenharmony_ci	error = xrep_fix_freelist(sc, true);
11462306a36Sopenharmony_ci	if (error)
11562306a36Sopenharmony_ci		return error;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/*
11862306a36Sopenharmony_ci	 * Since we're "freeing" a lost block onto the AGFL, we have to
11962306a36Sopenharmony_ci	 * create an rmap for the block prior to merging it or else other
12062306a36Sopenharmony_ci	 * parts will break.
12162306a36Sopenharmony_ci	 */
12262306a36Sopenharmony_ci	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno, 1,
12362306a36Sopenharmony_ci			&XFS_RMAP_OINFO_AG);
12462306a36Sopenharmony_ci	if (error)
12562306a36Sopenharmony_ci		return error;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Put the block on the AGFL. */
12862306a36Sopenharmony_ci	error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &agfl_bp);
12962306a36Sopenharmony_ci	if (error)
13062306a36Sopenharmony_ci		return error;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	error = xfs_alloc_put_freelist(sc->sa.pag, sc->tp, sc->sa.agf_bp,
13362306a36Sopenharmony_ci			agfl_bp, agbno, 0);
13462306a36Sopenharmony_ci	if (error)
13562306a36Sopenharmony_ci		return error;
13662306a36Sopenharmony_ci	xfs_extent_busy_insert(sc->tp, sc->sa.pag, agbno, 1,
13762306a36Sopenharmony_ci			XFS_EXTENT_BUSY_SKIP_DISCARD);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* Are there any uncommitted reap operations? */
14362306a36Sopenharmony_cistatic inline bool xreap_dirty(const struct xreap_state *rs)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	if (rs->force_roll)
14662306a36Sopenharmony_ci		return true;
14762306a36Sopenharmony_ci	if (rs->deferred)
14862306a36Sopenharmony_ci		return true;
14962306a36Sopenharmony_ci	if (rs->invalidated)
15062306a36Sopenharmony_ci		return true;
15162306a36Sopenharmony_ci	if (rs->total_deferred)
15262306a36Sopenharmony_ci		return true;
15362306a36Sopenharmony_ci	return false;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define XREAP_MAX_BINVAL	(2048)
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/*
15962306a36Sopenharmony_ci * Decide if we want to roll the transaction after reaping an extent.  We don't
16062306a36Sopenharmony_ci * want to overrun the transaction reservation, so we prohibit more than
16162306a36Sopenharmony_ci * 128 EFIs per transaction.  For the same reason, we limit the number
16262306a36Sopenharmony_ci * of buffer invalidations to 2048.
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_cistatic inline bool xreap_want_roll(const struct xreap_state *rs)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	if (rs->force_roll)
16762306a36Sopenharmony_ci		return true;
16862306a36Sopenharmony_ci	if (rs->deferred > XREP_MAX_ITRUNCATE_EFIS)
16962306a36Sopenharmony_ci		return true;
17062306a36Sopenharmony_ci	if (rs->invalidated > XREAP_MAX_BINVAL)
17162306a36Sopenharmony_ci		return true;
17262306a36Sopenharmony_ci	return false;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic inline void xreap_reset(struct xreap_state *rs)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	rs->total_deferred += rs->deferred;
17862306a36Sopenharmony_ci	rs->deferred = 0;
17962306a36Sopenharmony_ci	rs->invalidated = 0;
18062306a36Sopenharmony_ci	rs->force_roll = false;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define XREAP_MAX_DEFER_CHAIN		(2048)
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci * Decide if we want to finish the deferred ops that are attached to the scrub
18762306a36Sopenharmony_ci * transaction.  We don't want to queue huge chains of deferred ops because
18862306a36Sopenharmony_ci * that can consume a lot of log space and kernel memory.  Hence we trigger a
18962306a36Sopenharmony_ci * xfs_defer_finish if there are more than 2048 deferred reap operations or the
19062306a36Sopenharmony_ci * caller did some real work.
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic inline bool
19362306a36Sopenharmony_cixreap_want_defer_finish(const struct xreap_state *rs)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	if (rs->force_roll)
19662306a36Sopenharmony_ci		return true;
19762306a36Sopenharmony_ci	if (rs->total_deferred > XREAP_MAX_DEFER_CHAIN)
19862306a36Sopenharmony_ci		return true;
19962306a36Sopenharmony_ci	return false;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline void xreap_defer_finish_reset(struct xreap_state *rs)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	rs->total_deferred = 0;
20562306a36Sopenharmony_ci	rs->deferred = 0;
20662306a36Sopenharmony_ci	rs->invalidated = 0;
20762306a36Sopenharmony_ci	rs->force_roll = false;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/* Try to invalidate the incore buffers for an extent that we're freeing. */
21162306a36Sopenharmony_ciSTATIC void
21262306a36Sopenharmony_cixreap_agextent_binval(
21362306a36Sopenharmony_ci	struct xreap_state	*rs,
21462306a36Sopenharmony_ci	xfs_agblock_t		agbno,
21562306a36Sopenharmony_ci	xfs_extlen_t		*aglenp)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct xfs_scrub	*sc = rs->sc;
21862306a36Sopenharmony_ci	struct xfs_perag	*pag = sc->sa.pag;
21962306a36Sopenharmony_ci	struct xfs_mount	*mp = sc->mp;
22062306a36Sopenharmony_ci	xfs_agnumber_t		agno = sc->sa.pag->pag_agno;
22162306a36Sopenharmony_ci	xfs_agblock_t		agbno_next = agbno + *aglenp;
22262306a36Sopenharmony_ci	xfs_agblock_t		bno = agbno;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/*
22562306a36Sopenharmony_ci	 * Avoid invalidating AG headers and post-EOFS blocks because we never
22662306a36Sopenharmony_ci	 * own those.
22762306a36Sopenharmony_ci	 */
22862306a36Sopenharmony_ci	if (!xfs_verify_agbno(pag, agbno) ||
22962306a36Sopenharmony_ci	    !xfs_verify_agbno(pag, agbno_next - 1))
23062306a36Sopenharmony_ci		return;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/*
23362306a36Sopenharmony_ci	 * If there are incore buffers for these blocks, invalidate them.  We
23462306a36Sopenharmony_ci	 * assume that the lack of any other known owners means that the buffer
23562306a36Sopenharmony_ci	 * can be locked without risk of deadlocking.  The buffer cache cannot
23662306a36Sopenharmony_ci	 * detect aliasing, so employ nested loops to scan for incore buffers
23762306a36Sopenharmony_ci	 * of any plausible size.
23862306a36Sopenharmony_ci	 */
23962306a36Sopenharmony_ci	while (bno < agbno_next) {
24062306a36Sopenharmony_ci		xfs_agblock_t	fsbcount;
24162306a36Sopenharmony_ci		xfs_agblock_t	max_fsbs;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		/*
24462306a36Sopenharmony_ci		 * Max buffer size is the max remote xattr buffer size, which
24562306a36Sopenharmony_ci		 * is one fs block larger than 64k.
24662306a36Sopenharmony_ci		 */
24762306a36Sopenharmony_ci		max_fsbs = min_t(xfs_agblock_t, agbno_next - bno,
24862306a36Sopenharmony_ci				xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX));
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		for (fsbcount = 1; fsbcount < max_fsbs; fsbcount++) {
25162306a36Sopenharmony_ci			struct xfs_buf	*bp = NULL;
25262306a36Sopenharmony_ci			xfs_daddr_t	daddr;
25362306a36Sopenharmony_ci			int		error;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci			daddr = XFS_AGB_TO_DADDR(mp, agno, bno);
25662306a36Sopenharmony_ci			error = xfs_buf_incore(mp->m_ddev_targp, daddr,
25762306a36Sopenharmony_ci					XFS_FSB_TO_BB(mp, fsbcount),
25862306a36Sopenharmony_ci					XBF_LIVESCAN, &bp);
25962306a36Sopenharmony_ci			if (error)
26062306a36Sopenharmony_ci				continue;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci			xfs_trans_bjoin(sc->tp, bp);
26362306a36Sopenharmony_ci			xfs_trans_binval(sc->tp, bp);
26462306a36Sopenharmony_ci			rs->invalidated++;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci			/*
26762306a36Sopenharmony_ci			 * Stop invalidating if we've hit the limit; we should
26862306a36Sopenharmony_ci			 * still have enough reservation left to free however
26962306a36Sopenharmony_ci			 * far we've gotten.
27062306a36Sopenharmony_ci			 */
27162306a36Sopenharmony_ci			if (rs->invalidated > XREAP_MAX_BINVAL) {
27262306a36Sopenharmony_ci				*aglenp -= agbno_next - bno;
27362306a36Sopenharmony_ci				goto out;
27462306a36Sopenharmony_ci			}
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci		bno++;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ciout:
28162306a36Sopenharmony_ci	trace_xreap_agextent_binval(sc->sa.pag, agbno, *aglenp);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/*
28562306a36Sopenharmony_ci * Figure out the longest run of blocks that we can dispose of with a single
28662306a36Sopenharmony_ci * call.  Cross-linked blocks should have their reverse mappings removed, but
28762306a36Sopenharmony_ci * single-owner extents can be freed.  AGFL blocks can only be put back one at
28862306a36Sopenharmony_ci * a time.
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_ciSTATIC int
29162306a36Sopenharmony_cixreap_agextent_select(
29262306a36Sopenharmony_ci	struct xreap_state	*rs,
29362306a36Sopenharmony_ci	xfs_agblock_t		agbno,
29462306a36Sopenharmony_ci	xfs_agblock_t		agbno_next,
29562306a36Sopenharmony_ci	bool			*crosslinked,
29662306a36Sopenharmony_ci	xfs_extlen_t		*aglenp)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct xfs_scrub	*sc = rs->sc;
29962306a36Sopenharmony_ci	struct xfs_btree_cur	*cur;
30062306a36Sopenharmony_ci	xfs_agblock_t		bno = agbno + 1;
30162306a36Sopenharmony_ci	xfs_extlen_t		len = 1;
30262306a36Sopenharmony_ci	int			error;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/*
30562306a36Sopenharmony_ci	 * Determine if there are any other rmap records covering the first
30662306a36Sopenharmony_ci	 * block of this extent.  If so, the block is crosslinked.
30762306a36Sopenharmony_ci	 */
30862306a36Sopenharmony_ci	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, sc->sa.agf_bp,
30962306a36Sopenharmony_ci			sc->sa.pag);
31062306a36Sopenharmony_ci	error = xfs_rmap_has_other_keys(cur, agbno, 1, rs->oinfo,
31162306a36Sopenharmony_ci			crosslinked);
31262306a36Sopenharmony_ci	if (error)
31362306a36Sopenharmony_ci		goto out_cur;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* AGFL blocks can only be deal with one at a time. */
31662306a36Sopenharmony_ci	if (rs->resv == XFS_AG_RESV_AGFL)
31762306a36Sopenharmony_ci		goto out_found;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/*
32062306a36Sopenharmony_ci	 * Figure out how many of the subsequent blocks have the same crosslink
32162306a36Sopenharmony_ci	 * status.
32262306a36Sopenharmony_ci	 */
32362306a36Sopenharmony_ci	while (bno < agbno_next) {
32462306a36Sopenharmony_ci		bool		also_crosslinked;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		error = xfs_rmap_has_other_keys(cur, bno, 1, rs->oinfo,
32762306a36Sopenharmony_ci				&also_crosslinked);
32862306a36Sopenharmony_ci		if (error)
32962306a36Sopenharmony_ci			goto out_cur;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		if (*crosslinked != also_crosslinked)
33262306a36Sopenharmony_ci			break;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		len++;
33562306a36Sopenharmony_ci		bno++;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ciout_found:
33962306a36Sopenharmony_ci	*aglenp = len;
34062306a36Sopenharmony_ci	trace_xreap_agextent_select(sc->sa.pag, agbno, len, *crosslinked);
34162306a36Sopenharmony_ciout_cur:
34262306a36Sopenharmony_ci	xfs_btree_del_cursor(cur, error);
34362306a36Sopenharmony_ci	return error;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/*
34762306a36Sopenharmony_ci * Dispose of as much of the beginning of this AG extent as possible.  The
34862306a36Sopenharmony_ci * number of blocks disposed of will be returned in @aglenp.
34962306a36Sopenharmony_ci */
35062306a36Sopenharmony_ciSTATIC int
35162306a36Sopenharmony_cixreap_agextent_iter(
35262306a36Sopenharmony_ci	struct xreap_state	*rs,
35362306a36Sopenharmony_ci	xfs_agblock_t		agbno,
35462306a36Sopenharmony_ci	xfs_extlen_t		*aglenp,
35562306a36Sopenharmony_ci	bool			crosslinked)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct xfs_scrub	*sc = rs->sc;
35862306a36Sopenharmony_ci	xfs_fsblock_t		fsbno;
35962306a36Sopenharmony_ci	int			error = 0;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.pag->pag_agno, agbno);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/*
36462306a36Sopenharmony_ci	 * If there are other rmappings, this block is cross linked and must
36562306a36Sopenharmony_ci	 * not be freed.  Remove the reverse mapping and move on.  Otherwise,
36662306a36Sopenharmony_ci	 * we were the only owner of the block, so free the extent, which will
36762306a36Sopenharmony_ci	 * also remove the rmap.
36862306a36Sopenharmony_ci	 *
36962306a36Sopenharmony_ci	 * XXX: XFS doesn't support detecting the case where a single block
37062306a36Sopenharmony_ci	 * metadata structure is crosslinked with a multi-block structure
37162306a36Sopenharmony_ci	 * because the buffer cache doesn't detect aliasing problems, so we
37262306a36Sopenharmony_ci	 * can't fix 100% of crosslinking problems (yet).  The verifiers will
37362306a36Sopenharmony_ci	 * blow on writeout, the filesystem will shut down, and the admin gets
37462306a36Sopenharmony_ci	 * to run xfs_repair.
37562306a36Sopenharmony_ci	 */
37662306a36Sopenharmony_ci	if (crosslinked) {
37762306a36Sopenharmony_ci		trace_xreap_dispose_unmap_extent(sc->sa.pag, agbno, *aglenp);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		rs->force_roll = true;
38062306a36Sopenharmony_ci		return xfs_rmap_free(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno,
38162306a36Sopenharmony_ci				*aglenp, rs->oinfo);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	trace_xreap_dispose_free_extent(sc->sa.pag, agbno, *aglenp);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/*
38762306a36Sopenharmony_ci	 * Invalidate as many buffers as we can, starting at agbno.  If this
38862306a36Sopenharmony_ci	 * function sets *aglenp to zero, the transaction is full of logged
38962306a36Sopenharmony_ci	 * buffer invalidations, so we need to return early so that we can
39062306a36Sopenharmony_ci	 * roll and retry.
39162306a36Sopenharmony_ci	 */
39262306a36Sopenharmony_ci	xreap_agextent_binval(rs, agbno, aglenp);
39362306a36Sopenharmony_ci	if (*aglenp == 0) {
39462306a36Sopenharmony_ci		ASSERT(xreap_want_roll(rs));
39562306a36Sopenharmony_ci		return 0;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* Put blocks back on the AGFL one at a time. */
39962306a36Sopenharmony_ci	if (rs->resv == XFS_AG_RESV_AGFL) {
40062306a36Sopenharmony_ci		ASSERT(*aglenp == 1);
40162306a36Sopenharmony_ci		error = xreap_put_freelist(sc, agbno);
40262306a36Sopenharmony_ci		if (error)
40362306a36Sopenharmony_ci			return error;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		rs->force_roll = true;
40662306a36Sopenharmony_ci		return 0;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * Use deferred frees to get rid of the old btree blocks to try to
41162306a36Sopenharmony_ci	 * minimize the window in which we could crash and lose the old blocks.
41262306a36Sopenharmony_ci	 */
41362306a36Sopenharmony_ci	error = __xfs_free_extent_later(sc->tp, fsbno, *aglenp, rs->oinfo,
41462306a36Sopenharmony_ci			rs->resv, true);
41562306a36Sopenharmony_ci	if (error)
41662306a36Sopenharmony_ci		return error;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	rs->deferred++;
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/*
42362306a36Sopenharmony_ci * Break an AG metadata extent into sub-extents by fate (crosslinked, not
42462306a36Sopenharmony_ci * crosslinked), and dispose of each sub-extent separately.
42562306a36Sopenharmony_ci */
42662306a36Sopenharmony_ciSTATIC int
42762306a36Sopenharmony_cixreap_agmeta_extent(
42862306a36Sopenharmony_ci	uint64_t		fsbno,
42962306a36Sopenharmony_ci	uint64_t		len,
43062306a36Sopenharmony_ci	void			*priv)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct xreap_state	*rs = priv;
43362306a36Sopenharmony_ci	struct xfs_scrub	*sc = rs->sc;
43462306a36Sopenharmony_ci	xfs_agblock_t		agbno = fsbno;
43562306a36Sopenharmony_ci	xfs_agblock_t		agbno_next = agbno + len;
43662306a36Sopenharmony_ci	int			error = 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	ASSERT(len <= XFS_MAX_BMBT_EXTLEN);
43962306a36Sopenharmony_ci	ASSERT(sc->ip == NULL);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	while (agbno < agbno_next) {
44262306a36Sopenharmony_ci		xfs_extlen_t	aglen;
44362306a36Sopenharmony_ci		bool		crosslinked;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		error = xreap_agextent_select(rs, agbno, agbno_next,
44662306a36Sopenharmony_ci				&crosslinked, &aglen);
44762306a36Sopenharmony_ci		if (error)
44862306a36Sopenharmony_ci			return error;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		error = xreap_agextent_iter(rs, agbno, &aglen, crosslinked);
45162306a36Sopenharmony_ci		if (error)
45262306a36Sopenharmony_ci			return error;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		if (xreap_want_defer_finish(rs)) {
45562306a36Sopenharmony_ci			error = xrep_defer_finish(sc);
45662306a36Sopenharmony_ci			if (error)
45762306a36Sopenharmony_ci				return error;
45862306a36Sopenharmony_ci			xreap_defer_finish_reset(rs);
45962306a36Sopenharmony_ci		} else if (xreap_want_roll(rs)) {
46062306a36Sopenharmony_ci			error = xrep_roll_ag_trans(sc);
46162306a36Sopenharmony_ci			if (error)
46262306a36Sopenharmony_ci				return error;
46362306a36Sopenharmony_ci			xreap_reset(rs);
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		agbno += aglen;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return 0;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/* Dispose of every block of every AG metadata extent in the bitmap. */
47362306a36Sopenharmony_ciint
47462306a36Sopenharmony_cixrep_reap_agblocks(
47562306a36Sopenharmony_ci	struct xfs_scrub		*sc,
47662306a36Sopenharmony_ci	struct xagb_bitmap		*bitmap,
47762306a36Sopenharmony_ci	const struct xfs_owner_info	*oinfo,
47862306a36Sopenharmony_ci	enum xfs_ag_resv_type		type)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct xreap_state		rs = {
48162306a36Sopenharmony_ci		.sc			= sc,
48262306a36Sopenharmony_ci		.oinfo			= oinfo,
48362306a36Sopenharmony_ci		.resv			= type,
48462306a36Sopenharmony_ci	};
48562306a36Sopenharmony_ci	int				error;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	ASSERT(xfs_has_rmapbt(sc->mp));
48862306a36Sopenharmony_ci	ASSERT(sc->ip == NULL);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	error = xagb_bitmap_walk(bitmap, xreap_agmeta_extent, &rs);
49162306a36Sopenharmony_ci	if (error)
49262306a36Sopenharmony_ci		return error;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (xreap_dirty(&rs))
49562306a36Sopenharmony_ci		return xrep_defer_finish(sc);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return 0;
49862306a36Sopenharmony_ci}
499