// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2017-2023 Oracle. All Rights Reserved. * Author: Darrick J. Wong <[email protected]> */ #include "xfs.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_trans.h" #include "xfs_ag.h" #include "xfs_btree.h" #include "xfs_rmap.h" #include "xfs_refcount.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/btree.h" #include "scrub/trace.h" #include "scrub/repair.h" /* * Set us up to scrub reference count btrees. */ int xchk_setup_ag_refcountbt( struct xfs_scrub *sc) { … } /* Reference count btree scrubber. */ /* * Confirming Reference Counts via Reverse Mappings * * We want to count the reverse mappings overlapping a refcount record * (bno, len, refcount), allowing for the possibility that some of the * overlap may come from smaller adjoining reverse mappings, while some * comes from single extents which overlap the range entirely. The * outer loop is as follows: * * 1. For all reverse mappings overlapping the refcount extent, * a. If a given rmap completely overlaps, mark it as seen. * b. Otherwise, record the fragment (in agbno order) for later * processing. * * Once we've seen all the rmaps, we know that for all blocks in the * refcount record we want to find $refcount owners and we've already * visited $seen extents that overlap all the blocks. Therefore, we * need to find ($refcount - $seen) owners for every block in the * extent; call that quantity $target_nr. Proceed as follows: * * 2. Pull the first $target_nr fragments from the list; all of them * should start at or before the start of the extent. * Call this subset of fragments the working set. * 3. Until there are no more unprocessed fragments, * a. Find the shortest fragments in the set and remove them. * b. Note the block number of the end of these fragments. * c. Pull the same number of fragments from the list. All of these * fragments should start at the block number recorded in the * previous step. * d. Put those fragments in the set. * 4. Check that there are $target_nr fragments remaining in the list, * and that they all end at or beyond the end of the refcount extent. * * If the refcount is correct, all the check conditions in the algorithm * should always hold true. If not, the refcount is incorrect. */ struct xchk_refcnt_frag { … }; struct xchk_refcnt_check { … }; /* * Decide if the given rmap is large enough that we can redeem it * towards refcount verification now, or if it's a fragment, in * which case we'll hang onto it in the hopes that we'll later * discover that we've collected exactly the correct number of * fragments as the refcountbt says we should have. */ STATIC int xchk_refcountbt_rmap_check( struct xfs_btree_cur *cur, const struct xfs_rmap_irec *rec, void *priv) { … } /* * Given a bunch of rmap fragments, iterate through them, keeping * a running tally of the refcount. If this ever deviates from * what we expect (which is the refcountbt's refcount minus the * number of extents that totally covered the refcountbt extent), * we have a refcountbt error. */ STATIC void xchk_refcountbt_process_rmap_fragments( struct xchk_refcnt_check *refchk) { … } /* Use the rmap entries covering this extent to verify the refcount. */ STATIC void xchk_refcountbt_xref_rmap( struct xfs_scrub *sc, const struct xfs_refcount_irec *irec) { … } /* Cross-reference with the other btrees. */ STATIC void xchk_refcountbt_xref( struct xfs_scrub *sc, const struct xfs_refcount_irec *irec) { … } struct xchk_refcbt_records { … }; STATIC int xchk_refcountbt_rmap_check_gap( struct xfs_btree_cur *cur, const struct xfs_rmap_irec *rec, void *priv) { … } /* * Make sure that a gap in the reference count records does not correspond to * overlapping records (i.e. shared extents) in the reverse mappings. */ static inline void xchk_refcountbt_xref_gaps( struct xfs_scrub *sc, struct xchk_refcbt_records *rrc, xfs_agblock_t bno) { … } static inline bool xchk_refcount_mergeable( struct xchk_refcbt_records *rrc, const struct xfs_refcount_irec *r2) { … } /* Flag failures for records that could be merged. */ STATIC void xchk_refcountbt_check_mergeable( struct xchk_btree *bs, struct xchk_refcbt_records *rrc, const struct xfs_refcount_irec *irec) { … } /* Scrub a refcountbt record. */ STATIC int xchk_refcountbt_rec( struct xchk_btree *bs, const union xfs_btree_rec *rec) { … } /* Make sure we have as many refc blocks as the rmap says. */ STATIC void xchk_refcount_xref_rmap( struct xfs_scrub *sc, xfs_filblks_t cow_blocks) { … } /* Scrub the refcount btree for some AG. */ int xchk_refcountbt( struct xfs_scrub *sc) { … } /* xref check that a cow staging extent is marked in the refcountbt. */ void xchk_xref_is_cow_staging( struct xfs_scrub *sc, xfs_agblock_t agbno, xfs_extlen_t len) { … } /* * xref check that the extent is not shared. Only file data blocks * can have multiple owners. */ void xchk_xref_is_not_shared( struct xfs_scrub *sc, xfs_agblock_t agbno, xfs_extlen_t len) { … } /* xref check that the extent is not being used for CoW staging. */ void xchk_xref_is_not_cow_staging( struct xfs_scrub *sc, xfs_agblock_t agbno, xfs_extlen_t len) { … }