162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2017-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_log_format.h"
1162306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1262306a36Sopenharmony_ci#include "xfs_mount.h"
1362306a36Sopenharmony_ci#include "xfs_trans.h"
1462306a36Sopenharmony_ci#include "xfs_btree.h"
1562306a36Sopenharmony_ci#include "xfs_rmap.h"
1662306a36Sopenharmony_ci#include "xfs_refcount.h"
1762306a36Sopenharmony_ci#include "xfs_ag.h"
1862306a36Sopenharmony_ci#include "xfs_bit.h"
1962306a36Sopenharmony_ci#include "xfs_alloc.h"
2062306a36Sopenharmony_ci#include "xfs_alloc_btree.h"
2162306a36Sopenharmony_ci#include "xfs_ialloc_btree.h"
2262306a36Sopenharmony_ci#include "xfs_refcount_btree.h"
2362306a36Sopenharmony_ci#include "scrub/scrub.h"
2462306a36Sopenharmony_ci#include "scrub/common.h"
2562306a36Sopenharmony_ci#include "scrub/btree.h"
2662306a36Sopenharmony_ci#include "scrub/bitmap.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * Set us up to scrub reverse mapping btrees.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ciint
3262306a36Sopenharmony_cixchk_setup_ag_rmapbt(
3362306a36Sopenharmony_ci	struct xfs_scrub	*sc)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	if (xchk_need_intent_drain(sc))
3662306a36Sopenharmony_ci		xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return xchk_setup_ag_btree(sc, false);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* Reverse-mapping scrubber. */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct xchk_rmap {
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * The furthest-reaching of the rmapbt records that we've already
4662306a36Sopenharmony_ci	 * processed.  This enables us to detect overlapping records for space
4762306a36Sopenharmony_ci	 * allocations that cannot be shared.
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	struct xfs_rmap_irec	overlap_rec;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/*
5262306a36Sopenharmony_ci	 * The previous rmapbt record, so that we can check for two records
5362306a36Sopenharmony_ci	 * that could be one.
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	struct xfs_rmap_irec	prev_rec;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Bitmaps containing all blocks for each type of AG metadata. */
5862306a36Sopenharmony_ci	struct xagb_bitmap	fs_owned;
5962306a36Sopenharmony_ci	struct xagb_bitmap	log_owned;
6062306a36Sopenharmony_ci	struct xagb_bitmap	ag_owned;
6162306a36Sopenharmony_ci	struct xagb_bitmap	inobt_owned;
6262306a36Sopenharmony_ci	struct xagb_bitmap	refcbt_owned;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	/* Did we complete the AG space metadata bitmaps? */
6562306a36Sopenharmony_ci	bool			bitmaps_complete;
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* Cross-reference a rmap against the refcount btree. */
6962306a36Sopenharmony_ciSTATIC void
7062306a36Sopenharmony_cixchk_rmapbt_xref_refc(
7162306a36Sopenharmony_ci	struct xfs_scrub	*sc,
7262306a36Sopenharmony_ci	struct xfs_rmap_irec	*irec)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	xfs_agblock_t		fbno;
7562306a36Sopenharmony_ci	xfs_extlen_t		flen;
7662306a36Sopenharmony_ci	bool			non_inode;
7762306a36Sopenharmony_ci	bool			is_bmbt;
7862306a36Sopenharmony_ci	bool			is_attr;
7962306a36Sopenharmony_ci	bool			is_unwritten;
8062306a36Sopenharmony_ci	int			error;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm))
8362306a36Sopenharmony_ci		return;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	non_inode = XFS_RMAP_NON_INODE_OWNER(irec->rm_owner);
8662306a36Sopenharmony_ci	is_bmbt = irec->rm_flags & XFS_RMAP_BMBT_BLOCK;
8762306a36Sopenharmony_ci	is_attr = irec->rm_flags & XFS_RMAP_ATTR_FORK;
8862306a36Sopenharmony_ci	is_unwritten = irec->rm_flags & XFS_RMAP_UNWRITTEN;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* If this is shared, must be a data fork extent. */
9162306a36Sopenharmony_ci	error = xfs_refcount_find_shared(sc->sa.refc_cur, irec->rm_startblock,
9262306a36Sopenharmony_ci			irec->rm_blockcount, &fbno, &flen, false);
9362306a36Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
9462306a36Sopenharmony_ci		return;
9562306a36Sopenharmony_ci	if (flen != 0 && (non_inode || is_attr || is_bmbt || is_unwritten))
9662306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* Cross-reference with the other btrees. */
10062306a36Sopenharmony_ciSTATIC void
10162306a36Sopenharmony_cixchk_rmapbt_xref(
10262306a36Sopenharmony_ci	struct xfs_scrub	*sc,
10362306a36Sopenharmony_ci	struct xfs_rmap_irec	*irec)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	xfs_agblock_t		agbno = irec->rm_startblock;
10662306a36Sopenharmony_ci	xfs_extlen_t		len = irec->rm_blockcount;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
10962306a36Sopenharmony_ci		return;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	xchk_xref_is_used_space(sc, agbno, len);
11262306a36Sopenharmony_ci	if (irec->rm_owner == XFS_RMAP_OWN_INODES)
11362306a36Sopenharmony_ci		xchk_xref_is_inode_chunk(sc, agbno, len);
11462306a36Sopenharmony_ci	else
11562306a36Sopenharmony_ci		xchk_xref_is_not_inode_chunk(sc, agbno, len);
11662306a36Sopenharmony_ci	if (irec->rm_owner == XFS_RMAP_OWN_COW)
11762306a36Sopenharmony_ci		xchk_xref_is_cow_staging(sc, irec->rm_startblock,
11862306a36Sopenharmony_ci				irec->rm_blockcount);
11962306a36Sopenharmony_ci	else
12062306a36Sopenharmony_ci		xchk_rmapbt_xref_refc(sc, irec);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/*
12462306a36Sopenharmony_ci * Check for bogus UNWRITTEN flags in the rmapbt node block keys.
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * In reverse mapping records, the file mapping extent state
12762306a36Sopenharmony_ci * (XFS_RMAP_OFF_UNWRITTEN) is a record attribute, not a key field.  It is not
12862306a36Sopenharmony_ci * involved in lookups in any way.  In older kernels, the functions that
12962306a36Sopenharmony_ci * convert rmapbt records to keys forgot to filter out the extent state bit,
13062306a36Sopenharmony_ci * even though the key comparison functions have filtered the flag correctly.
13162306a36Sopenharmony_ci * If we spot an rmap key with the unwritten bit set in rm_offset, we should
13262306a36Sopenharmony_ci * mark the btree as needing optimization to rebuild the btree without those
13362306a36Sopenharmony_ci * flags.
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_ciSTATIC void
13662306a36Sopenharmony_cixchk_rmapbt_check_unwritten_in_keyflags(
13762306a36Sopenharmony_ci	struct xchk_btree	*bs)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct xfs_scrub	*sc = bs->sc;
14062306a36Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
14162306a36Sopenharmony_ci	struct xfs_btree_block	*keyblock;
14262306a36Sopenharmony_ci	union xfs_btree_key	*lkey, *hkey;
14362306a36Sopenharmony_ci	__be64			badflag = cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
14462306a36Sopenharmony_ci	unsigned int		level;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_PREEN)
14762306a36Sopenharmony_ci		return;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	for (level = 1; level < cur->bc_nlevels; level++) {
15062306a36Sopenharmony_ci		struct xfs_buf	*bp;
15162306a36Sopenharmony_ci		unsigned int	ptr;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		/* Only check the first time we've seen this node block. */
15462306a36Sopenharmony_ci		if (cur->bc_levels[level].ptr > 1)
15562306a36Sopenharmony_ci			continue;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		keyblock = xfs_btree_get_block(cur, level, &bp);
15862306a36Sopenharmony_ci		for (ptr = 1; ptr <= be16_to_cpu(keyblock->bb_numrecs); ptr++) {
15962306a36Sopenharmony_ci			lkey = xfs_btree_key_addr(cur, ptr, keyblock);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci			if (lkey->rmap.rm_offset & badflag) {
16262306a36Sopenharmony_ci				xchk_btree_set_preen(sc, cur, level);
16362306a36Sopenharmony_ci				break;
16462306a36Sopenharmony_ci			}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci			hkey = xfs_btree_high_key_addr(cur, ptr, keyblock);
16762306a36Sopenharmony_ci			if (hkey->rmap.rm_offset & badflag) {
16862306a36Sopenharmony_ci				xchk_btree_set_preen(sc, cur, level);
16962306a36Sopenharmony_ci				break;
17062306a36Sopenharmony_ci			}
17162306a36Sopenharmony_ci		}
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic inline bool
17662306a36Sopenharmony_cixchk_rmapbt_is_shareable(
17762306a36Sopenharmony_ci	struct xfs_scrub		*sc,
17862306a36Sopenharmony_ci	const struct xfs_rmap_irec	*irec)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	if (!xfs_has_reflink(sc->mp))
18162306a36Sopenharmony_ci		return false;
18262306a36Sopenharmony_ci	if (XFS_RMAP_NON_INODE_OWNER(irec->rm_owner))
18362306a36Sopenharmony_ci		return false;
18462306a36Sopenharmony_ci	if (irec->rm_flags & (XFS_RMAP_BMBT_BLOCK | XFS_RMAP_ATTR_FORK |
18562306a36Sopenharmony_ci			      XFS_RMAP_UNWRITTEN))
18662306a36Sopenharmony_ci		return false;
18762306a36Sopenharmony_ci	return true;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* Flag failures for records that overlap but cannot. */
19162306a36Sopenharmony_ciSTATIC void
19262306a36Sopenharmony_cixchk_rmapbt_check_overlapping(
19362306a36Sopenharmony_ci	struct xchk_btree		*bs,
19462306a36Sopenharmony_ci	struct xchk_rmap		*cr,
19562306a36Sopenharmony_ci	const struct xfs_rmap_irec	*irec)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	xfs_agblock_t			pnext, inext;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
20062306a36Sopenharmony_ci		return;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* No previous record? */
20362306a36Sopenharmony_ci	if (cr->overlap_rec.rm_blockcount == 0)
20462306a36Sopenharmony_ci		goto set_prev;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Do overlap_rec and irec overlap? */
20762306a36Sopenharmony_ci	pnext = cr->overlap_rec.rm_startblock + cr->overlap_rec.rm_blockcount;
20862306a36Sopenharmony_ci	if (pnext <= irec->rm_startblock)
20962306a36Sopenharmony_ci		goto set_prev;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* Overlap is only allowed if both records are data fork mappings. */
21262306a36Sopenharmony_ci	if (!xchk_rmapbt_is_shareable(bs->sc, &cr->overlap_rec) ||
21362306a36Sopenharmony_ci	    !xchk_rmapbt_is_shareable(bs->sc, irec))
21462306a36Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/* Save whichever rmap record extends furthest. */
21762306a36Sopenharmony_ci	inext = irec->rm_startblock + irec->rm_blockcount;
21862306a36Sopenharmony_ci	if (pnext > inext)
21962306a36Sopenharmony_ci		return;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ciset_prev:
22262306a36Sopenharmony_ci	memcpy(&cr->overlap_rec, irec, sizeof(struct xfs_rmap_irec));
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* Decide if two reverse-mapping records can be merged. */
22662306a36Sopenharmony_cistatic inline bool
22762306a36Sopenharmony_cixchk_rmap_mergeable(
22862306a36Sopenharmony_ci	struct xchk_rmap		*cr,
22962306a36Sopenharmony_ci	const struct xfs_rmap_irec	*r2)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	const struct xfs_rmap_irec	*r1 = &cr->prev_rec;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Ignore if prev_rec is not yet initialized. */
23462306a36Sopenharmony_ci	if (cr->prev_rec.rm_blockcount == 0)
23562306a36Sopenharmony_ci		return false;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (r1->rm_owner != r2->rm_owner)
23862306a36Sopenharmony_ci		return false;
23962306a36Sopenharmony_ci	if (r1->rm_startblock + r1->rm_blockcount != r2->rm_startblock)
24062306a36Sopenharmony_ci		return false;
24162306a36Sopenharmony_ci	if ((unsigned long long)r1->rm_blockcount + r2->rm_blockcount >
24262306a36Sopenharmony_ci	    XFS_RMAP_LEN_MAX)
24362306a36Sopenharmony_ci		return false;
24462306a36Sopenharmony_ci	if (XFS_RMAP_NON_INODE_OWNER(r2->rm_owner))
24562306a36Sopenharmony_ci		return true;
24662306a36Sopenharmony_ci	/* must be an inode owner below here */
24762306a36Sopenharmony_ci	if (r1->rm_flags != r2->rm_flags)
24862306a36Sopenharmony_ci		return false;
24962306a36Sopenharmony_ci	if (r1->rm_flags & XFS_RMAP_BMBT_BLOCK)
25062306a36Sopenharmony_ci		return true;
25162306a36Sopenharmony_ci	return r1->rm_offset + r1->rm_blockcount == r2->rm_offset;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/* Flag failures for records that could be merged. */
25562306a36Sopenharmony_ciSTATIC void
25662306a36Sopenharmony_cixchk_rmapbt_check_mergeable(
25762306a36Sopenharmony_ci	struct xchk_btree		*bs,
25862306a36Sopenharmony_ci	struct xchk_rmap		*cr,
25962306a36Sopenharmony_ci	const struct xfs_rmap_irec	*irec)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
26262306a36Sopenharmony_ci		return;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (xchk_rmap_mergeable(cr, irec))
26562306a36Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	memcpy(&cr->prev_rec, irec, sizeof(struct xfs_rmap_irec));
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/* Compare an rmap for AG metadata against the metadata walk. */
27162306a36Sopenharmony_ciSTATIC int
27262306a36Sopenharmony_cixchk_rmapbt_mark_bitmap(
27362306a36Sopenharmony_ci	struct xchk_btree		*bs,
27462306a36Sopenharmony_ci	struct xchk_rmap		*cr,
27562306a36Sopenharmony_ci	const struct xfs_rmap_irec	*irec)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct xfs_scrub		*sc = bs->sc;
27862306a36Sopenharmony_ci	struct xagb_bitmap		*bmp = NULL;
27962306a36Sopenharmony_ci	xfs_extlen_t			fsbcount = irec->rm_blockcount;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/*
28262306a36Sopenharmony_ci	 * Skip corrupt records.  It is essential that we detect records in the
28362306a36Sopenharmony_ci	 * btree that cannot overlap but do, flag those as CORRUPT, and skip
28462306a36Sopenharmony_ci	 * the bitmap comparison to avoid generating false XCORRUPT reports.
28562306a36Sopenharmony_ci	 */
28662306a36Sopenharmony_ci	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
28762306a36Sopenharmony_ci		return 0;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/*
29062306a36Sopenharmony_ci	 * If the AG metadata walk didn't complete, there's no point in
29162306a36Sopenharmony_ci	 * comparing against partial results.
29262306a36Sopenharmony_ci	 */
29362306a36Sopenharmony_ci	if (!cr->bitmaps_complete)
29462306a36Sopenharmony_ci		return 0;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	switch (irec->rm_owner) {
29762306a36Sopenharmony_ci	case XFS_RMAP_OWN_FS:
29862306a36Sopenharmony_ci		bmp = &cr->fs_owned;
29962306a36Sopenharmony_ci		break;
30062306a36Sopenharmony_ci	case XFS_RMAP_OWN_LOG:
30162306a36Sopenharmony_ci		bmp = &cr->log_owned;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci	case XFS_RMAP_OWN_AG:
30462306a36Sopenharmony_ci		bmp = &cr->ag_owned;
30562306a36Sopenharmony_ci		break;
30662306a36Sopenharmony_ci	case XFS_RMAP_OWN_INOBT:
30762306a36Sopenharmony_ci		bmp = &cr->inobt_owned;
30862306a36Sopenharmony_ci		break;
30962306a36Sopenharmony_ci	case XFS_RMAP_OWN_REFC:
31062306a36Sopenharmony_ci		bmp = &cr->refcbt_owned;
31162306a36Sopenharmony_ci		break;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (!bmp)
31562306a36Sopenharmony_ci		return 0;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (xagb_bitmap_test(bmp, irec->rm_startblock, &fsbcount)) {
31862306a36Sopenharmony_ci		/*
31962306a36Sopenharmony_ci		 * The start of this reverse mapping corresponds to a set
32062306a36Sopenharmony_ci		 * region in the bitmap.  If the mapping covers more area than
32162306a36Sopenharmony_ci		 * the set region, then it covers space that wasn't found by
32262306a36Sopenharmony_ci		 * the AG metadata walk.
32362306a36Sopenharmony_ci		 */
32462306a36Sopenharmony_ci		if (fsbcount < irec->rm_blockcount)
32562306a36Sopenharmony_ci			xchk_btree_xref_set_corrupt(bs->sc,
32662306a36Sopenharmony_ci					bs->sc->sa.rmap_cur, 0);
32762306a36Sopenharmony_ci	} else {
32862306a36Sopenharmony_ci		/*
32962306a36Sopenharmony_ci		 * The start of this reverse mapping does not correspond to a
33062306a36Sopenharmony_ci		 * completely set region in the bitmap.  The region wasn't
33162306a36Sopenharmony_ci		 * fully set by walking the AG metadata, so this is a
33262306a36Sopenharmony_ci		 * cross-referencing corruption.
33362306a36Sopenharmony_ci		 */
33462306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(bs->sc, bs->sc->sa.rmap_cur, 0);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* Unset the region so that we can detect missing rmap records. */
33862306a36Sopenharmony_ci	return xagb_bitmap_clear(bmp, irec->rm_startblock, irec->rm_blockcount);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/* Scrub an rmapbt record. */
34262306a36Sopenharmony_ciSTATIC int
34362306a36Sopenharmony_cixchk_rmapbt_rec(
34462306a36Sopenharmony_ci	struct xchk_btree	*bs,
34562306a36Sopenharmony_ci	const union xfs_btree_rec *rec)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct xchk_rmap	*cr = bs->private;
34862306a36Sopenharmony_ci	struct xfs_rmap_irec	irec;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
35162306a36Sopenharmony_ci	    xfs_rmap_check_irec(bs->cur, &irec) != NULL) {
35262306a36Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
35362306a36Sopenharmony_ci		return 0;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	xchk_rmapbt_check_unwritten_in_keyflags(bs);
35762306a36Sopenharmony_ci	xchk_rmapbt_check_mergeable(bs, cr, &irec);
35862306a36Sopenharmony_ci	xchk_rmapbt_check_overlapping(bs, cr, &irec);
35962306a36Sopenharmony_ci	xchk_rmapbt_xref(bs->sc, &irec);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	return xchk_rmapbt_mark_bitmap(bs, cr, &irec);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/* Add an AGFL block to the rmap list. */
36562306a36Sopenharmony_ciSTATIC int
36662306a36Sopenharmony_cixchk_rmapbt_walk_agfl(
36762306a36Sopenharmony_ci	struct xfs_mount	*mp,
36862306a36Sopenharmony_ci	xfs_agblock_t		agbno,
36962306a36Sopenharmony_ci	void			*priv)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct xagb_bitmap	*bitmap = priv;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	return xagb_bitmap_set(bitmap, agbno, 1);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/*
37762306a36Sopenharmony_ci * Set up bitmaps mapping all the AG metadata to compare with the rmapbt
37862306a36Sopenharmony_ci * records.
37962306a36Sopenharmony_ci *
38062306a36Sopenharmony_ci * Grab our own btree cursors here if the scrub setup function didn't give us a
38162306a36Sopenharmony_ci * btree cursor due to reports of poor health.  We need to find out if the
38262306a36Sopenharmony_ci * rmapbt disagrees with primary metadata btrees to tag the rmapbt as being
38362306a36Sopenharmony_ci * XCORRUPT.
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_ciSTATIC int
38662306a36Sopenharmony_cixchk_rmapbt_walk_ag_metadata(
38762306a36Sopenharmony_ci	struct xfs_scrub	*sc,
38862306a36Sopenharmony_ci	struct xchk_rmap	*cr)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct xfs_mount	*mp = sc->mp;
39162306a36Sopenharmony_ci	struct xfs_buf		*agfl_bp;
39262306a36Sopenharmony_ci	struct xfs_agf		*agf = sc->sa.agf_bp->b_addr;
39362306a36Sopenharmony_ci	struct xfs_btree_cur	*cur;
39462306a36Sopenharmony_ci	int			error;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* OWN_FS: AG headers */
39762306a36Sopenharmony_ci	error = xagb_bitmap_set(&cr->fs_owned, XFS_SB_BLOCK(mp),
39862306a36Sopenharmony_ci			XFS_AGFL_BLOCK(mp) - XFS_SB_BLOCK(mp) + 1);
39962306a36Sopenharmony_ci	if (error)
40062306a36Sopenharmony_ci		goto out;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* OWN_LOG: Internal log */
40362306a36Sopenharmony_ci	if (xfs_ag_contains_log(mp, sc->sa.pag->pag_agno)) {
40462306a36Sopenharmony_ci		error = xagb_bitmap_set(&cr->log_owned,
40562306a36Sopenharmony_ci				XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart),
40662306a36Sopenharmony_ci				mp->m_sb.sb_logblocks);
40762306a36Sopenharmony_ci		if (error)
40862306a36Sopenharmony_ci			goto out;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* OWN_AG: bnobt, cntbt, rmapbt, and AGFL */
41262306a36Sopenharmony_ci	cur = sc->sa.bno_cur;
41362306a36Sopenharmony_ci	if (!cur)
41462306a36Sopenharmony_ci		cur = xfs_allocbt_init_cursor(sc->mp, sc->tp, sc->sa.agf_bp,
41562306a36Sopenharmony_ci				sc->sa.pag, XFS_BTNUM_BNO);
41662306a36Sopenharmony_ci	error = xagb_bitmap_set_btblocks(&cr->ag_owned, cur);
41762306a36Sopenharmony_ci	if (cur != sc->sa.bno_cur)
41862306a36Sopenharmony_ci		xfs_btree_del_cursor(cur, error);
41962306a36Sopenharmony_ci	if (error)
42062306a36Sopenharmony_ci		goto out;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	cur = sc->sa.cnt_cur;
42362306a36Sopenharmony_ci	if (!cur)
42462306a36Sopenharmony_ci		cur = xfs_allocbt_init_cursor(sc->mp, sc->tp, sc->sa.agf_bp,
42562306a36Sopenharmony_ci				sc->sa.pag, XFS_BTNUM_CNT);
42662306a36Sopenharmony_ci	error = xagb_bitmap_set_btblocks(&cr->ag_owned, cur);
42762306a36Sopenharmony_ci	if (cur != sc->sa.cnt_cur)
42862306a36Sopenharmony_ci		xfs_btree_del_cursor(cur, error);
42962306a36Sopenharmony_ci	if (error)
43062306a36Sopenharmony_ci		goto out;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	error = xagb_bitmap_set_btblocks(&cr->ag_owned, sc->sa.rmap_cur);
43362306a36Sopenharmony_ci	if (error)
43462306a36Sopenharmony_ci		goto out;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &agfl_bp);
43762306a36Sopenharmony_ci	if (error)
43862306a36Sopenharmony_ci		goto out;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	error = xfs_agfl_walk(sc->mp, agf, agfl_bp, xchk_rmapbt_walk_agfl,
44162306a36Sopenharmony_ci			&cr->ag_owned);
44262306a36Sopenharmony_ci	xfs_trans_brelse(sc->tp, agfl_bp);
44362306a36Sopenharmony_ci	if (error)
44462306a36Sopenharmony_ci		goto out;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/* OWN_INOBT: inobt, finobt */
44762306a36Sopenharmony_ci	cur = sc->sa.ino_cur;
44862306a36Sopenharmony_ci	if (!cur)
44962306a36Sopenharmony_ci		cur = xfs_inobt_init_cursor(sc->sa.pag, sc->tp, sc->sa.agi_bp,
45062306a36Sopenharmony_ci				XFS_BTNUM_INO);
45162306a36Sopenharmony_ci	error = xagb_bitmap_set_btblocks(&cr->inobt_owned, cur);
45262306a36Sopenharmony_ci	if (cur != sc->sa.ino_cur)
45362306a36Sopenharmony_ci		xfs_btree_del_cursor(cur, error);
45462306a36Sopenharmony_ci	if (error)
45562306a36Sopenharmony_ci		goto out;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (xfs_has_finobt(sc->mp)) {
45862306a36Sopenharmony_ci		cur = sc->sa.fino_cur;
45962306a36Sopenharmony_ci		if (!cur)
46062306a36Sopenharmony_ci			cur = xfs_inobt_init_cursor(sc->sa.pag, sc->tp,
46162306a36Sopenharmony_ci					sc->sa.agi_bp, XFS_BTNUM_FINO);
46262306a36Sopenharmony_ci		error = xagb_bitmap_set_btblocks(&cr->inobt_owned, cur);
46362306a36Sopenharmony_ci		if (cur != sc->sa.fino_cur)
46462306a36Sopenharmony_ci			xfs_btree_del_cursor(cur, error);
46562306a36Sopenharmony_ci		if (error)
46662306a36Sopenharmony_ci			goto out;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* OWN_REFC: refcountbt */
47062306a36Sopenharmony_ci	if (xfs_has_reflink(sc->mp)) {
47162306a36Sopenharmony_ci		cur = sc->sa.refc_cur;
47262306a36Sopenharmony_ci		if (!cur)
47362306a36Sopenharmony_ci			cur = xfs_refcountbt_init_cursor(sc->mp, sc->tp,
47462306a36Sopenharmony_ci					sc->sa.agf_bp, sc->sa.pag);
47562306a36Sopenharmony_ci		error = xagb_bitmap_set_btblocks(&cr->refcbt_owned, cur);
47662306a36Sopenharmony_ci		if (cur != sc->sa.refc_cur)
47762306a36Sopenharmony_ci			xfs_btree_del_cursor(cur, error);
47862306a36Sopenharmony_ci		if (error)
47962306a36Sopenharmony_ci			goto out;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ciout:
48362306a36Sopenharmony_ci	/*
48462306a36Sopenharmony_ci	 * If there's an error, set XFAIL and disable the bitmap
48562306a36Sopenharmony_ci	 * cross-referencing checks, but proceed with the scrub anyway.
48662306a36Sopenharmony_ci	 */
48762306a36Sopenharmony_ci	if (error)
48862306a36Sopenharmony_ci		xchk_btree_xref_process_error(sc, sc->sa.rmap_cur,
48962306a36Sopenharmony_ci				sc->sa.rmap_cur->bc_nlevels - 1, &error);
49062306a36Sopenharmony_ci	else
49162306a36Sopenharmony_ci		cr->bitmaps_complete = true;
49262306a36Sopenharmony_ci	return 0;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci/*
49662306a36Sopenharmony_ci * Check for set regions in the bitmaps; if there are any, the rmap records do
49762306a36Sopenharmony_ci * not describe all the AG metadata.
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_ciSTATIC void
50062306a36Sopenharmony_cixchk_rmapbt_check_bitmaps(
50162306a36Sopenharmony_ci	struct xfs_scrub	*sc,
50262306a36Sopenharmony_ci	struct xchk_rmap	*cr)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct xfs_btree_cur	*cur = sc->sa.rmap_cur;
50562306a36Sopenharmony_ci	unsigned int		level;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
50862306a36Sopenharmony_ci				XFS_SCRUB_OFLAG_XFAIL))
50962306a36Sopenharmony_ci		return;
51062306a36Sopenharmony_ci	if (!cur)
51162306a36Sopenharmony_ci		return;
51262306a36Sopenharmony_ci	level = cur->bc_nlevels - 1;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/*
51562306a36Sopenharmony_ci	 * Any bitmap with bits still set indicates that the reverse mapping
51662306a36Sopenharmony_ci	 * doesn't cover the entire primary structure.
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	if (xagb_bitmap_hweight(&cr->fs_owned) != 0)
51962306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, cur, level);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (xagb_bitmap_hweight(&cr->log_owned) != 0)
52262306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, cur, level);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (xagb_bitmap_hweight(&cr->ag_owned) != 0)
52562306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, cur, level);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (xagb_bitmap_hweight(&cr->inobt_owned) != 0)
52862306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, cur, level);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (xagb_bitmap_hweight(&cr->refcbt_owned) != 0)
53162306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, cur, level);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci/* Scrub the rmap btree for some AG. */
53562306a36Sopenharmony_ciint
53662306a36Sopenharmony_cixchk_rmapbt(
53762306a36Sopenharmony_ci	struct xfs_scrub	*sc)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct xchk_rmap	*cr;
54062306a36Sopenharmony_ci	int			error;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	cr = kzalloc(sizeof(struct xchk_rmap), XCHK_GFP_FLAGS);
54362306a36Sopenharmony_ci	if (!cr)
54462306a36Sopenharmony_ci		return -ENOMEM;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	xagb_bitmap_init(&cr->fs_owned);
54762306a36Sopenharmony_ci	xagb_bitmap_init(&cr->log_owned);
54862306a36Sopenharmony_ci	xagb_bitmap_init(&cr->ag_owned);
54962306a36Sopenharmony_ci	xagb_bitmap_init(&cr->inobt_owned);
55062306a36Sopenharmony_ci	xagb_bitmap_init(&cr->refcbt_owned);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	error = xchk_rmapbt_walk_ag_metadata(sc, cr);
55362306a36Sopenharmony_ci	if (error)
55462306a36Sopenharmony_ci		goto out;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	error = xchk_btree(sc, sc->sa.rmap_cur, xchk_rmapbt_rec,
55762306a36Sopenharmony_ci			&XFS_RMAP_OINFO_AG, cr);
55862306a36Sopenharmony_ci	if (error)
55962306a36Sopenharmony_ci		goto out;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	xchk_rmapbt_check_bitmaps(sc, cr);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ciout:
56462306a36Sopenharmony_ci	xagb_bitmap_destroy(&cr->refcbt_owned);
56562306a36Sopenharmony_ci	xagb_bitmap_destroy(&cr->inobt_owned);
56662306a36Sopenharmony_ci	xagb_bitmap_destroy(&cr->ag_owned);
56762306a36Sopenharmony_ci	xagb_bitmap_destroy(&cr->log_owned);
56862306a36Sopenharmony_ci	xagb_bitmap_destroy(&cr->fs_owned);
56962306a36Sopenharmony_ci	kfree(cr);
57062306a36Sopenharmony_ci	return error;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/* xref check that the extent is owned only by a given owner */
57462306a36Sopenharmony_civoid
57562306a36Sopenharmony_cixchk_xref_is_only_owned_by(
57662306a36Sopenharmony_ci	struct xfs_scrub		*sc,
57762306a36Sopenharmony_ci	xfs_agblock_t			bno,
57862306a36Sopenharmony_ci	xfs_extlen_t			len,
57962306a36Sopenharmony_ci	const struct xfs_owner_info	*oinfo)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct xfs_rmap_matches		res;
58262306a36Sopenharmony_ci	int				error;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (!sc->sa.rmap_cur || xchk_skip_xref(sc->sm))
58562306a36Sopenharmony_ci		return;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	error = xfs_rmap_count_owners(sc->sa.rmap_cur, bno, len, oinfo, &res);
58862306a36Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))
58962306a36Sopenharmony_ci		return;
59062306a36Sopenharmony_ci	if (res.matches != 1)
59162306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
59262306a36Sopenharmony_ci	if (res.bad_non_owner_matches)
59362306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
59462306a36Sopenharmony_ci	if (res.non_owner_matches)
59562306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci/* xref check that the extent is not owned by a given owner */
59962306a36Sopenharmony_civoid
60062306a36Sopenharmony_cixchk_xref_is_not_owned_by(
60162306a36Sopenharmony_ci	struct xfs_scrub		*sc,
60262306a36Sopenharmony_ci	xfs_agblock_t			bno,
60362306a36Sopenharmony_ci	xfs_extlen_t			len,
60462306a36Sopenharmony_ci	const struct xfs_owner_info	*oinfo)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct xfs_rmap_matches		res;
60762306a36Sopenharmony_ci	int				error;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (!sc->sa.rmap_cur || xchk_skip_xref(sc->sm))
61062306a36Sopenharmony_ci		return;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	error = xfs_rmap_count_owners(sc->sa.rmap_cur, bno, len, oinfo, &res);
61362306a36Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))
61462306a36Sopenharmony_ci		return;
61562306a36Sopenharmony_ci	if (res.matches != 0)
61662306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
61762306a36Sopenharmony_ci	if (res.bad_non_owner_matches)
61862306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci/* xref check that the extent has no reverse mapping at all */
62262306a36Sopenharmony_civoid
62362306a36Sopenharmony_cixchk_xref_has_no_owner(
62462306a36Sopenharmony_ci	struct xfs_scrub	*sc,
62562306a36Sopenharmony_ci	xfs_agblock_t		bno,
62662306a36Sopenharmony_ci	xfs_extlen_t		len)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	enum xbtree_recpacking	outcome;
62962306a36Sopenharmony_ci	int			error;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (!sc->sa.rmap_cur || xchk_skip_xref(sc->sm))
63262306a36Sopenharmony_ci		return;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	error = xfs_rmap_has_records(sc->sa.rmap_cur, bno, len, &outcome);
63562306a36Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))
63662306a36Sopenharmony_ci		return;
63762306a36Sopenharmony_ci	if (outcome != XBTREE_RECPACKING_EMPTY)
63862306a36Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
63962306a36Sopenharmony_ci}
640