18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Oracle.  All Rights Reserved.
48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "xfs.h"
78c2ecf20Sopenharmony_ci#include "xfs_fs.h"
88c2ecf20Sopenharmony_ci#include "xfs_shared.h"
98c2ecf20Sopenharmony_ci#include "xfs_format.h"
108c2ecf20Sopenharmony_ci#include "xfs_btree.h"
118c2ecf20Sopenharmony_ci#include "xfs_rmap.h"
128c2ecf20Sopenharmony_ci#include "xfs_refcount.h"
138c2ecf20Sopenharmony_ci#include "scrub/scrub.h"
148c2ecf20Sopenharmony_ci#include "scrub/common.h"
158c2ecf20Sopenharmony_ci#include "scrub/btree.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * Set us up to scrub reference count btrees.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ciint
218c2ecf20Sopenharmony_cixchk_setup_ag_refcountbt(
228c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
238c2ecf20Sopenharmony_ci	struct xfs_inode	*ip)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	return xchk_setup_ag_btree(sc, ip, false);
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Reference count btree scrubber. */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * Confirming Reference Counts via Reverse Mappings
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * We want to count the reverse mappings overlapping a refcount record
348c2ecf20Sopenharmony_ci * (bno, len, refcount), allowing for the possibility that some of the
358c2ecf20Sopenharmony_ci * overlap may come from smaller adjoining reverse mappings, while some
368c2ecf20Sopenharmony_ci * comes from single extents which overlap the range entirely.  The
378c2ecf20Sopenharmony_ci * outer loop is as follows:
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * 1. For all reverse mappings overlapping the refcount extent,
408c2ecf20Sopenharmony_ci *    a. If a given rmap completely overlaps, mark it as seen.
418c2ecf20Sopenharmony_ci *    b. Otherwise, record the fragment (in agbno order) for later
428c2ecf20Sopenharmony_ci *       processing.
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * Once we've seen all the rmaps, we know that for all blocks in the
458c2ecf20Sopenharmony_ci * refcount record we want to find $refcount owners and we've already
468c2ecf20Sopenharmony_ci * visited $seen extents that overlap all the blocks.  Therefore, we
478c2ecf20Sopenharmony_ci * need to find ($refcount - $seen) owners for every block in the
488c2ecf20Sopenharmony_ci * extent; call that quantity $target_nr.  Proceed as follows:
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * 2. Pull the first $target_nr fragments from the list; all of them
518c2ecf20Sopenharmony_ci *    should start at or before the start of the extent.
528c2ecf20Sopenharmony_ci *    Call this subset of fragments the working set.
538c2ecf20Sopenharmony_ci * 3. Until there are no more unprocessed fragments,
548c2ecf20Sopenharmony_ci *    a. Find the shortest fragments in the set and remove them.
558c2ecf20Sopenharmony_ci *    b. Note the block number of the end of these fragments.
568c2ecf20Sopenharmony_ci *    c. Pull the same number of fragments from the list.  All of these
578c2ecf20Sopenharmony_ci *       fragments should start at the block number recorded in the
588c2ecf20Sopenharmony_ci *       previous step.
598c2ecf20Sopenharmony_ci *    d. Put those fragments in the set.
608c2ecf20Sopenharmony_ci * 4. Check that there are $target_nr fragments remaining in the list,
618c2ecf20Sopenharmony_ci *    and that they all end at or beyond the end of the refcount extent.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * If the refcount is correct, all the check conditions in the algorithm
648c2ecf20Sopenharmony_ci * should always hold true.  If not, the refcount is incorrect.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_cistruct xchk_refcnt_frag {
678c2ecf20Sopenharmony_ci	struct list_head	list;
688c2ecf20Sopenharmony_ci	struct xfs_rmap_irec	rm;
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistruct xchk_refcnt_check {
728c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc;
738c2ecf20Sopenharmony_ci	struct list_head	fragments;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* refcount extent we're examining */
768c2ecf20Sopenharmony_ci	xfs_agblock_t		bno;
778c2ecf20Sopenharmony_ci	xfs_extlen_t		len;
788c2ecf20Sopenharmony_ci	xfs_nlink_t		refcount;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* number of owners seen */
818c2ecf20Sopenharmony_ci	xfs_nlink_t		seen;
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/*
858c2ecf20Sopenharmony_ci * Decide if the given rmap is large enough that we can redeem it
868c2ecf20Sopenharmony_ci * towards refcount verification now, or if it's a fragment, in
878c2ecf20Sopenharmony_ci * which case we'll hang onto it in the hopes that we'll later
888c2ecf20Sopenharmony_ci * discover that we've collected exactly the correct number of
898c2ecf20Sopenharmony_ci * fragments as the refcountbt says we should have.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_ciSTATIC int
928c2ecf20Sopenharmony_cixchk_refcountbt_rmap_check(
938c2ecf20Sopenharmony_ci	struct xfs_btree_cur		*cur,
948c2ecf20Sopenharmony_ci	struct xfs_rmap_irec		*rec,
958c2ecf20Sopenharmony_ci	void				*priv)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct xchk_refcnt_check	*refchk = priv;
988c2ecf20Sopenharmony_ci	struct xchk_refcnt_frag		*frag;
998c2ecf20Sopenharmony_ci	xfs_agblock_t			rm_last;
1008c2ecf20Sopenharmony_ci	xfs_agblock_t			rc_last;
1018c2ecf20Sopenharmony_ci	int				error = 0;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (xchk_should_terminate(refchk->sc, &error))
1048c2ecf20Sopenharmony_ci		return error;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	rm_last = rec->rm_startblock + rec->rm_blockcount - 1;
1078c2ecf20Sopenharmony_ci	rc_last = refchk->bno + refchk->len - 1;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* Confirm that a single-owner refc extent is a CoW stage. */
1108c2ecf20Sopenharmony_ci	if (refchk->refcount == 1 && rec->rm_owner != XFS_RMAP_OWN_COW) {
1118c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(refchk->sc, cur, 0);
1128c2ecf20Sopenharmony_ci		return 0;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (rec->rm_startblock <= refchk->bno && rm_last >= rc_last) {
1168c2ecf20Sopenharmony_ci		/*
1178c2ecf20Sopenharmony_ci		 * The rmap overlaps the refcount record, so we can confirm
1188c2ecf20Sopenharmony_ci		 * one refcount owner seen.
1198c2ecf20Sopenharmony_ci		 */
1208c2ecf20Sopenharmony_ci		refchk->seen++;
1218c2ecf20Sopenharmony_ci	} else {
1228c2ecf20Sopenharmony_ci		/*
1238c2ecf20Sopenharmony_ci		 * This rmap covers only part of the refcount record, so
1248c2ecf20Sopenharmony_ci		 * save the fragment for later processing.  If the rmapbt
1258c2ecf20Sopenharmony_ci		 * is healthy each rmap_irec we see will be in agbno order
1268c2ecf20Sopenharmony_ci		 * so we don't need insertion sort here.
1278c2ecf20Sopenharmony_ci		 */
1288c2ecf20Sopenharmony_ci		frag = kmem_alloc(sizeof(struct xchk_refcnt_frag),
1298c2ecf20Sopenharmony_ci				KM_MAYFAIL);
1308c2ecf20Sopenharmony_ci		if (!frag)
1318c2ecf20Sopenharmony_ci			return -ENOMEM;
1328c2ecf20Sopenharmony_ci		memcpy(&frag->rm, rec, sizeof(frag->rm));
1338c2ecf20Sopenharmony_ci		list_add_tail(&frag->list, &refchk->fragments);
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/*
1408c2ecf20Sopenharmony_ci * Given a bunch of rmap fragments, iterate through them, keeping
1418c2ecf20Sopenharmony_ci * a running tally of the refcount.  If this ever deviates from
1428c2ecf20Sopenharmony_ci * what we expect (which is the refcountbt's refcount minus the
1438c2ecf20Sopenharmony_ci * number of extents that totally covered the refcountbt extent),
1448c2ecf20Sopenharmony_ci * we have a refcountbt error.
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_ciSTATIC void
1478c2ecf20Sopenharmony_cixchk_refcountbt_process_rmap_fragments(
1488c2ecf20Sopenharmony_ci	struct xchk_refcnt_check	*refchk)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct list_head		worklist;
1518c2ecf20Sopenharmony_ci	struct xchk_refcnt_frag		*frag;
1528c2ecf20Sopenharmony_ci	struct xchk_refcnt_frag		*n;
1538c2ecf20Sopenharmony_ci	xfs_agblock_t			bno;
1548c2ecf20Sopenharmony_ci	xfs_agblock_t			rbno;
1558c2ecf20Sopenharmony_ci	xfs_agblock_t			next_rbno;
1568c2ecf20Sopenharmony_ci	xfs_nlink_t			nr;
1578c2ecf20Sopenharmony_ci	xfs_nlink_t			target_nr;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	target_nr = refchk->refcount - refchk->seen;
1608c2ecf20Sopenharmony_ci	if (target_nr == 0)
1618c2ecf20Sopenharmony_ci		return;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/*
1648c2ecf20Sopenharmony_ci	 * There are (refchk->rc.rc_refcount - refchk->nr refcount)
1658c2ecf20Sopenharmony_ci	 * references we haven't found yet.  Pull that many off the
1668c2ecf20Sopenharmony_ci	 * fragment list and figure out where the smallest rmap ends
1678c2ecf20Sopenharmony_ci	 * (and therefore the next rmap should start).  All the rmaps
1688c2ecf20Sopenharmony_ci	 * we pull off should start at or before the beginning of the
1698c2ecf20Sopenharmony_ci	 * refcount record's range.
1708c2ecf20Sopenharmony_ci	 */
1718c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&worklist);
1728c2ecf20Sopenharmony_ci	rbno = NULLAGBLOCK;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* Make sure the fragments actually /are/ in agbno order. */
1758c2ecf20Sopenharmony_ci	bno = 0;
1768c2ecf20Sopenharmony_ci	list_for_each_entry(frag, &refchk->fragments, list) {
1778c2ecf20Sopenharmony_ci		if (frag->rm.rm_startblock < bno)
1788c2ecf20Sopenharmony_ci			goto done;
1798c2ecf20Sopenharmony_ci		bno = frag->rm.rm_startblock;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/*
1838c2ecf20Sopenharmony_ci	 * Find all the rmaps that start at or before the refc extent,
1848c2ecf20Sopenharmony_ci	 * and put them on the worklist.
1858c2ecf20Sopenharmony_ci	 */
1868c2ecf20Sopenharmony_ci	nr = 0;
1878c2ecf20Sopenharmony_ci	list_for_each_entry_safe(frag, n, &refchk->fragments, list) {
1888c2ecf20Sopenharmony_ci		if (frag->rm.rm_startblock > refchk->bno || nr > target_nr)
1898c2ecf20Sopenharmony_ci			break;
1908c2ecf20Sopenharmony_ci		bno = frag->rm.rm_startblock + frag->rm.rm_blockcount;
1918c2ecf20Sopenharmony_ci		if (bno < rbno)
1928c2ecf20Sopenharmony_ci			rbno = bno;
1938c2ecf20Sopenharmony_ci		list_move_tail(&frag->list, &worklist);
1948c2ecf20Sopenharmony_ci		nr++;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/*
1988c2ecf20Sopenharmony_ci	 * We should have found exactly $target_nr rmap fragments starting
1998c2ecf20Sopenharmony_ci	 * at or before the refcount extent.
2008c2ecf20Sopenharmony_ci	 */
2018c2ecf20Sopenharmony_ci	if (nr != target_nr)
2028c2ecf20Sopenharmony_ci		goto done;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	while (!list_empty(&refchk->fragments)) {
2058c2ecf20Sopenharmony_ci		/* Discard any fragments ending at rbno from the worklist. */
2068c2ecf20Sopenharmony_ci		nr = 0;
2078c2ecf20Sopenharmony_ci		next_rbno = NULLAGBLOCK;
2088c2ecf20Sopenharmony_ci		list_for_each_entry_safe(frag, n, &worklist, list) {
2098c2ecf20Sopenharmony_ci			bno = frag->rm.rm_startblock + frag->rm.rm_blockcount;
2108c2ecf20Sopenharmony_ci			if (bno != rbno) {
2118c2ecf20Sopenharmony_ci				if (bno < next_rbno)
2128c2ecf20Sopenharmony_ci					next_rbno = bno;
2138c2ecf20Sopenharmony_ci				continue;
2148c2ecf20Sopenharmony_ci			}
2158c2ecf20Sopenharmony_ci			list_del(&frag->list);
2168c2ecf20Sopenharmony_ci			kmem_free(frag);
2178c2ecf20Sopenharmony_ci			nr++;
2188c2ecf20Sopenharmony_ci		}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		/* Try to add nr rmaps starting at rbno to the worklist. */
2218c2ecf20Sopenharmony_ci		list_for_each_entry_safe(frag, n, &refchk->fragments, list) {
2228c2ecf20Sopenharmony_ci			bno = frag->rm.rm_startblock + frag->rm.rm_blockcount;
2238c2ecf20Sopenharmony_ci			if (frag->rm.rm_startblock != rbno)
2248c2ecf20Sopenharmony_ci				goto done;
2258c2ecf20Sopenharmony_ci			list_move_tail(&frag->list, &worklist);
2268c2ecf20Sopenharmony_ci			if (next_rbno > bno)
2278c2ecf20Sopenharmony_ci				next_rbno = bno;
2288c2ecf20Sopenharmony_ci			nr--;
2298c2ecf20Sopenharmony_ci			if (nr == 0)
2308c2ecf20Sopenharmony_ci				break;
2318c2ecf20Sopenharmony_ci		}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		/*
2348c2ecf20Sopenharmony_ci		 * If we get here and nr > 0, this means that we added fewer
2358c2ecf20Sopenharmony_ci		 * items to the worklist than we discarded because the fragment
2368c2ecf20Sopenharmony_ci		 * list ran out of items.  Therefore, we cannot maintain the
2378c2ecf20Sopenharmony_ci		 * required refcount.  Something is wrong, so we're done.
2388c2ecf20Sopenharmony_ci		 */
2398c2ecf20Sopenharmony_ci		if (nr)
2408c2ecf20Sopenharmony_ci			goto done;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		rbno = next_rbno;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/*
2468c2ecf20Sopenharmony_ci	 * Make sure the last extent we processed ends at or beyond
2478c2ecf20Sopenharmony_ci	 * the end of the refcount extent.
2488c2ecf20Sopenharmony_ci	 */
2498c2ecf20Sopenharmony_ci	if (rbno < refchk->bno + refchk->len)
2508c2ecf20Sopenharmony_ci		goto done;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* Actually record us having seen the remaining refcount. */
2538c2ecf20Sopenharmony_ci	refchk->seen = refchk->refcount;
2548c2ecf20Sopenharmony_cidone:
2558c2ecf20Sopenharmony_ci	/* Delete fragments and work list. */
2568c2ecf20Sopenharmony_ci	list_for_each_entry_safe(frag, n, &worklist, list) {
2578c2ecf20Sopenharmony_ci		list_del(&frag->list);
2588c2ecf20Sopenharmony_ci		kmem_free(frag);
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci	list_for_each_entry_safe(frag, n, &refchk->fragments, list) {
2618c2ecf20Sopenharmony_ci		list_del(&frag->list);
2628c2ecf20Sopenharmony_ci		kmem_free(frag);
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci/* Use the rmap entries covering this extent to verify the refcount. */
2678c2ecf20Sopenharmony_ciSTATIC void
2688c2ecf20Sopenharmony_cixchk_refcountbt_xref_rmap(
2698c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
2708c2ecf20Sopenharmony_ci	xfs_agblock_t			bno,
2718c2ecf20Sopenharmony_ci	xfs_extlen_t			len,
2728c2ecf20Sopenharmony_ci	xfs_nlink_t			refcount)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct xchk_refcnt_check	refchk = {
2758c2ecf20Sopenharmony_ci		.sc = sc,
2768c2ecf20Sopenharmony_ci		.bno = bno,
2778c2ecf20Sopenharmony_ci		.len = len,
2788c2ecf20Sopenharmony_ci		.refcount = refcount,
2798c2ecf20Sopenharmony_ci		.seen = 0,
2808c2ecf20Sopenharmony_ci	};
2818c2ecf20Sopenharmony_ci	struct xfs_rmap_irec		low;
2828c2ecf20Sopenharmony_ci	struct xfs_rmap_irec		high;
2838c2ecf20Sopenharmony_ci	struct xchk_refcnt_frag		*frag;
2848c2ecf20Sopenharmony_ci	struct xchk_refcnt_frag		*n;
2858c2ecf20Sopenharmony_ci	int				error;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (!sc->sa.rmap_cur || xchk_skip_xref(sc->sm))
2888c2ecf20Sopenharmony_ci		return;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* Cross-reference with the rmapbt to confirm the refcount. */
2918c2ecf20Sopenharmony_ci	memset(&low, 0, sizeof(low));
2928c2ecf20Sopenharmony_ci	low.rm_startblock = bno;
2938c2ecf20Sopenharmony_ci	memset(&high, 0xFF, sizeof(high));
2948c2ecf20Sopenharmony_ci	high.rm_startblock = bno + len - 1;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&refchk.fragments);
2978c2ecf20Sopenharmony_ci	error = xfs_rmap_query_range(sc->sa.rmap_cur, &low, &high,
2988c2ecf20Sopenharmony_ci			&xchk_refcountbt_rmap_check, &refchk);
2998c2ecf20Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))
3008c2ecf20Sopenharmony_ci		goto out_free;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	xchk_refcountbt_process_rmap_fragments(&refchk);
3038c2ecf20Sopenharmony_ci	if (refcount != refchk.seen)
3048c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ciout_free:
3078c2ecf20Sopenharmony_ci	list_for_each_entry_safe(frag, n, &refchk.fragments, list) {
3088c2ecf20Sopenharmony_ci		list_del(&frag->list);
3098c2ecf20Sopenharmony_ci		kmem_free(frag);
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci/* Cross-reference with the other btrees. */
3148c2ecf20Sopenharmony_ciSTATIC void
3158c2ecf20Sopenharmony_cixchk_refcountbt_xref(
3168c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
3178c2ecf20Sopenharmony_ci	xfs_agblock_t		agbno,
3188c2ecf20Sopenharmony_ci	xfs_extlen_t		len,
3198c2ecf20Sopenharmony_ci	xfs_nlink_t		refcount)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
3228c2ecf20Sopenharmony_ci		return;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	xchk_xref_is_used_space(sc, agbno, len);
3258c2ecf20Sopenharmony_ci	xchk_xref_is_not_inode_chunk(sc, agbno, len);
3268c2ecf20Sopenharmony_ci	xchk_refcountbt_xref_rmap(sc, agbno, len, refcount);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci/* Scrub a refcountbt record. */
3308c2ecf20Sopenharmony_ciSTATIC int
3318c2ecf20Sopenharmony_cixchk_refcountbt_rec(
3328c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
3338c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = bs->cur->bc_mp;
3368c2ecf20Sopenharmony_ci	xfs_agblock_t		*cow_blocks = bs->private;
3378c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno = bs->cur->bc_ag.agno;
3388c2ecf20Sopenharmony_ci	xfs_agblock_t		bno;
3398c2ecf20Sopenharmony_ci	xfs_extlen_t		len;
3408c2ecf20Sopenharmony_ci	xfs_nlink_t		refcount;
3418c2ecf20Sopenharmony_ci	bool			has_cowflag;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	bno = be32_to_cpu(rec->refc.rc_startblock);
3448c2ecf20Sopenharmony_ci	len = be32_to_cpu(rec->refc.rc_blockcount);
3458c2ecf20Sopenharmony_ci	refcount = be32_to_cpu(rec->refc.rc_refcount);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* Only CoW records can have refcount == 1. */
3488c2ecf20Sopenharmony_ci	has_cowflag = (bno & XFS_REFC_COW_START);
3498c2ecf20Sopenharmony_ci	if ((refcount == 1 && !has_cowflag) || (refcount != 1 && has_cowflag))
3508c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
3518c2ecf20Sopenharmony_ci	if (has_cowflag)
3528c2ecf20Sopenharmony_ci		(*cow_blocks) += len;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* Check the extent. */
3558c2ecf20Sopenharmony_ci	bno &= ~XFS_REFC_COW_START;
3568c2ecf20Sopenharmony_ci	if (bno + len <= bno ||
3578c2ecf20Sopenharmony_ci	    !xfs_verify_agbno(mp, agno, bno) ||
3588c2ecf20Sopenharmony_ci	    !xfs_verify_agbno(mp, agno, bno + len - 1))
3598c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (refcount == 0)
3628c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	xchk_refcountbt_xref(bs->sc, bno, len, refcount);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return 0;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/* Make sure we have as many refc blocks as the rmap says. */
3708c2ecf20Sopenharmony_ciSTATIC void
3718c2ecf20Sopenharmony_cixchk_refcount_xref_rmap(
3728c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
3738c2ecf20Sopenharmony_ci	xfs_filblks_t		cow_blocks)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	xfs_extlen_t		refcbt_blocks = 0;
3768c2ecf20Sopenharmony_ci	xfs_filblks_t		blocks;
3778c2ecf20Sopenharmony_ci	int			error;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (!sc->sa.rmap_cur || xchk_skip_xref(sc->sm))
3808c2ecf20Sopenharmony_ci		return;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/* Check that we saw as many refcbt blocks as the rmap knows about. */
3838c2ecf20Sopenharmony_ci	error = xfs_btree_count_blocks(sc->sa.refc_cur, &refcbt_blocks);
3848c2ecf20Sopenharmony_ci	if (!xchk_btree_process_error(sc, sc->sa.refc_cur, 0, &error))
3858c2ecf20Sopenharmony_ci		return;
3868c2ecf20Sopenharmony_ci	error = xchk_count_rmap_ownedby_ag(sc, sc->sa.rmap_cur,
3878c2ecf20Sopenharmony_ci			&XFS_RMAP_OINFO_REFC, &blocks);
3888c2ecf20Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))
3898c2ecf20Sopenharmony_ci		return;
3908c2ecf20Sopenharmony_ci	if (blocks != refcbt_blocks)
3918c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/* Check that we saw as many cow blocks as the rmap knows about. */
3948c2ecf20Sopenharmony_ci	error = xchk_count_rmap_ownedby_ag(sc, sc->sa.rmap_cur,
3958c2ecf20Sopenharmony_ci			&XFS_RMAP_OINFO_COW, &blocks);
3968c2ecf20Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))
3978c2ecf20Sopenharmony_ci		return;
3988c2ecf20Sopenharmony_ci	if (blocks != cow_blocks)
3998c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci/* Scrub the refcount btree for some AG. */
4038c2ecf20Sopenharmony_ciint
4048c2ecf20Sopenharmony_cixchk_refcountbt(
4058c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	xfs_agblock_t		cow_blocks = 0;
4088c2ecf20Sopenharmony_ci	int			error;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	error = xchk_btree(sc, sc->sa.refc_cur, xchk_refcountbt_rec,
4118c2ecf20Sopenharmony_ci			&XFS_RMAP_OINFO_REFC, &cow_blocks);
4128c2ecf20Sopenharmony_ci	if (error)
4138c2ecf20Sopenharmony_ci		return error;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	xchk_refcount_xref_rmap(sc, cow_blocks);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	return 0;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/* xref check that a cow staging extent is marked in the refcountbt. */
4218c2ecf20Sopenharmony_civoid
4228c2ecf20Sopenharmony_cixchk_xref_is_cow_staging(
4238c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
4248c2ecf20Sopenharmony_ci	xfs_agblock_t			agbno,
4258c2ecf20Sopenharmony_ci	xfs_extlen_t			len)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct xfs_refcount_irec	rc;
4288c2ecf20Sopenharmony_ci	bool				has_cowflag;
4298c2ecf20Sopenharmony_ci	int				has_refcount;
4308c2ecf20Sopenharmony_ci	int				error;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm))
4338c2ecf20Sopenharmony_ci		return;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	/* Find the CoW staging extent. */
4368c2ecf20Sopenharmony_ci	error = xfs_refcount_lookup_le(sc->sa.refc_cur,
4378c2ecf20Sopenharmony_ci			agbno + XFS_REFC_COW_START, &has_refcount);
4388c2ecf20Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
4398c2ecf20Sopenharmony_ci		return;
4408c2ecf20Sopenharmony_ci	if (!has_refcount) {
4418c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
4428c2ecf20Sopenharmony_ci		return;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	error = xfs_refcount_get_rec(sc->sa.refc_cur, &rc, &has_refcount);
4468c2ecf20Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
4478c2ecf20Sopenharmony_ci		return;
4488c2ecf20Sopenharmony_ci	if (!has_refcount) {
4498c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
4508c2ecf20Sopenharmony_ci		return;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* CoW flag must be set, refcount must be 1. */
4548c2ecf20Sopenharmony_ci	has_cowflag = (rc.rc_startblock & XFS_REFC_COW_START);
4558c2ecf20Sopenharmony_ci	if (!has_cowflag || rc.rc_refcount != 1)
4568c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/* Must be at least as long as what was passed in */
4598c2ecf20Sopenharmony_ci	if (rc.rc_blockcount < len)
4608c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci/*
4648c2ecf20Sopenharmony_ci * xref check that the extent is not shared.  Only file data blocks
4658c2ecf20Sopenharmony_ci * can have multiple owners.
4668c2ecf20Sopenharmony_ci */
4678c2ecf20Sopenharmony_civoid
4688c2ecf20Sopenharmony_cixchk_xref_is_not_shared(
4698c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
4708c2ecf20Sopenharmony_ci	xfs_agblock_t		agbno,
4718c2ecf20Sopenharmony_ci	xfs_extlen_t		len)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	bool			shared;
4748c2ecf20Sopenharmony_ci	int			error;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm))
4778c2ecf20Sopenharmony_ci		return;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	error = xfs_refcount_has_record(sc->sa.refc_cur, agbno, len, &shared);
4808c2ecf20Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
4818c2ecf20Sopenharmony_ci		return;
4828c2ecf20Sopenharmony_ci	if (shared)
4838c2ecf20Sopenharmony_ci		xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
4848c2ecf20Sopenharmony_ci}
485