1739a2fe0SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later 2edc09b52SDarrick J. Wong /* 3ecc73f8aSDarrick J. Wong * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4739a2fe0SDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org> 5edc09b52SDarrick J. Wong */ 6edc09b52SDarrick J. Wong #include "xfs.h" 7edc09b52SDarrick J. Wong #include "xfs_fs.h" 8edc09b52SDarrick J. Wong #include "xfs_shared.h" 9edc09b52SDarrick J. Wong #include "xfs_format.h" 10d5c88131SDarrick J. Wong #include "xfs_trans_resv.h" 11d5c88131SDarrick J. Wong #include "xfs_mount.h" 12*422d5653SDave Chinner #include "xfs_ag.h" 13edc09b52SDarrick J. Wong #include "xfs_btree.h" 14edc09b52SDarrick J. Wong #include "xfs_rmap.h" 15f6d5fc21SDarrick J. Wong #include "xfs_refcount.h" 16edc09b52SDarrick J. Wong #include "scrub/scrub.h" 17edc09b52SDarrick J. Wong #include "scrub/common.h" 18edc09b52SDarrick J. Wong #include "scrub/btree.h" 1990148903SDarrick J. Wong #include "scrub/trace.h" 20edc09b52SDarrick J. Wong 21edc09b52SDarrick J. Wong /* 22edc09b52SDarrick J. Wong * Set us up to scrub reference count btrees. 23edc09b52SDarrick J. Wong */ 24edc09b52SDarrick J. Wong int 25c517b3aaSDarrick J. Wong xchk_setup_ag_refcountbt( 26026f57ebSDarrick J. Wong struct xfs_scrub *sc) 27edc09b52SDarrick J. Wong { 28466c525dSDarrick J. Wong if (xchk_need_intent_drain(sc)) 29466c525dSDarrick J. Wong xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); 30026f57ebSDarrick J. Wong return xchk_setup_ag_btree(sc, false); 31edc09b52SDarrick J. Wong } 32edc09b52SDarrick J. Wong 33edc09b52SDarrick J. Wong /* Reference count btree scrubber. */ 34edc09b52SDarrick J. Wong 35dbde19daSDarrick J. Wong /* 36dbde19daSDarrick J. Wong * Confirming Reference Counts via Reverse Mappings 37dbde19daSDarrick J. Wong * 38dbde19daSDarrick J. Wong * We want to count the reverse mappings overlapping a refcount record 39dbde19daSDarrick J. Wong * (bno, len, refcount), allowing for the possibility that some of the 40dbde19daSDarrick J. Wong * overlap may come from smaller adjoining reverse mappings, while some 41dbde19daSDarrick J. Wong * comes from single extents which overlap the range entirely. The 42dbde19daSDarrick J. Wong * outer loop is as follows: 43dbde19daSDarrick J. Wong * 44dbde19daSDarrick J. Wong * 1. For all reverse mappings overlapping the refcount extent, 45dbde19daSDarrick J. Wong * a. If a given rmap completely overlaps, mark it as seen. 46dbde19daSDarrick J. Wong * b. Otherwise, record the fragment (in agbno order) for later 47dbde19daSDarrick J. Wong * processing. 48dbde19daSDarrick J. Wong * 49dbde19daSDarrick J. Wong * Once we've seen all the rmaps, we know that for all blocks in the 50dbde19daSDarrick J. Wong * refcount record we want to find $refcount owners and we've already 51dbde19daSDarrick J. Wong * visited $seen extents that overlap all the blocks. Therefore, we 52dbde19daSDarrick J. Wong * need to find ($refcount - $seen) owners for every block in the 53dbde19daSDarrick J. Wong * extent; call that quantity $target_nr. Proceed as follows: 54dbde19daSDarrick J. Wong * 55dbde19daSDarrick J. Wong * 2. Pull the first $target_nr fragments from the list; all of them 56dbde19daSDarrick J. Wong * should start at or before the start of the extent. 57dbde19daSDarrick J. Wong * Call this subset of fragments the working set. 58dbde19daSDarrick J. Wong * 3. Until there are no more unprocessed fragments, 59dbde19daSDarrick J. Wong * a. Find the shortest fragments in the set and remove them. 60dbde19daSDarrick J. Wong * b. Note the block number of the end of these fragments. 61dbde19daSDarrick J. Wong * c. Pull the same number of fragments from the list. All of these 62dbde19daSDarrick J. Wong * fragments should start at the block number recorded in the 63dbde19daSDarrick J. Wong * previous step. 64dbde19daSDarrick J. Wong * d. Put those fragments in the set. 65dbde19daSDarrick J. Wong * 4. Check that there are $target_nr fragments remaining in the list, 66dbde19daSDarrick J. Wong * and that they all end at or beyond the end of the refcount extent. 67dbde19daSDarrick J. Wong * 68dbde19daSDarrick J. Wong * If the refcount is correct, all the check conditions in the algorithm 69dbde19daSDarrick J. Wong * should always hold true. If not, the refcount is incorrect. 70dbde19daSDarrick J. Wong */ 71c517b3aaSDarrick J. Wong struct xchk_refcnt_frag { 72dbde19daSDarrick J. Wong struct list_head list; 73dbde19daSDarrick J. Wong struct xfs_rmap_irec rm; 74dbde19daSDarrick J. Wong }; 75dbde19daSDarrick J. Wong 76c517b3aaSDarrick J. Wong struct xchk_refcnt_check { 771d8a748aSDarrick J. Wong struct xfs_scrub *sc; 78dbde19daSDarrick J. Wong struct list_head fragments; 79dbde19daSDarrick J. Wong 80dbde19daSDarrick J. Wong /* refcount extent we're examining */ 81dbde19daSDarrick J. Wong xfs_agblock_t bno; 82dbde19daSDarrick J. Wong xfs_extlen_t len; 83dbde19daSDarrick J. Wong xfs_nlink_t refcount; 84dbde19daSDarrick J. Wong 85dbde19daSDarrick J. Wong /* number of owners seen */ 86dbde19daSDarrick J. Wong xfs_nlink_t seen; 87dbde19daSDarrick J. Wong }; 88dbde19daSDarrick J. Wong 89dbde19daSDarrick J. Wong /* 90dbde19daSDarrick J. Wong * Decide if the given rmap is large enough that we can redeem it 91dbde19daSDarrick J. Wong * towards refcount verification now, or if it's a fragment, in 92dbde19daSDarrick J. Wong * which case we'll hang onto it in the hopes that we'll later 93dbde19daSDarrick J. Wong * discover that we've collected exactly the correct number of 94dbde19daSDarrick J. Wong * fragments as the refcountbt says we should have. 95dbde19daSDarrick J. Wong */ 96dbde19daSDarrick J. Wong STATIC int 97c517b3aaSDarrick J. Wong xchk_refcountbt_rmap_check( 98dbde19daSDarrick J. Wong struct xfs_btree_cur *cur, 99159eb69dSDarrick J. Wong const struct xfs_rmap_irec *rec, 100dbde19daSDarrick J. Wong void *priv) 101dbde19daSDarrick J. Wong { 102c517b3aaSDarrick J. Wong struct xchk_refcnt_check *refchk = priv; 103c517b3aaSDarrick J. Wong struct xchk_refcnt_frag *frag; 104dbde19daSDarrick J. Wong xfs_agblock_t rm_last; 105dbde19daSDarrick J. Wong xfs_agblock_t rc_last; 106dbde19daSDarrick J. Wong int error = 0; 107dbde19daSDarrick J. Wong 108c517b3aaSDarrick J. Wong if (xchk_should_terminate(refchk->sc, &error)) 109dbde19daSDarrick J. Wong return error; 110dbde19daSDarrick J. Wong 111dbde19daSDarrick J. Wong rm_last = rec->rm_startblock + rec->rm_blockcount - 1; 112dbde19daSDarrick J. Wong rc_last = refchk->bno + refchk->len - 1; 113dbde19daSDarrick J. Wong 114dbde19daSDarrick J. Wong /* Confirm that a single-owner refc extent is a CoW stage. */ 115dbde19daSDarrick J. Wong if (refchk->refcount == 1 && rec->rm_owner != XFS_RMAP_OWN_COW) { 116c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(refchk->sc, cur, 0); 117dbde19daSDarrick J. Wong return 0; 118dbde19daSDarrick J. Wong } 119dbde19daSDarrick J. Wong 120dbde19daSDarrick J. Wong if (rec->rm_startblock <= refchk->bno && rm_last >= rc_last) { 121dbde19daSDarrick J. Wong /* 122dbde19daSDarrick J. Wong * The rmap overlaps the refcount record, so we can confirm 123dbde19daSDarrick J. Wong * one refcount owner seen. 124dbde19daSDarrick J. Wong */ 125dbde19daSDarrick J. Wong refchk->seen++; 126dbde19daSDarrick J. Wong } else { 127dbde19daSDarrick J. Wong /* 128dbde19daSDarrick J. Wong * This rmap covers only part of the refcount record, so 129dbde19daSDarrick J. Wong * save the fragment for later processing. If the rmapbt 130dbde19daSDarrick J. Wong * is healthy each rmap_irec we see will be in agbno order 131dbde19daSDarrick J. Wong * so we don't need insertion sort here. 132dbde19daSDarrick J. Wong */ 133306195f3SDarrick J. Wong frag = kmalloc(sizeof(struct xchk_refcnt_frag), 134306195f3SDarrick J. Wong XCHK_GFP_FLAGS); 135dbde19daSDarrick J. Wong if (!frag) 136dbde19daSDarrick J. Wong return -ENOMEM; 137dbde19daSDarrick J. Wong memcpy(&frag->rm, rec, sizeof(frag->rm)); 138dbde19daSDarrick J. Wong list_add_tail(&frag->list, &refchk->fragments); 139dbde19daSDarrick J. Wong } 140dbde19daSDarrick J. Wong 141dbde19daSDarrick J. Wong return 0; 142dbde19daSDarrick J. Wong } 143dbde19daSDarrick J. Wong 144dbde19daSDarrick J. Wong /* 145dbde19daSDarrick J. Wong * Given a bunch of rmap fragments, iterate through them, keeping 146dbde19daSDarrick J. Wong * a running tally of the refcount. If this ever deviates from 147dbde19daSDarrick J. Wong * what we expect (which is the refcountbt's refcount minus the 148dbde19daSDarrick J. Wong * number of extents that totally covered the refcountbt extent), 149dbde19daSDarrick J. Wong * we have a refcountbt error. 150dbde19daSDarrick J. Wong */ 151dbde19daSDarrick J. Wong STATIC void 152c517b3aaSDarrick J. Wong xchk_refcountbt_process_rmap_fragments( 153c517b3aaSDarrick J. Wong struct xchk_refcnt_check *refchk) 154dbde19daSDarrick J. Wong { 155dbde19daSDarrick J. Wong struct list_head worklist; 156c517b3aaSDarrick J. Wong struct xchk_refcnt_frag *frag; 157c517b3aaSDarrick J. Wong struct xchk_refcnt_frag *n; 158dbde19daSDarrick J. Wong xfs_agblock_t bno; 159dbde19daSDarrick J. Wong xfs_agblock_t rbno; 160dbde19daSDarrick J. Wong xfs_agblock_t next_rbno; 161dbde19daSDarrick J. Wong xfs_nlink_t nr; 162dbde19daSDarrick J. Wong xfs_nlink_t target_nr; 163dbde19daSDarrick J. Wong 164dbde19daSDarrick J. Wong target_nr = refchk->refcount - refchk->seen; 165dbde19daSDarrick J. Wong if (target_nr == 0) 166dbde19daSDarrick J. Wong return; 167dbde19daSDarrick J. Wong 168dbde19daSDarrick J. Wong /* 169dbde19daSDarrick J. Wong * There are (refchk->rc.rc_refcount - refchk->nr refcount) 170dbde19daSDarrick J. Wong * references we haven't found yet. Pull that many off the 171dbde19daSDarrick J. Wong * fragment list and figure out where the smallest rmap ends 172dbde19daSDarrick J. Wong * (and therefore the next rmap should start). All the rmaps 173dbde19daSDarrick J. Wong * we pull off should start at or before the beginning of the 174dbde19daSDarrick J. Wong * refcount record's range. 175dbde19daSDarrick J. Wong */ 176dbde19daSDarrick J. Wong INIT_LIST_HEAD(&worklist); 177dbde19daSDarrick J. Wong rbno = NULLAGBLOCK; 178dbde19daSDarrick J. Wong 179dbde19daSDarrick J. Wong /* Make sure the fragments actually /are/ in agbno order. */ 180dbde19daSDarrick J. Wong bno = 0; 181dbde19daSDarrick J. Wong list_for_each_entry(frag, &refchk->fragments, list) { 182dbde19daSDarrick J. Wong if (frag->rm.rm_startblock < bno) 183dbde19daSDarrick J. Wong goto done; 184dbde19daSDarrick J. Wong bno = frag->rm.rm_startblock; 185dbde19daSDarrick J. Wong } 186dbde19daSDarrick J. Wong 187dbde19daSDarrick J. Wong /* 188dbde19daSDarrick J. Wong * Find all the rmaps that start at or before the refc extent, 189dbde19daSDarrick J. Wong * and put them on the worklist. 190dbde19daSDarrick J. Wong */ 19154e9b09eSDarrick J. Wong nr = 0; 192dbde19daSDarrick J. Wong list_for_each_entry_safe(frag, n, &refchk->fragments, list) { 19354e9b09eSDarrick J. Wong if (frag->rm.rm_startblock > refchk->bno || nr > target_nr) 19454e9b09eSDarrick J. Wong break; 195dbde19daSDarrick J. Wong bno = frag->rm.rm_startblock + frag->rm.rm_blockcount; 196dbde19daSDarrick J. Wong if (bno < rbno) 197dbde19daSDarrick J. Wong rbno = bno; 198dbde19daSDarrick J. Wong list_move_tail(&frag->list, &worklist); 199dbde19daSDarrick J. Wong nr++; 200dbde19daSDarrick J. Wong } 201dbde19daSDarrick J. Wong 202dbde19daSDarrick J. Wong /* 203dbde19daSDarrick J. Wong * We should have found exactly $target_nr rmap fragments starting 204dbde19daSDarrick J. Wong * at or before the refcount extent. 205dbde19daSDarrick J. Wong */ 206dbde19daSDarrick J. Wong if (nr != target_nr) 207dbde19daSDarrick J. Wong goto done; 208dbde19daSDarrick J. Wong 209dbde19daSDarrick J. Wong while (!list_empty(&refchk->fragments)) { 210dbde19daSDarrick J. Wong /* Discard any fragments ending at rbno from the worklist. */ 211dbde19daSDarrick J. Wong nr = 0; 212dbde19daSDarrick J. Wong next_rbno = NULLAGBLOCK; 213dbde19daSDarrick J. Wong list_for_each_entry_safe(frag, n, &worklist, list) { 214dbde19daSDarrick J. Wong bno = frag->rm.rm_startblock + frag->rm.rm_blockcount; 215dbde19daSDarrick J. Wong if (bno != rbno) { 216dbde19daSDarrick J. Wong if (bno < next_rbno) 217dbde19daSDarrick J. Wong next_rbno = bno; 218dbde19daSDarrick J. Wong continue; 219dbde19daSDarrick J. Wong } 220dbde19daSDarrick J. Wong list_del(&frag->list); 221306195f3SDarrick J. Wong kfree(frag); 222dbde19daSDarrick J. Wong nr++; 223dbde19daSDarrick J. Wong } 224dbde19daSDarrick J. Wong 225dbde19daSDarrick J. Wong /* Try to add nr rmaps starting at rbno to the worklist. */ 226dbde19daSDarrick J. Wong list_for_each_entry_safe(frag, n, &refchk->fragments, list) { 227dbde19daSDarrick J. Wong bno = frag->rm.rm_startblock + frag->rm.rm_blockcount; 228dbde19daSDarrick J. Wong if (frag->rm.rm_startblock != rbno) 229dbde19daSDarrick J. Wong goto done; 230dbde19daSDarrick J. Wong list_move_tail(&frag->list, &worklist); 231dbde19daSDarrick J. Wong if (next_rbno > bno) 232dbde19daSDarrick J. Wong next_rbno = bno; 233dbde19daSDarrick J. Wong nr--; 234dbde19daSDarrick J. Wong if (nr == 0) 235dbde19daSDarrick J. Wong break; 236dbde19daSDarrick J. Wong } 237dbde19daSDarrick J. Wong 238dbde19daSDarrick J. Wong /* 239dbde19daSDarrick J. Wong * If we get here and nr > 0, this means that we added fewer 240dbde19daSDarrick J. Wong * items to the worklist than we discarded because the fragment 241dbde19daSDarrick J. Wong * list ran out of items. Therefore, we cannot maintain the 242dbde19daSDarrick J. Wong * required refcount. Something is wrong, so we're done. 243dbde19daSDarrick J. Wong */ 244dbde19daSDarrick J. Wong if (nr) 245dbde19daSDarrick J. Wong goto done; 246dbde19daSDarrick J. Wong 247dbde19daSDarrick J. Wong rbno = next_rbno; 248dbde19daSDarrick J. Wong } 249dbde19daSDarrick J. Wong 250dbde19daSDarrick J. Wong /* 251dbde19daSDarrick J. Wong * Make sure the last extent we processed ends at or beyond 252dbde19daSDarrick J. Wong * the end of the refcount extent. 253dbde19daSDarrick J. Wong */ 254dbde19daSDarrick J. Wong if (rbno < refchk->bno + refchk->len) 255dbde19daSDarrick J. Wong goto done; 256dbde19daSDarrick J. Wong 257dbde19daSDarrick J. Wong /* Actually record us having seen the remaining refcount. */ 258dbde19daSDarrick J. Wong refchk->seen = refchk->refcount; 259dbde19daSDarrick J. Wong done: 260dbde19daSDarrick J. Wong /* Delete fragments and work list. */ 261dbde19daSDarrick J. Wong list_for_each_entry_safe(frag, n, &worklist, list) { 262dbde19daSDarrick J. Wong list_del(&frag->list); 263306195f3SDarrick J. Wong kfree(frag); 264dbde19daSDarrick J. Wong } 265dbde19daSDarrick J. Wong list_for_each_entry_safe(frag, n, &refchk->fragments, list) { 266dbde19daSDarrick J. Wong list_del(&frag->list); 267306195f3SDarrick J. Wong kfree(frag); 268dbde19daSDarrick J. Wong } 269dbde19daSDarrick J. Wong } 270dbde19daSDarrick J. Wong 271dbde19daSDarrick J. Wong /* Use the rmap entries covering this extent to verify the refcount. */ 272dbde19daSDarrick J. Wong STATIC void 273c517b3aaSDarrick J. Wong xchk_refcountbt_xref_rmap( 2741d8a748aSDarrick J. Wong struct xfs_scrub *sc, 2755a8c345cSDarrick J. Wong const struct xfs_refcount_irec *irec) 276dbde19daSDarrick J. Wong { 277c517b3aaSDarrick J. Wong struct xchk_refcnt_check refchk = { 278dbde19daSDarrick J. Wong .sc = sc, 2795a8c345cSDarrick J. Wong .bno = irec->rc_startblock, 2805a8c345cSDarrick J. Wong .len = irec->rc_blockcount, 2815a8c345cSDarrick J. Wong .refcount = irec->rc_refcount, 282dbde19daSDarrick J. Wong .seen = 0, 283dbde19daSDarrick J. Wong }; 284dbde19daSDarrick J. Wong struct xfs_rmap_irec low; 285dbde19daSDarrick J. Wong struct xfs_rmap_irec high; 286c517b3aaSDarrick J. Wong struct xchk_refcnt_frag *frag; 287c517b3aaSDarrick J. Wong struct xchk_refcnt_frag *n; 288dbde19daSDarrick J. Wong int error; 289dbde19daSDarrick J. Wong 290c517b3aaSDarrick J. Wong if (!sc->sa.rmap_cur || xchk_skip_xref(sc->sm)) 291dbde19daSDarrick J. Wong return; 292dbde19daSDarrick J. Wong 293dbde19daSDarrick J. Wong /* Cross-reference with the rmapbt to confirm the refcount. */ 294dbde19daSDarrick J. Wong memset(&low, 0, sizeof(low)); 2955a8c345cSDarrick J. Wong low.rm_startblock = irec->rc_startblock; 296dbde19daSDarrick J. Wong memset(&high, 0xFF, sizeof(high)); 2975a8c345cSDarrick J. Wong high.rm_startblock = irec->rc_startblock + irec->rc_blockcount - 1; 298dbde19daSDarrick J. Wong 299dbde19daSDarrick J. Wong INIT_LIST_HEAD(&refchk.fragments); 300dbde19daSDarrick J. Wong error = xfs_rmap_query_range(sc->sa.rmap_cur, &low, &high, 301c517b3aaSDarrick J. Wong &xchk_refcountbt_rmap_check, &refchk); 302c517b3aaSDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur)) 303dbde19daSDarrick J. Wong goto out_free; 304dbde19daSDarrick J. Wong 305c517b3aaSDarrick J. Wong xchk_refcountbt_process_rmap_fragments(&refchk); 30690148903SDarrick J. Wong if (irec->rc_refcount != refchk.seen) { 30790148903SDarrick J. Wong trace_xchk_refcount_incorrect(sc->sa.pag, irec, refchk.seen); 308c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0); 30990148903SDarrick J. Wong } 310dbde19daSDarrick J. Wong 311dbde19daSDarrick J. Wong out_free: 312dbde19daSDarrick J. Wong list_for_each_entry_safe(frag, n, &refchk.fragments, list) { 313dbde19daSDarrick J. Wong list_del(&frag->list); 314306195f3SDarrick J. Wong kfree(frag); 315dbde19daSDarrick J. Wong } 316dbde19daSDarrick J. Wong } 317dbde19daSDarrick J. Wong 318166d7641SDarrick J. Wong /* Cross-reference with the other btrees. */ 319166d7641SDarrick J. Wong STATIC void 320c517b3aaSDarrick J. Wong xchk_refcountbt_xref( 3211d8a748aSDarrick J. Wong struct xfs_scrub *sc, 3225a8c345cSDarrick J. Wong const struct xfs_refcount_irec *irec) 323166d7641SDarrick J. Wong { 324166d7641SDarrick J. Wong if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 325166d7641SDarrick J. Wong return; 32652dc4b44SDarrick J. Wong 3275a8c345cSDarrick J. Wong xchk_xref_is_used_space(sc, irec->rc_startblock, irec->rc_blockcount); 3285a8c345cSDarrick J. Wong xchk_xref_is_not_inode_chunk(sc, irec->rc_startblock, 3295a8c345cSDarrick J. Wong irec->rc_blockcount); 3305a8c345cSDarrick J. Wong xchk_refcountbt_xref_rmap(sc, irec); 331166d7641SDarrick J. Wong } 332166d7641SDarrick J. Wong 3337ad9ea63SDarrick J. Wong struct xchk_refcbt_records { 334db0502b3SDarrick J. Wong /* Previous refcount record. */ 335db0502b3SDarrick J. Wong struct xfs_refcount_irec prev_rec; 336db0502b3SDarrick J. Wong 3377ad9ea63SDarrick J. Wong /* The next AG block where we aren't expecting shared extents. */ 3387ad9ea63SDarrick J. Wong xfs_agblock_t next_unshared_agbno; 3397ad9ea63SDarrick J. Wong 3407ad9ea63SDarrick J. Wong /* Number of CoW blocks we expect. */ 3417ad9ea63SDarrick J. Wong xfs_agblock_t cow_blocks; 3427ad9ea63SDarrick J. Wong 3437ad9ea63SDarrick J. Wong /* Was the last record a shared or CoW staging extent? */ 3447ad9ea63SDarrick J. Wong enum xfs_refc_domain prev_domain; 3457ad9ea63SDarrick J. Wong }; 3467ad9ea63SDarrick J. Wong 3477ad9ea63SDarrick J. Wong STATIC int 3487ad9ea63SDarrick J. Wong xchk_refcountbt_rmap_check_gap( 3497ad9ea63SDarrick J. Wong struct xfs_btree_cur *cur, 3507ad9ea63SDarrick J. Wong const struct xfs_rmap_irec *rec, 3517ad9ea63SDarrick J. Wong void *priv) 3527ad9ea63SDarrick J. Wong { 3537ad9ea63SDarrick J. Wong xfs_agblock_t *next_bno = priv; 3547ad9ea63SDarrick J. Wong 3557ad9ea63SDarrick J. Wong if (*next_bno != NULLAGBLOCK && rec->rm_startblock < *next_bno) 3567ad9ea63SDarrick J. Wong return -ECANCELED; 3577ad9ea63SDarrick J. Wong 3587ad9ea63SDarrick J. Wong *next_bno = rec->rm_startblock + rec->rm_blockcount; 3597ad9ea63SDarrick J. Wong return 0; 3607ad9ea63SDarrick J. Wong } 3617ad9ea63SDarrick J. Wong 3627ad9ea63SDarrick J. Wong /* 3637ad9ea63SDarrick J. Wong * Make sure that a gap in the reference count records does not correspond to 3647ad9ea63SDarrick J. Wong * overlapping records (i.e. shared extents) in the reverse mappings. 3657ad9ea63SDarrick J. Wong */ 3667ad9ea63SDarrick J. Wong static inline void 3677ad9ea63SDarrick J. Wong xchk_refcountbt_xref_gaps( 3687ad9ea63SDarrick J. Wong struct xfs_scrub *sc, 3697ad9ea63SDarrick J. Wong struct xchk_refcbt_records *rrc, 3707ad9ea63SDarrick J. Wong xfs_agblock_t bno) 3717ad9ea63SDarrick J. Wong { 3727ad9ea63SDarrick J. Wong struct xfs_rmap_irec low; 3737ad9ea63SDarrick J. Wong struct xfs_rmap_irec high; 3747ad9ea63SDarrick J. Wong xfs_agblock_t next_bno = NULLAGBLOCK; 3757ad9ea63SDarrick J. Wong int error; 3767ad9ea63SDarrick J. Wong 3777ad9ea63SDarrick J. Wong if (bno <= rrc->next_unshared_agbno || !sc->sa.rmap_cur || 3787ad9ea63SDarrick J. Wong xchk_skip_xref(sc->sm)) 3797ad9ea63SDarrick J. Wong return; 3807ad9ea63SDarrick J. Wong 3817ad9ea63SDarrick J. Wong memset(&low, 0, sizeof(low)); 3827ad9ea63SDarrick J. Wong low.rm_startblock = rrc->next_unshared_agbno; 3837ad9ea63SDarrick J. Wong memset(&high, 0xFF, sizeof(high)); 3847ad9ea63SDarrick J. Wong high.rm_startblock = bno - 1; 3857ad9ea63SDarrick J. Wong 3867ad9ea63SDarrick J. Wong error = xfs_rmap_query_range(sc->sa.rmap_cur, &low, &high, 3877ad9ea63SDarrick J. Wong xchk_refcountbt_rmap_check_gap, &next_bno); 3887ad9ea63SDarrick J. Wong if (error == -ECANCELED) 3897ad9ea63SDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0); 3907ad9ea63SDarrick J. Wong else 3917ad9ea63SDarrick J. Wong xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur); 3927ad9ea63SDarrick J. Wong } 3937ad9ea63SDarrick J. Wong 394db0502b3SDarrick J. Wong static inline bool 395db0502b3SDarrick J. Wong xchk_refcount_mergeable( 396db0502b3SDarrick J. Wong struct xchk_refcbt_records *rrc, 397db0502b3SDarrick J. Wong const struct xfs_refcount_irec *r2) 398db0502b3SDarrick J. Wong { 399db0502b3SDarrick J. Wong const struct xfs_refcount_irec *r1 = &rrc->prev_rec; 400db0502b3SDarrick J. Wong 401db0502b3SDarrick J. Wong /* Ignore if prev_rec is not yet initialized. */ 402db0502b3SDarrick J. Wong if (r1->rc_blockcount > 0) 403db0502b3SDarrick J. Wong return false; 404db0502b3SDarrick J. Wong 405db0502b3SDarrick J. Wong if (r1->rc_domain != r2->rc_domain) 406db0502b3SDarrick J. Wong return false; 407db0502b3SDarrick J. Wong if (r1->rc_startblock + r1->rc_blockcount != r2->rc_startblock) 408db0502b3SDarrick J. Wong return false; 409db0502b3SDarrick J. Wong if (r1->rc_refcount != r2->rc_refcount) 410db0502b3SDarrick J. Wong return false; 411db0502b3SDarrick J. Wong if ((unsigned long long)r1->rc_blockcount + r2->rc_blockcount > 412db0502b3SDarrick J. Wong MAXREFCEXTLEN) 413db0502b3SDarrick J. Wong return false; 414db0502b3SDarrick J. Wong 415db0502b3SDarrick J. Wong return true; 416db0502b3SDarrick J. Wong } 417db0502b3SDarrick J. Wong 418db0502b3SDarrick J. Wong /* Flag failures for records that could be merged. */ 419db0502b3SDarrick J. Wong STATIC void 420db0502b3SDarrick J. Wong xchk_refcountbt_check_mergeable( 421db0502b3SDarrick J. Wong struct xchk_btree *bs, 422db0502b3SDarrick J. Wong struct xchk_refcbt_records *rrc, 423db0502b3SDarrick J. Wong const struct xfs_refcount_irec *irec) 424db0502b3SDarrick J. Wong { 425db0502b3SDarrick J. Wong if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 426db0502b3SDarrick J. Wong return; 427db0502b3SDarrick J. Wong 428db0502b3SDarrick J. Wong if (xchk_refcount_mergeable(rrc, irec)) 429db0502b3SDarrick J. Wong xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 430db0502b3SDarrick J. Wong 431db0502b3SDarrick J. Wong memcpy(&rrc->prev_rec, irec, sizeof(struct xfs_refcount_irec)); 432db0502b3SDarrick J. Wong } 433db0502b3SDarrick J. Wong 434edc09b52SDarrick J. Wong /* Scrub a refcountbt record. */ 435edc09b52SDarrick J. Wong STATIC int 436c517b3aaSDarrick J. Wong xchk_refcountbt_rec( 437c517b3aaSDarrick J. Wong struct xchk_btree *bs, 43822ece4e8SDarrick J. Wong const union xfs_btree_rec *rec) 439edc09b52SDarrick J. Wong { 4405a8c345cSDarrick J. Wong struct xfs_refcount_irec irec; 4417ad9ea63SDarrick J. Wong struct xchk_refcbt_records *rrc = bs->private; 442edc09b52SDarrick J. Wong 4435a8c345cSDarrick J. Wong xfs_refcount_btrec_to_irec(rec, &irec); 4442b30cc0bSDarrick J. Wong if (xfs_refcount_check_irec(bs->cur, &irec) != NULL) { 445c517b3aaSDarrick J. Wong xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 4462b30cc0bSDarrick J. Wong return 0; 4472b30cc0bSDarrick J. Wong } 448f492135dSDarrick J. Wong 449f492135dSDarrick J. Wong if (irec.rc_domain == XFS_REFC_DOMAIN_COW) 4507ad9ea63SDarrick J. Wong rrc->cow_blocks += irec.rc_blockcount; 4517ad9ea63SDarrick J. Wong 4527ad9ea63SDarrick J. Wong /* Shared records always come before CoW records. */ 4537ad9ea63SDarrick J. Wong if (irec.rc_domain == XFS_REFC_DOMAIN_SHARED && 4547ad9ea63SDarrick J. Wong rrc->prev_domain == XFS_REFC_DOMAIN_COW) 4557ad9ea63SDarrick J. Wong xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 4567ad9ea63SDarrick J. Wong rrc->prev_domain = irec.rc_domain; 457edc09b52SDarrick J. Wong 458db0502b3SDarrick J. Wong xchk_refcountbt_check_mergeable(bs, rrc, &irec); 4595a8c345cSDarrick J. Wong xchk_refcountbt_xref(bs->sc, &irec); 460166d7641SDarrick J. Wong 4617ad9ea63SDarrick J. Wong /* 4627ad9ea63SDarrick J. Wong * If this is a record for a shared extent, check that all blocks 4637ad9ea63SDarrick J. Wong * between the previous record and this one have at most one reverse 4647ad9ea63SDarrick J. Wong * mapping. 4657ad9ea63SDarrick J. Wong */ 4667ad9ea63SDarrick J. Wong if (irec.rc_domain == XFS_REFC_DOMAIN_SHARED) { 4677ad9ea63SDarrick J. Wong xchk_refcountbt_xref_gaps(bs->sc, rrc, irec.rc_startblock); 4687ad9ea63SDarrick J. Wong rrc->next_unshared_agbno = irec.rc_startblock + 4697ad9ea63SDarrick J. Wong irec.rc_blockcount; 4707ad9ea63SDarrick J. Wong } 4717ad9ea63SDarrick J. Wong 472d5cc14d9SAliasgar Surti return 0; 473edc09b52SDarrick J. Wong } 474edc09b52SDarrick J. Wong 475dbde19daSDarrick J. Wong /* Make sure we have as many refc blocks as the rmap says. */ 476dbde19daSDarrick J. Wong STATIC void 477c517b3aaSDarrick J. Wong xchk_refcount_xref_rmap( 4781d8a748aSDarrick J. Wong struct xfs_scrub *sc, 479dbde19daSDarrick J. Wong xfs_filblks_t cow_blocks) 480dbde19daSDarrick J. Wong { 481dbde19daSDarrick J. Wong xfs_extlen_t refcbt_blocks = 0; 482dbde19daSDarrick J. Wong xfs_filblks_t blocks; 483dbde19daSDarrick J. Wong int error; 484dbde19daSDarrick J. Wong 485c517b3aaSDarrick J. Wong if (!sc->sa.rmap_cur || xchk_skip_xref(sc->sm)) 486dbde19daSDarrick J. Wong return; 487dbde19daSDarrick J. Wong 488dbde19daSDarrick J. Wong /* Check that we saw as many refcbt blocks as the rmap knows about. */ 489dbde19daSDarrick J. Wong error = xfs_btree_count_blocks(sc->sa.refc_cur, &refcbt_blocks); 490c517b3aaSDarrick J. Wong if (!xchk_btree_process_error(sc, sc->sa.refc_cur, 0, &error)) 491dbde19daSDarrick J. Wong return; 4927280fedaSDarrick J. Wong error = xchk_count_rmap_ownedby_ag(sc, sc->sa.rmap_cur, 4937280fedaSDarrick J. Wong &XFS_RMAP_OINFO_REFC, &blocks); 494c517b3aaSDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur)) 495dbde19daSDarrick J. Wong return; 496dbde19daSDarrick J. Wong if (blocks != refcbt_blocks) 497c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0); 498dbde19daSDarrick J. Wong 499dbde19daSDarrick J. Wong /* Check that we saw as many cow blocks as the rmap knows about. */ 5007280fedaSDarrick J. Wong error = xchk_count_rmap_ownedby_ag(sc, sc->sa.rmap_cur, 5017280fedaSDarrick J. Wong &XFS_RMAP_OINFO_COW, &blocks); 502c517b3aaSDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur)) 503dbde19daSDarrick J. Wong return; 504dbde19daSDarrick J. Wong if (blocks != cow_blocks) 505c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0); 506dbde19daSDarrick J. Wong } 507dbde19daSDarrick J. Wong 508edc09b52SDarrick J. Wong /* Scrub the refcount btree for some AG. */ 509edc09b52SDarrick J. Wong int 510c517b3aaSDarrick J. Wong xchk_refcountbt( 5111d8a748aSDarrick J. Wong struct xfs_scrub *sc) 512edc09b52SDarrick J. Wong { 5137ad9ea63SDarrick J. Wong struct xchk_refcbt_records rrc = { 5147ad9ea63SDarrick J. Wong .cow_blocks = 0, 5157ad9ea63SDarrick J. Wong .next_unshared_agbno = 0, 5167ad9ea63SDarrick J. Wong .prev_domain = XFS_REFC_DOMAIN_SHARED, 5177ad9ea63SDarrick J. Wong }; 518dbde19daSDarrick J. Wong int error; 519edc09b52SDarrick J. Wong 520c517b3aaSDarrick J. Wong error = xchk_btree(sc, sc->sa.refc_cur, xchk_refcountbt_rec, 5217ad9ea63SDarrick J. Wong &XFS_RMAP_OINFO_REFC, &rrc); 522dbde19daSDarrick J. Wong if (error) 523dbde19daSDarrick J. Wong return error; 524dbde19daSDarrick J. Wong 5257ad9ea63SDarrick J. Wong /* 5267ad9ea63SDarrick J. Wong * Check that all blocks between the last refcount > 1 record and the 5277ad9ea63SDarrick J. Wong * end of the AG have at most one reverse mapping. 5287ad9ea63SDarrick J. Wong */ 5297ad9ea63SDarrick J. Wong xchk_refcountbt_xref_gaps(sc, &rrc, sc->mp->m_sb.sb_agblocks); 5307ad9ea63SDarrick J. Wong 5317ad9ea63SDarrick J. Wong xchk_refcount_xref_rmap(sc, rrc.cow_blocks); 532dbde19daSDarrick J. Wong 533dbde19daSDarrick J. Wong return 0; 534edc09b52SDarrick J. Wong } 535f6d5fc21SDarrick J. Wong 536f6d5fc21SDarrick J. Wong /* xref check that a cow staging extent is marked in the refcountbt. */ 537f6d5fc21SDarrick J. Wong void 538c517b3aaSDarrick J. Wong xchk_xref_is_cow_staging( 5391d8a748aSDarrick J. Wong struct xfs_scrub *sc, 540f6d5fc21SDarrick J. Wong xfs_agblock_t agbno, 541f6d5fc21SDarrick J. Wong xfs_extlen_t len) 542f6d5fc21SDarrick J. Wong { 543f6d5fc21SDarrick J. Wong struct xfs_refcount_irec rc; 544f6d5fc21SDarrick J. Wong int has_refcount; 545f6d5fc21SDarrick J. Wong int error; 546f6d5fc21SDarrick J. Wong 547c517b3aaSDarrick J. Wong if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm)) 548f6d5fc21SDarrick J. Wong return; 549f6d5fc21SDarrick J. Wong 550f6d5fc21SDarrick J. Wong /* Find the CoW staging extent. */ 5519a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(sc->sa.refc_cur, XFS_REFC_DOMAIN_COW, 5529a50ee4fSDarrick J. Wong agbno, &has_refcount); 553c517b3aaSDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur)) 554f6d5fc21SDarrick J. Wong return; 555f6d5fc21SDarrick J. Wong if (!has_refcount) { 556c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0); 557f6d5fc21SDarrick J. Wong return; 558f6d5fc21SDarrick J. Wong } 559f6d5fc21SDarrick J. Wong 560f6d5fc21SDarrick J. Wong error = xfs_refcount_get_rec(sc->sa.refc_cur, &rc, &has_refcount); 561c517b3aaSDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur)) 562f6d5fc21SDarrick J. Wong return; 563f6d5fc21SDarrick J. Wong if (!has_refcount) { 564c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0); 565f6d5fc21SDarrick J. Wong return; 566f6d5fc21SDarrick J. Wong } 567f6d5fc21SDarrick J. Wong 568f62ac3e0SDarrick J. Wong /* CoW lookup returned a shared extent record? */ 569f62ac3e0SDarrick J. Wong if (rc.rc_domain != XFS_REFC_DOMAIN_COW) 570c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0); 571f6d5fc21SDarrick J. Wong 572f6d5fc21SDarrick J. Wong /* Must be at least as long as what was passed in */ 573f6d5fc21SDarrick J. Wong if (rc.rc_blockcount < len) 574c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0); 575f6d5fc21SDarrick J. Wong } 576f6d5fc21SDarrick J. Wong 577f6d5fc21SDarrick J. Wong /* 578f6d5fc21SDarrick J. Wong * xref check that the extent is not shared. Only file data blocks 579f6d5fc21SDarrick J. Wong * can have multiple owners. 580f6d5fc21SDarrick J. Wong */ 581f6d5fc21SDarrick J. Wong void 582c517b3aaSDarrick J. Wong xchk_xref_is_not_shared( 5831d8a748aSDarrick J. Wong struct xfs_scrub *sc, 584f6d5fc21SDarrick J. Wong xfs_agblock_t agbno, 585f6d5fc21SDarrick J. Wong xfs_extlen_t len) 586f6d5fc21SDarrick J. Wong { 5876abc7aefSDarrick J. Wong enum xbtree_recpacking outcome; 588f6d5fc21SDarrick J. Wong int error; 589f6d5fc21SDarrick J. Wong 590c517b3aaSDarrick J. Wong if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm)) 591f6d5fc21SDarrick J. Wong return; 592f6d5fc21SDarrick J. Wong 5936abc7aefSDarrick J. Wong error = xfs_refcount_has_records(sc->sa.refc_cur, 5946abc7aefSDarrick J. Wong XFS_REFC_DOMAIN_SHARED, agbno, len, &outcome); 595c517b3aaSDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur)) 596f6d5fc21SDarrick J. Wong return; 5976abc7aefSDarrick J. Wong if (outcome != XBTREE_RECPACKING_EMPTY) 598c517b3aaSDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0); 599f6d5fc21SDarrick J. Wong } 6007ac14fa2SDarrick J. Wong 6017ac14fa2SDarrick J. Wong /* xref check that the extent is not being used for CoW staging. */ 6027ac14fa2SDarrick J. Wong void 6037ac14fa2SDarrick J. Wong xchk_xref_is_not_cow_staging( 6047ac14fa2SDarrick J. Wong struct xfs_scrub *sc, 6057ac14fa2SDarrick J. Wong xfs_agblock_t agbno, 6067ac14fa2SDarrick J. Wong xfs_extlen_t len) 6077ac14fa2SDarrick J. Wong { 6087ac14fa2SDarrick J. Wong enum xbtree_recpacking outcome; 6097ac14fa2SDarrick J. Wong int error; 6107ac14fa2SDarrick J. Wong 6117ac14fa2SDarrick J. Wong if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm)) 6127ac14fa2SDarrick J. Wong return; 6137ac14fa2SDarrick J. Wong 6147ac14fa2SDarrick J. Wong error = xfs_refcount_has_records(sc->sa.refc_cur, XFS_REFC_DOMAIN_COW, 6157ac14fa2SDarrick J. Wong agbno, len, &outcome); 6167ac14fa2SDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur)) 6177ac14fa2SDarrick J. Wong return; 6187ac14fa2SDarrick J. Wong if (outcome != XBTREE_RECPACKING_EMPTY) 6197ac14fa2SDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0); 6207ac14fa2SDarrick J. Wong } 621