1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 */ 6 #include "xfs_platform.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_log_format.h" 11 #include "xfs_trans_resv.h" 12 #include "xfs_mount.h" 13 #include "xfs_trans.h" 14 #include "xfs_btree.h" 15 #include "xfs_rmap.h" 16 #include "xfs_refcount.h" 17 #include "xfs_inode.h" 18 #include "xfs_rtbitmap.h" 19 #include "xfs_rtgroup.h" 20 #include "xfs_metafile.h" 21 #include "xfs_rtrefcount_btree.h" 22 #include "xfs_rtalloc.h" 23 #include "xfs_ag.h" 24 #include "scrub/scrub.h" 25 #include "scrub/common.h" 26 #include "scrub/btree.h" 27 #include "scrub/repair.h" 28 29 /* Set us up with the realtime refcount metadata locked. */ 30 int 31 xchk_setup_rtrefcountbt( 32 struct xfs_scrub *sc) 33 { 34 int error; 35 36 if (xchk_need_intent_drain(sc)) 37 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); 38 39 if (xchk_could_repair(sc)) { 40 error = xrep_setup_rtrefcountbt(sc); 41 if (error) 42 return error; 43 } 44 45 error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr); 46 if (error) 47 return error; 48 49 error = xchk_setup_rt(sc); 50 if (error) 51 return error; 52 53 error = xchk_install_live_inode(sc, rtg_refcount(sc->sr.rtg)); 54 if (error) 55 return error; 56 57 return xchk_rtgroup_lock(sc, &sc->sr, XCHK_RTGLOCK_ALL); 58 } 59 60 /* Realtime Reference count btree scrubber. */ 61 62 /* 63 * Confirming Reference Counts via Reverse Mappings 64 * 65 * We want to count the reverse mappings overlapping a refcount record 66 * (bno, len, refcount), allowing for the possibility that some of the 67 * overlap may come from smaller adjoining reverse mappings, while some 68 * comes from single extents which overlap the range entirely. The 69 * outer loop is as follows: 70 * 71 * 1. For all reverse mappings overlapping the refcount extent, 72 * a. If a given rmap completely overlaps, mark it as seen. 73 * b. Otherwise, record the fragment (in agbno order) for later 74 * processing. 75 * 76 * Once we've seen all the rmaps, we know that for all blocks in the 77 * refcount record we want to find $refcount owners and we've already 78 * visited $seen extents that overlap all the blocks. Therefore, we 79 * need to find ($refcount - $seen) owners for every block in the 80 * extent; call that quantity $target_nr. Proceed as follows: 81 * 82 * 2. Pull the first $target_nr fragments from the list; all of them 83 * should start at or before the start of the extent. 84 * Call this subset of fragments the working set. 85 * 3. Until there are no more unprocessed fragments, 86 * a. Find the shortest fragments in the set and remove them. 87 * b. Note the block number of the end of these fragments. 88 * c. Pull the same number of fragments from the list. All of these 89 * fragments should start at the block number recorded in the 90 * previous step. 91 * d. Put those fragments in the set. 92 * 4. Check that there are $target_nr fragments remaining in the list, 93 * and that they all end at or beyond the end of the refcount extent. 94 * 95 * If the refcount is correct, all the check conditions in the algorithm 96 * should always hold true. If not, the refcount is incorrect. 97 */ 98 struct xchk_rtrefcnt_frag { 99 struct list_head list; 100 struct xfs_rmap_irec rm; 101 }; 102 103 struct xchk_rtrefcnt_check { 104 struct xfs_scrub *sc; 105 struct list_head fragments; 106 107 /* refcount extent we're examining */ 108 xfs_rgblock_t bno; 109 xfs_extlen_t len; 110 xfs_nlink_t refcount; 111 112 /* number of owners seen */ 113 xfs_nlink_t seen; 114 }; 115 116 /* 117 * Decide if the given rmap is large enough that we can redeem it 118 * towards refcount verification now, or if it's a fragment, in 119 * which case we'll hang onto it in the hopes that we'll later 120 * discover that we've collected exactly the correct number of 121 * fragments as the rtrefcountbt says we should have. 122 */ 123 STATIC int 124 xchk_rtrefcountbt_rmap_check( 125 struct xfs_btree_cur *cur, 126 const struct xfs_rmap_irec *rec, 127 void *priv) 128 { 129 struct xchk_rtrefcnt_check *refchk = priv; 130 struct xchk_rtrefcnt_frag *frag; 131 xfs_rgblock_t rm_last; 132 xfs_rgblock_t rc_last; 133 int error = 0; 134 135 if (xchk_should_terminate(refchk->sc, &error)) 136 return error; 137 138 rm_last = rec->rm_startblock + rec->rm_blockcount - 1; 139 rc_last = refchk->bno + refchk->len - 1; 140 141 /* Confirm that a single-owner refc extent is a CoW stage. */ 142 if (refchk->refcount == 1 && rec->rm_owner != XFS_RMAP_OWN_COW) { 143 xchk_btree_xref_set_corrupt(refchk->sc, cur, 0); 144 return 0; 145 } 146 147 if (rec->rm_startblock <= refchk->bno && rm_last >= rc_last) { 148 /* 149 * The rmap overlaps the refcount record, so we can confirm 150 * one refcount owner seen. 151 */ 152 refchk->seen++; 153 } else { 154 /* 155 * This rmap covers only part of the refcount record, so 156 * save the fragment for later processing. If the rmapbt 157 * is healthy each rmap_irec we see will be in agbno order 158 * so we don't need insertion sort here. 159 */ 160 frag = kmalloc_obj(struct xchk_rtrefcnt_frag, XCHK_GFP_FLAGS); 161 if (!frag) 162 return -ENOMEM; 163 memcpy(&frag->rm, rec, sizeof(frag->rm)); 164 list_add_tail(&frag->list, &refchk->fragments); 165 } 166 167 return 0; 168 } 169 170 /* 171 * Given a bunch of rmap fragments, iterate through them, keeping 172 * a running tally of the refcount. If this ever deviates from 173 * what we expect (which is the rtrefcountbt's refcount minus the 174 * number of extents that totally covered the rtrefcountbt extent), 175 * we have a rtrefcountbt error. 176 */ 177 STATIC void 178 xchk_rtrefcountbt_process_rmap_fragments( 179 struct xchk_rtrefcnt_check *refchk) 180 { 181 struct list_head worklist; 182 struct xchk_rtrefcnt_frag *frag; 183 struct xchk_rtrefcnt_frag *n; 184 xfs_rgblock_t bno; 185 xfs_rgblock_t rbno; 186 xfs_rgblock_t next_rbno; 187 xfs_nlink_t nr; 188 xfs_nlink_t target_nr; 189 190 target_nr = refchk->refcount - refchk->seen; 191 if (target_nr == 0) 192 return; 193 194 /* 195 * There are (refchk->rc.rc_refcount - refchk->nr refcount) 196 * references we haven't found yet. Pull that many off the 197 * fragment list and figure out where the smallest rmap ends 198 * (and therefore the next rmap should start). All the rmaps 199 * we pull off should start at or before the beginning of the 200 * refcount record's range. 201 */ 202 INIT_LIST_HEAD(&worklist); 203 rbno = NULLRGBLOCK; 204 205 /* Make sure the fragments actually /are/ in bno order. */ 206 bno = 0; 207 list_for_each_entry(frag, &refchk->fragments, list) { 208 if (frag->rm.rm_startblock < bno) 209 goto done; 210 bno = frag->rm.rm_startblock; 211 } 212 213 /* 214 * Find all the rmaps that start at or before the refc extent, 215 * and put them on the worklist. 216 */ 217 nr = 0; 218 list_for_each_entry_safe(frag, n, &refchk->fragments, list) { 219 if (frag->rm.rm_startblock > refchk->bno || nr > target_nr) 220 break; 221 bno = frag->rm.rm_startblock + frag->rm.rm_blockcount; 222 if (bno < rbno) 223 rbno = bno; 224 list_move_tail(&frag->list, &worklist); 225 nr++; 226 } 227 228 /* 229 * We should have found exactly $target_nr rmap fragments starting 230 * at or before the refcount extent. 231 */ 232 if (nr != target_nr) 233 goto done; 234 235 while (!list_empty(&refchk->fragments)) { 236 /* Discard any fragments ending at rbno from the worklist. */ 237 nr = 0; 238 next_rbno = NULLRGBLOCK; 239 list_for_each_entry_safe(frag, n, &worklist, list) { 240 bno = frag->rm.rm_startblock + frag->rm.rm_blockcount; 241 if (bno != rbno) { 242 if (bno < next_rbno) 243 next_rbno = bno; 244 continue; 245 } 246 list_del(&frag->list); 247 kfree(frag); 248 nr++; 249 } 250 251 /* Try to add nr rmaps starting at rbno to the worklist. */ 252 list_for_each_entry_safe(frag, n, &refchk->fragments, list) { 253 bno = frag->rm.rm_startblock + frag->rm.rm_blockcount; 254 if (frag->rm.rm_startblock != rbno) 255 goto done; 256 list_move_tail(&frag->list, &worklist); 257 if (next_rbno > bno) 258 next_rbno = bno; 259 nr--; 260 if (nr == 0) 261 break; 262 } 263 264 /* 265 * If we get here and nr > 0, this means that we added fewer 266 * items to the worklist than we discarded because the fragment 267 * list ran out of items. Therefore, we cannot maintain the 268 * required refcount. Something is wrong, so we're done. 269 */ 270 if (nr) 271 goto done; 272 273 rbno = next_rbno; 274 } 275 276 /* 277 * Make sure the last extent we processed ends at or beyond 278 * the end of the refcount extent. 279 */ 280 if (rbno < refchk->bno + refchk->len) 281 goto done; 282 283 /* Actually record us having seen the remaining refcount. */ 284 refchk->seen = refchk->refcount; 285 done: 286 /* Delete fragments and work list. */ 287 list_for_each_entry_safe(frag, n, &worklist, list) { 288 list_del(&frag->list); 289 kfree(frag); 290 } 291 list_for_each_entry_safe(frag, n, &refchk->fragments, list) { 292 list_del(&frag->list); 293 kfree(frag); 294 } 295 } 296 297 /* Use the rmap entries covering this extent to verify the refcount. */ 298 STATIC void 299 xchk_rtrefcountbt_xref_rmap( 300 struct xfs_scrub *sc, 301 const struct xfs_refcount_irec *irec) 302 { 303 struct xchk_rtrefcnt_check refchk = { 304 .sc = sc, 305 .bno = irec->rc_startblock, 306 .len = irec->rc_blockcount, 307 .refcount = irec->rc_refcount, 308 .seen = 0, 309 }; 310 struct xfs_rmap_irec low; 311 struct xfs_rmap_irec high; 312 struct xchk_rtrefcnt_frag *frag; 313 struct xchk_rtrefcnt_frag *n; 314 int error; 315 316 if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm)) 317 return; 318 319 /* Cross-reference with the rmapbt to confirm the refcount. */ 320 memset(&low, 0, sizeof(low)); 321 low.rm_startblock = irec->rc_startblock; 322 memset(&high, 0xFF, sizeof(high)); 323 high.rm_startblock = irec->rc_startblock + irec->rc_blockcount - 1; 324 325 INIT_LIST_HEAD(&refchk.fragments); 326 error = xfs_rmap_query_range(sc->sr.rmap_cur, &low, &high, 327 xchk_rtrefcountbt_rmap_check, &refchk); 328 if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur)) 329 goto out_free; 330 331 xchk_rtrefcountbt_process_rmap_fragments(&refchk); 332 if (irec->rc_refcount != refchk.seen) 333 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 334 335 out_free: 336 list_for_each_entry_safe(frag, n, &refchk.fragments, list) { 337 list_del(&frag->list); 338 kfree(frag); 339 } 340 } 341 342 /* Cross-reference with the other btrees. */ 343 STATIC void 344 xchk_rtrefcountbt_xref( 345 struct xfs_scrub *sc, 346 const struct xfs_refcount_irec *irec) 347 { 348 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 349 return; 350 351 xchk_xref_is_used_rt_space(sc, 352 xfs_rgbno_to_rtb(sc->sr.rtg, irec->rc_startblock), 353 irec->rc_blockcount); 354 xchk_rtrefcountbt_xref_rmap(sc, irec); 355 } 356 357 struct xchk_rtrefcbt_records { 358 /* Previous refcount record. */ 359 struct xfs_refcount_irec prev_rec; 360 361 /* The next rtgroup block where we aren't expecting shared extents. */ 362 xfs_rgblock_t next_unshared_rgbno; 363 364 /* Number of CoW blocks we expect. */ 365 xfs_extlen_t cow_blocks; 366 367 /* Was the last record a shared or CoW staging extent? */ 368 enum xfs_refc_domain prev_domain; 369 }; 370 371 static inline bool 372 xchk_rtrefcount_mergeable( 373 struct xchk_rtrefcbt_records *rrc, 374 const struct xfs_refcount_irec *r2) 375 { 376 const struct xfs_refcount_irec *r1 = &rrc->prev_rec; 377 378 /* Ignore if prev_rec is not yet initialized. */ 379 if (r1->rc_blockcount == 0) 380 return false; 381 382 if (r1->rc_startblock + r1->rc_blockcount != r2->rc_startblock) 383 return false; 384 if (r1->rc_refcount != r2->rc_refcount) 385 return false; 386 if ((unsigned long long)r1->rc_blockcount + r2->rc_blockcount > 387 XFS_REFC_LEN_MAX) 388 return false; 389 390 return true; 391 } 392 393 /* Flag failures for records that could be merged. */ 394 STATIC void 395 xchk_rtrefcountbt_check_mergeable( 396 struct xchk_btree *bs, 397 struct xchk_rtrefcbt_records *rrc, 398 const struct xfs_refcount_irec *irec) 399 { 400 if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 401 return; 402 403 if (xchk_rtrefcount_mergeable(rrc, irec)) 404 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 405 406 memcpy(&rrc->prev_rec, irec, sizeof(struct xfs_refcount_irec)); 407 } 408 409 STATIC int 410 xchk_rtrefcountbt_rmap_check_gap( 411 struct xfs_btree_cur *cur, 412 const struct xfs_rmap_irec *rec, 413 void *priv) 414 { 415 xfs_rgblock_t *next_bno = priv; 416 417 if (*next_bno != NULLRGBLOCK && rec->rm_startblock < *next_bno) 418 return -ECANCELED; 419 420 *next_bno = rec->rm_startblock + rec->rm_blockcount; 421 return 0; 422 } 423 424 /* 425 * Make sure that a gap in the reference count records does not correspond to 426 * overlapping records (i.e. shared extents) in the reverse mappings. 427 */ 428 static inline void 429 xchk_rtrefcountbt_xref_gaps( 430 struct xfs_scrub *sc, 431 struct xchk_rtrefcbt_records *rrc, 432 xfs_rgblock_t bno) 433 { 434 struct xfs_rmap_irec low; 435 struct xfs_rmap_irec high; 436 xfs_rgblock_t next_bno = NULLRGBLOCK; 437 int error; 438 439 if (bno <= rrc->next_unshared_rgbno || !sc->sr.rmap_cur || 440 xchk_skip_xref(sc->sm)) 441 return; 442 443 memset(&low, 0, sizeof(low)); 444 low.rm_startblock = rrc->next_unshared_rgbno; 445 memset(&high, 0xFF, sizeof(high)); 446 high.rm_startblock = bno - 1; 447 448 error = xfs_rmap_query_range(sc->sr.rmap_cur, &low, &high, 449 xchk_rtrefcountbt_rmap_check_gap, &next_bno); 450 if (error == -ECANCELED) 451 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 452 else 453 xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur); 454 } 455 456 /* Scrub a rtrefcountbt record. */ 457 STATIC int 458 xchk_rtrefcountbt_rec( 459 struct xchk_btree *bs, 460 const union xfs_btree_rec *rec) 461 { 462 struct xfs_mount *mp = bs->cur->bc_mp; 463 struct xchk_rtrefcbt_records *rrc = bs->private; 464 struct xfs_refcount_irec irec; 465 u32 mod; 466 467 xfs_refcount_btrec_to_irec(rec, &irec); 468 if (xfs_rtrefcount_check_irec(to_rtg(bs->cur->bc_group), &irec) != 469 NULL) { 470 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 471 return 0; 472 } 473 474 /* We can only share full rt extents. */ 475 mod = xfs_rgbno_to_rtxoff(mp, irec.rc_startblock); 476 if (mod) 477 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 478 mod = xfs_extlen_to_rtxmod(mp, irec.rc_blockcount); 479 if (mod) 480 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 481 482 if (irec.rc_domain == XFS_REFC_DOMAIN_COW) 483 rrc->cow_blocks += irec.rc_blockcount; 484 485 /* Shared records always come before CoW records. */ 486 if (irec.rc_domain == XFS_REFC_DOMAIN_SHARED && 487 rrc->prev_domain == XFS_REFC_DOMAIN_COW) 488 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 489 rrc->prev_domain = irec.rc_domain; 490 491 xchk_rtrefcountbt_check_mergeable(bs, rrc, &irec); 492 xchk_rtrefcountbt_xref(bs->sc, &irec); 493 494 /* 495 * If this is a record for a shared extent, check that all blocks 496 * between the previous record and this one have at most one reverse 497 * mapping. 498 */ 499 if (irec.rc_domain == XFS_REFC_DOMAIN_SHARED) { 500 xchk_rtrefcountbt_xref_gaps(bs->sc, rrc, irec.rc_startblock); 501 rrc->next_unshared_rgbno = irec.rc_startblock + 502 irec.rc_blockcount; 503 } 504 505 return 0; 506 } 507 508 /* Count the number of blocks used by the rtrefcount btree file in this AG. */ 509 static int 510 xchk_rtrefcount_count_agblocks( 511 struct xfs_scrub *sc, 512 xfs_agnumber_t agno, 513 const struct xfs_owner_info *btree_oinfo, 514 xfs_filblks_t *blocks) 515 { 516 xfs_filblks_t agblocks = 0; 517 int error; 518 519 error = xchk_ag_init_existing(sc, agno, &sc->sa); 520 if (error) 521 goto out_free; 522 523 /* 524 * If we don't have an rmap cursor, we can't complete the cross 525 * referencing, so return EFSCORRUPTED to end the loop and trigger the 526 * XFAIL flag. 527 */ 528 if (!sc->sa.rmap_cur) { 529 error = -EFSCORRUPTED; 530 goto out_free; 531 } 532 533 error = xchk_count_rmap_ownedby_ag(sc, sc->sa.rmap_cur, btree_oinfo, 534 &agblocks); 535 if (error) 536 goto out_free; 537 538 *blocks += agblocks; 539 out_free: 540 xchk_ag_free(sc, &sc->sa); 541 return error; 542 } 543 544 /* Make sure we have as many refc blocks as the rmap says. */ 545 STATIC void 546 xchk_rtrefcount_xref_rmap( 547 struct xfs_scrub *sc, 548 const struct xfs_owner_info *btree_oinfo, 549 xfs_extlen_t cow_blocks) 550 { 551 xfs_filblks_t refcbt_blocks = 0; 552 xfs_filblks_t blocks = 1; /* one for the iroot */ 553 xfs_agnumber_t agno; 554 int error = 0; 555 556 if (!xfs_has_rmapbt(sc->mp) || xchk_skip_xref(sc->sm)) 557 return; 558 559 /* Check that we saw as many refcbt blocks as the rmap knows about. */ 560 error = xfs_btree_count_blocks(sc->sr.refc_cur, &refcbt_blocks); 561 if (!xchk_btree_process_error(sc, sc->sr.refc_cur, 0, &error)) 562 return; 563 564 for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) { 565 error = xchk_rtrefcount_count_agblocks(sc, agno, btree_oinfo, 566 &blocks); 567 if (error) 568 break; 569 } 570 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error)) 571 return; 572 if (blocks != refcbt_blocks) 573 xchk_fblock_xref_set_corrupt(sc, XFS_DATA_FORK, 0); 574 575 if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm)) 576 return; 577 578 /* Check that we saw as many cow blocks as the rmap knows about. */ 579 error = xchk_count_rmap_ownedby_ag(sc, sc->sr.rmap_cur, 580 &XFS_RMAP_OINFO_COW, &blocks); 581 if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur)) 582 return; 583 if (blocks != cow_blocks) 584 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 585 } 586 587 /* Scrub the refcount btree for some rtgroup. */ 588 int 589 xchk_rtrefcountbt( 590 struct xfs_scrub *sc) 591 { 592 struct xfs_owner_info btree_oinfo; 593 struct xchk_rtrefcbt_records rrc = { 594 .cow_blocks = 0, 595 .next_unshared_rgbno = 0, 596 .prev_domain = XFS_REFC_DOMAIN_SHARED, 597 }; 598 int error; 599 600 error = xchk_metadata_inode_forks(sc); 601 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 602 return error; 603 604 xfs_rmap_inode_bmbt_owner(&btree_oinfo, rtg_refcount(sc->sr.rtg), 605 XFS_DATA_FORK); 606 error = xchk_btree(sc, sc->sr.refc_cur, xchk_rtrefcountbt_rec, 607 &btree_oinfo, &rrc); 608 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 609 return error; 610 611 /* 612 * Check that all blocks between the last refcount > 1 record and the 613 * end of the rtgroup have at most one reverse mapping. 614 */ 615 xchk_rtrefcountbt_xref_gaps(sc, &rrc, 616 xfs_rtx_to_rgbno(sc->sr.rtg, sc->mp->m_sb.sb_rgextents)); 617 xchk_rtrefcount_xref_rmap(sc, &btree_oinfo, rrc.cow_blocks); 618 619 return 0; 620 } 621 622 /* xref check that a cow staging extent is marked in the rtrefcountbt. */ 623 void 624 xchk_xref_is_rt_cow_staging( 625 struct xfs_scrub *sc, 626 xfs_rgblock_t bno, 627 xfs_extlen_t len) 628 { 629 struct xfs_refcount_irec rc; 630 int has_refcount; 631 int error; 632 633 if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm)) 634 return; 635 636 /* Find the CoW staging extent. */ 637 error = xfs_refcount_lookup_le(sc->sr.refc_cur, XFS_REFC_DOMAIN_COW, 638 bno, &has_refcount); 639 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) 640 return; 641 if (!has_refcount) { 642 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); 643 return; 644 } 645 646 error = xfs_refcount_get_rec(sc->sr.refc_cur, &rc, &has_refcount); 647 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) 648 return; 649 if (!has_refcount) { 650 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); 651 return; 652 } 653 654 /* CoW lookup returned a shared extent record? */ 655 if (rc.rc_domain != XFS_REFC_DOMAIN_COW) 656 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); 657 658 /* Can't start after bno */ 659 if (rc.rc_startblock > bno) 660 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); 661 662 /* Must be at least as long as what was passed in */ 663 if (rc.rc_startblock + rc.rc_blockcount < bno + len) 664 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); 665 } 666 667 /* 668 * xref check that the extent is not shared. Only file data blocks 669 * can have multiple owners. 670 */ 671 void 672 xchk_xref_is_not_rt_shared( 673 struct xfs_scrub *sc, 674 xfs_rgblock_t bno, 675 xfs_extlen_t len) 676 { 677 enum xbtree_recpacking outcome; 678 int error; 679 680 if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm)) 681 return; 682 683 error = xfs_refcount_has_records(sc->sr.refc_cur, 684 XFS_REFC_DOMAIN_SHARED, bno, len, &outcome); 685 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) 686 return; 687 if (outcome != XBTREE_RECPACKING_EMPTY) 688 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); 689 } 690 691 /* xref check that the extent is not being used for CoW staging. */ 692 void 693 xchk_xref_is_not_rt_cow_staging( 694 struct xfs_scrub *sc, 695 xfs_rgblock_t bno, 696 xfs_extlen_t len) 697 { 698 enum xbtree_recpacking outcome; 699 int error; 700 701 if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm)) 702 return; 703 704 error = xfs_refcount_has_records(sc->sr.refc_cur, XFS_REFC_DOMAIN_COW, 705 bno, len, &outcome); 706 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) 707 return; 708 if (outcome != XBTREE_RECPACKING_EMPTY) 709 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); 710 } 711