1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2017 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 */ 6 #include "xfs.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_trans_resv.h" 11 #include "xfs_mount.h" 12 #include "xfs_btree.h" 13 #include "xfs_bit.h" 14 #include "xfs_log_format.h" 15 #include "xfs_trans.h" 16 #include "xfs_inode.h" 17 #include "xfs_alloc.h" 18 #include "xfs_bmap.h" 19 #include "xfs_bmap_btree.h" 20 #include "xfs_rmap.h" 21 #include "xfs_rmap_btree.h" 22 #include "scrub/scrub.h" 23 #include "scrub/common.h" 24 #include "scrub/btree.h" 25 26 /* Set us up with an inode's bmap. */ 27 int 28 xchk_setup_inode_bmap( 29 struct xfs_scrub *sc, 30 struct xfs_inode *ip) 31 { 32 int error; 33 34 error = xchk_get_inode(sc, ip); 35 if (error) 36 goto out; 37 38 sc->ilock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; 39 xfs_ilock(sc->ip, sc->ilock_flags); 40 41 /* 42 * We don't want any ephemeral data fork updates sitting around 43 * while we inspect block mappings, so wait for directio to finish 44 * and flush dirty data if we have delalloc reservations. 45 */ 46 if (S_ISREG(VFS_I(sc->ip)->i_mode) && 47 sc->sm->sm_type == XFS_SCRUB_TYPE_BMBTD) { 48 inode_dio_wait(VFS_I(sc->ip)); 49 error = filemap_write_and_wait(VFS_I(sc->ip)->i_mapping); 50 if (error) 51 goto out; 52 } 53 54 /* Got the inode, lock it and we're ready to go. */ 55 error = xchk_trans_alloc(sc, 0); 56 if (error) 57 goto out; 58 sc->ilock_flags |= XFS_ILOCK_EXCL; 59 xfs_ilock(sc->ip, XFS_ILOCK_EXCL); 60 61 out: 62 /* scrub teardown will unlock and release the inode */ 63 return error; 64 } 65 66 /* 67 * Inode fork block mapping (BMBT) scrubber. 68 * More complex than the others because we have to scrub 69 * all the extents regardless of whether or not the fork 70 * is in btree format. 71 */ 72 73 struct xchk_bmap_info { 74 struct xfs_scrub *sc; 75 xfs_fileoff_t lastoff; 76 bool is_rt; 77 bool is_shared; 78 bool was_loaded; 79 int whichfork; 80 }; 81 82 /* Look for a corresponding rmap for this irec. */ 83 static inline bool 84 xchk_bmap_get_rmap( 85 struct xchk_bmap_info *info, 86 struct xfs_bmbt_irec *irec, 87 xfs_agblock_t agbno, 88 uint64_t owner, 89 struct xfs_rmap_irec *rmap) 90 { 91 xfs_fileoff_t offset; 92 unsigned int rflags = 0; 93 int has_rmap; 94 int error; 95 96 if (info->whichfork == XFS_ATTR_FORK) 97 rflags |= XFS_RMAP_ATTR_FORK; 98 99 /* 100 * CoW staging extents are owned (on disk) by the refcountbt, so 101 * their rmaps do not have offsets. 102 */ 103 if (info->whichfork == XFS_COW_FORK) 104 offset = 0; 105 else 106 offset = irec->br_startoff; 107 108 /* 109 * If the caller thinks this could be a shared bmbt extent (IOWs, 110 * any data fork extent of a reflink inode) then we have to use the 111 * range rmap lookup to make sure we get the correct owner/offset. 112 */ 113 if (info->is_shared) { 114 error = xfs_rmap_lookup_le_range(info->sc->sa.rmap_cur, agbno, 115 owner, offset, rflags, rmap, &has_rmap); 116 if (!xchk_should_check_xref(info->sc, &error, 117 &info->sc->sa.rmap_cur)) 118 return false; 119 goto out; 120 } 121 122 /* 123 * Otherwise, use the (faster) regular lookup. 124 */ 125 error = xfs_rmap_lookup_le(info->sc->sa.rmap_cur, agbno, 0, owner, 126 offset, rflags, &has_rmap); 127 if (!xchk_should_check_xref(info->sc, &error, 128 &info->sc->sa.rmap_cur)) 129 return false; 130 if (!has_rmap) 131 goto out; 132 133 error = xfs_rmap_get_rec(info->sc->sa.rmap_cur, rmap, &has_rmap); 134 if (!xchk_should_check_xref(info->sc, &error, 135 &info->sc->sa.rmap_cur)) 136 return false; 137 138 out: 139 if (!has_rmap) 140 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, 141 irec->br_startoff); 142 return has_rmap; 143 } 144 145 /* Make sure that we have rmapbt records for this extent. */ 146 STATIC void 147 xchk_bmap_xref_rmap( 148 struct xchk_bmap_info *info, 149 struct xfs_bmbt_irec *irec, 150 xfs_agblock_t agbno) 151 { 152 struct xfs_rmap_irec rmap; 153 unsigned long long rmap_end; 154 uint64_t owner; 155 156 if (!info->sc->sa.rmap_cur || xchk_skip_xref(info->sc->sm)) 157 return; 158 159 if (info->whichfork == XFS_COW_FORK) 160 owner = XFS_RMAP_OWN_COW; 161 else 162 owner = info->sc->ip->i_ino; 163 164 /* Find the rmap record for this irec. */ 165 if (!xchk_bmap_get_rmap(info, irec, agbno, owner, &rmap)) 166 return; 167 168 /* Check the rmap. */ 169 rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount; 170 if (rmap.rm_startblock > agbno || 171 agbno + irec->br_blockcount > rmap_end) 172 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, 173 irec->br_startoff); 174 175 /* 176 * Check the logical offsets if applicable. CoW staging extents 177 * don't track logical offsets since the mappings only exist in 178 * memory. 179 */ 180 if (info->whichfork != XFS_COW_FORK) { 181 rmap_end = (unsigned long long)rmap.rm_offset + 182 rmap.rm_blockcount; 183 if (rmap.rm_offset > irec->br_startoff || 184 irec->br_startoff + irec->br_blockcount > rmap_end) 185 xchk_fblock_xref_set_corrupt(info->sc, 186 info->whichfork, irec->br_startoff); 187 } 188 189 if (rmap.rm_owner != owner) 190 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, 191 irec->br_startoff); 192 193 /* 194 * Check for discrepancies between the unwritten flag in the irec and 195 * the rmap. Note that the (in-memory) CoW fork distinguishes between 196 * unwritten and written extents, but we don't track that in the rmap 197 * records because the blocks are owned (on-disk) by the refcountbt, 198 * which doesn't track unwritten state. 199 */ 200 if (owner != XFS_RMAP_OWN_COW && 201 irec->br_state == XFS_EXT_UNWRITTEN && 202 !(rmap.rm_flags & XFS_RMAP_UNWRITTEN)) 203 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, 204 irec->br_startoff); 205 206 if (info->whichfork == XFS_ATTR_FORK && 207 !(rmap.rm_flags & XFS_RMAP_ATTR_FORK)) 208 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, 209 irec->br_startoff); 210 if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK) 211 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, 212 irec->br_startoff); 213 } 214 215 /* Cross-reference a single rtdev extent record. */ 216 STATIC void 217 xchk_bmap_rt_iextent_xref( 218 struct xfs_inode *ip, 219 struct xchk_bmap_info *info, 220 struct xfs_bmbt_irec *irec) 221 { 222 xchk_xref_is_used_rt_space(info->sc, irec->br_startblock, 223 irec->br_blockcount); 224 } 225 226 /* Cross-reference a single datadev extent record. */ 227 STATIC void 228 xchk_bmap_iextent_xref( 229 struct xfs_inode *ip, 230 struct xchk_bmap_info *info, 231 struct xfs_bmbt_irec *irec) 232 { 233 struct xfs_mount *mp = info->sc->mp; 234 xfs_agnumber_t agno; 235 xfs_agblock_t agbno; 236 xfs_extlen_t len; 237 int error; 238 239 agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock); 240 agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock); 241 len = irec->br_blockcount; 242 243 error = xchk_ag_init(info->sc, agno, &info->sc->sa); 244 if (!xchk_fblock_process_error(info->sc, info->whichfork, 245 irec->br_startoff, &error)) 246 return; 247 248 xchk_xref_is_used_space(info->sc, agbno, len); 249 xchk_xref_is_not_inode_chunk(info->sc, agbno, len); 250 xchk_bmap_xref_rmap(info, irec, agbno); 251 switch (info->whichfork) { 252 case XFS_DATA_FORK: 253 if (xfs_is_reflink_inode(info->sc->ip)) 254 break; 255 /* fall through */ 256 case XFS_ATTR_FORK: 257 xchk_xref_is_not_shared(info->sc, agbno, 258 irec->br_blockcount); 259 break; 260 case XFS_COW_FORK: 261 xchk_xref_is_cow_staging(info->sc, agbno, 262 irec->br_blockcount); 263 break; 264 } 265 266 xchk_ag_free(info->sc, &info->sc->sa); 267 } 268 269 /* 270 * Directories and attr forks should never have blocks that can't be addressed 271 * by a xfs_dablk_t. 272 */ 273 STATIC void 274 xchk_bmap_dirattr_extent( 275 struct xfs_inode *ip, 276 struct xchk_bmap_info *info, 277 struct xfs_bmbt_irec *irec) 278 { 279 struct xfs_mount *mp = ip->i_mount; 280 xfs_fileoff_t off; 281 282 if (!S_ISDIR(VFS_I(ip)->i_mode) && info->whichfork != XFS_ATTR_FORK) 283 return; 284 285 if (!xfs_verify_dablk(mp, irec->br_startoff)) 286 xchk_fblock_set_corrupt(info->sc, info->whichfork, 287 irec->br_startoff); 288 289 off = irec->br_startoff + irec->br_blockcount - 1; 290 if (!xfs_verify_dablk(mp, off)) 291 xchk_fblock_set_corrupt(info->sc, info->whichfork, off); 292 } 293 294 /* Scrub a single extent record. */ 295 STATIC int 296 xchk_bmap_iextent( 297 struct xfs_inode *ip, 298 struct xchk_bmap_info *info, 299 struct xfs_bmbt_irec *irec) 300 { 301 struct xfs_mount *mp = info->sc->mp; 302 xfs_filblks_t end; 303 int error = 0; 304 305 /* 306 * Check for out-of-order extents. This record could have come 307 * from the incore list, for which there is no ordering check. 308 */ 309 if (irec->br_startoff < info->lastoff) 310 xchk_fblock_set_corrupt(info->sc, info->whichfork, 311 irec->br_startoff); 312 313 xchk_bmap_dirattr_extent(ip, info, irec); 314 315 /* There should never be a "hole" extent in either extent list. */ 316 if (irec->br_startblock == HOLESTARTBLOCK) 317 xchk_fblock_set_corrupt(info->sc, info->whichfork, 318 irec->br_startoff); 319 320 /* 321 * Check for delalloc extents. We never iterate the ones in the 322 * in-core extent scan, and we should never see these in the bmbt. 323 */ 324 if (isnullstartblock(irec->br_startblock)) 325 xchk_fblock_set_corrupt(info->sc, info->whichfork, 326 irec->br_startoff); 327 328 /* Make sure the extent points to a valid place. */ 329 if (irec->br_blockcount > MAXEXTLEN) 330 xchk_fblock_set_corrupt(info->sc, info->whichfork, 331 irec->br_startoff); 332 if (irec->br_startblock + irec->br_blockcount <= irec->br_startblock) 333 xchk_fblock_set_corrupt(info->sc, info->whichfork, 334 irec->br_startoff); 335 end = irec->br_startblock + irec->br_blockcount - 1; 336 if (info->is_rt && 337 (!xfs_verify_rtbno(mp, irec->br_startblock) || 338 !xfs_verify_rtbno(mp, end))) 339 xchk_fblock_set_corrupt(info->sc, info->whichfork, 340 irec->br_startoff); 341 if (!info->is_rt && 342 (!xfs_verify_fsbno(mp, irec->br_startblock) || 343 !xfs_verify_fsbno(mp, end) || 344 XFS_FSB_TO_AGNO(mp, irec->br_startblock) != 345 XFS_FSB_TO_AGNO(mp, end))) 346 xchk_fblock_set_corrupt(info->sc, info->whichfork, 347 irec->br_startoff); 348 349 /* We don't allow unwritten extents on attr forks. */ 350 if (irec->br_state == XFS_EXT_UNWRITTEN && 351 info->whichfork == XFS_ATTR_FORK) 352 xchk_fblock_set_corrupt(info->sc, info->whichfork, 353 irec->br_startoff); 354 355 if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 356 return 0; 357 358 if (info->is_rt) 359 xchk_bmap_rt_iextent_xref(ip, info, irec); 360 else 361 xchk_bmap_iextent_xref(ip, info, irec); 362 363 info->lastoff = irec->br_startoff + irec->br_blockcount; 364 return error; 365 } 366 367 /* Scrub a bmbt record. */ 368 STATIC int 369 xchk_bmapbt_rec( 370 struct xchk_btree *bs, 371 union xfs_btree_rec *rec) 372 { 373 struct xfs_bmbt_irec irec; 374 struct xfs_bmbt_irec iext_irec; 375 struct xfs_iext_cursor icur; 376 struct xchk_bmap_info *info = bs->private; 377 struct xfs_inode *ip = bs->cur->bc_ino.ip; 378 struct xfs_buf *bp = NULL; 379 struct xfs_btree_block *block; 380 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, info->whichfork); 381 uint64_t owner; 382 int i; 383 384 /* 385 * Check the owners of the btree blocks up to the level below 386 * the root since the verifiers don't do that. 387 */ 388 if (xfs_sb_version_hascrc(&bs->cur->bc_mp->m_sb) && 389 bs->cur->bc_ptrs[0] == 1) { 390 for (i = 0; i < bs->cur->bc_nlevels - 1; i++) { 391 block = xfs_btree_get_block(bs->cur, i, &bp); 392 owner = be64_to_cpu(block->bb_u.l.bb_owner); 393 if (owner != ip->i_ino) 394 xchk_fblock_set_corrupt(bs->sc, 395 info->whichfork, 0); 396 } 397 } 398 399 /* 400 * Check that the incore extent tree contains an extent that matches 401 * this one exactly. We validate those cached bmaps later, so we don't 402 * need to check them here. If the incore extent tree was just loaded 403 * from disk by the scrubber, we assume that its contents match what's 404 * on disk (we still hold the ILOCK) and skip the equivalence check. 405 */ 406 if (!info->was_loaded) 407 return 0; 408 409 xfs_bmbt_disk_get_all(&rec->bmbt, &irec); 410 if (!xfs_iext_lookup_extent(ip, ifp, irec.br_startoff, &icur, 411 &iext_irec) || 412 irec.br_startoff != iext_irec.br_startoff || 413 irec.br_startblock != iext_irec.br_startblock || 414 irec.br_blockcount != iext_irec.br_blockcount || 415 irec.br_state != iext_irec.br_state) 416 xchk_fblock_set_corrupt(bs->sc, info->whichfork, 417 irec.br_startoff); 418 return 0; 419 } 420 421 /* Scan the btree records. */ 422 STATIC int 423 xchk_bmap_btree( 424 struct xfs_scrub *sc, 425 int whichfork, 426 struct xchk_bmap_info *info) 427 { 428 struct xfs_owner_info oinfo; 429 struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, whichfork); 430 struct xfs_mount *mp = sc->mp; 431 struct xfs_inode *ip = sc->ip; 432 struct xfs_btree_cur *cur; 433 int error; 434 435 /* Load the incore bmap cache if it's not loaded. */ 436 info->was_loaded = ifp->if_flags & XFS_IFEXTENTS; 437 if (!info->was_loaded) { 438 error = xfs_iread_extents(sc->tp, ip, whichfork); 439 if (!xchk_fblock_process_error(sc, whichfork, 0, &error)) 440 goto out; 441 } 442 443 /* Check the btree structure. */ 444 cur = xfs_bmbt_init_cursor(mp, sc->tp, ip, whichfork); 445 xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork); 446 error = xchk_btree(sc, cur, xchk_bmapbt_rec, &oinfo, info); 447 xfs_btree_del_cursor(cur, error); 448 out: 449 return error; 450 } 451 452 struct xchk_bmap_check_rmap_info { 453 struct xfs_scrub *sc; 454 int whichfork; 455 struct xfs_iext_cursor icur; 456 }; 457 458 /* Can we find bmaps that fit this rmap? */ 459 STATIC int 460 xchk_bmap_check_rmap( 461 struct xfs_btree_cur *cur, 462 struct xfs_rmap_irec *rec, 463 void *priv) 464 { 465 struct xfs_bmbt_irec irec; 466 struct xchk_bmap_check_rmap_info *sbcri = priv; 467 struct xfs_ifork *ifp; 468 struct xfs_scrub *sc = sbcri->sc; 469 bool have_map; 470 471 /* Is this even the right fork? */ 472 if (rec->rm_owner != sc->ip->i_ino) 473 return 0; 474 if ((sbcri->whichfork == XFS_ATTR_FORK) ^ 475 !!(rec->rm_flags & XFS_RMAP_ATTR_FORK)) 476 return 0; 477 if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK) 478 return 0; 479 480 /* Now look up the bmbt record. */ 481 ifp = XFS_IFORK_PTR(sc->ip, sbcri->whichfork); 482 if (!ifp) { 483 xchk_fblock_set_corrupt(sc, sbcri->whichfork, 484 rec->rm_offset); 485 goto out; 486 } 487 have_map = xfs_iext_lookup_extent(sc->ip, ifp, rec->rm_offset, 488 &sbcri->icur, &irec); 489 if (!have_map) 490 xchk_fblock_set_corrupt(sc, sbcri->whichfork, 491 rec->rm_offset); 492 /* 493 * bmap extent record lengths are constrained to 2^21 blocks in length 494 * because of space constraints in the on-disk metadata structure. 495 * However, rmap extent record lengths are constrained only by AG 496 * length, so we have to loop through the bmbt to make sure that the 497 * entire rmap is covered by bmbt records. 498 */ 499 while (have_map) { 500 if (irec.br_startoff != rec->rm_offset) 501 xchk_fblock_set_corrupt(sc, sbcri->whichfork, 502 rec->rm_offset); 503 if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp, 504 cur->bc_ag.agno, rec->rm_startblock)) 505 xchk_fblock_set_corrupt(sc, sbcri->whichfork, 506 rec->rm_offset); 507 if (irec.br_blockcount > rec->rm_blockcount) 508 xchk_fblock_set_corrupt(sc, sbcri->whichfork, 509 rec->rm_offset); 510 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 511 break; 512 rec->rm_startblock += irec.br_blockcount; 513 rec->rm_offset += irec.br_blockcount; 514 rec->rm_blockcount -= irec.br_blockcount; 515 if (rec->rm_blockcount == 0) 516 break; 517 have_map = xfs_iext_next_extent(ifp, &sbcri->icur, &irec); 518 if (!have_map) 519 xchk_fblock_set_corrupt(sc, sbcri->whichfork, 520 rec->rm_offset); 521 } 522 523 out: 524 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 525 return -ECANCELED; 526 return 0; 527 } 528 529 /* Make sure each rmap has a corresponding bmbt entry. */ 530 STATIC int 531 xchk_bmap_check_ag_rmaps( 532 struct xfs_scrub *sc, 533 int whichfork, 534 xfs_agnumber_t agno) 535 { 536 struct xchk_bmap_check_rmap_info sbcri; 537 struct xfs_btree_cur *cur; 538 struct xfs_buf *agf; 539 int error; 540 541 error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf); 542 if (error) 543 return error; 544 545 cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno); 546 if (!cur) { 547 error = -ENOMEM; 548 goto out_agf; 549 } 550 551 sbcri.sc = sc; 552 sbcri.whichfork = whichfork; 553 error = xfs_rmap_query_all(cur, xchk_bmap_check_rmap, &sbcri); 554 if (error == -ECANCELED) 555 error = 0; 556 557 xfs_btree_del_cursor(cur, error); 558 out_agf: 559 xfs_trans_brelse(sc->tp, agf); 560 return error; 561 } 562 563 /* Make sure each rmap has a corresponding bmbt entry. */ 564 STATIC int 565 xchk_bmap_check_rmaps( 566 struct xfs_scrub *sc, 567 int whichfork) 568 { 569 loff_t size; 570 xfs_agnumber_t agno; 571 int error; 572 573 if (!xfs_sb_version_hasrmapbt(&sc->mp->m_sb) || 574 whichfork == XFS_COW_FORK || 575 (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 576 return 0; 577 578 /* Don't support realtime rmap checks yet. */ 579 if (XFS_IS_REALTIME_INODE(sc->ip) && whichfork == XFS_DATA_FORK) 580 return 0; 581 582 /* 583 * Only do this for complex maps that are in btree format, or for 584 * situations where we would seem to have a size but zero extents. 585 * The inode repair code can zap broken iforks, which means we have 586 * to flag this bmap as corrupt if there are rmaps that need to be 587 * reattached. 588 */ 589 switch (whichfork) { 590 case XFS_DATA_FORK: 591 size = i_size_read(VFS_I(sc->ip)); 592 break; 593 case XFS_ATTR_FORK: 594 size = XFS_IFORK_Q(sc->ip); 595 break; 596 default: 597 size = 0; 598 break; 599 } 600 if (XFS_IFORK_FORMAT(sc->ip, whichfork) != XFS_DINODE_FMT_BTREE && 601 (size == 0 || XFS_IFORK_NEXTENTS(sc->ip, whichfork) > 0)) 602 return 0; 603 604 for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) { 605 error = xchk_bmap_check_ag_rmaps(sc, whichfork, agno); 606 if (error) 607 return error; 608 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 609 break; 610 } 611 612 return 0; 613 } 614 615 /* 616 * Scrub an inode fork's block mappings. 617 * 618 * First we scan every record in every btree block, if applicable. 619 * Then we unconditionally scan the incore extent cache. 620 */ 621 STATIC int 622 xchk_bmap( 623 struct xfs_scrub *sc, 624 int whichfork) 625 { 626 struct xfs_bmbt_irec irec; 627 struct xchk_bmap_info info = { NULL }; 628 struct xfs_mount *mp = sc->mp; 629 struct xfs_inode *ip = sc->ip; 630 struct xfs_ifork *ifp; 631 xfs_fileoff_t endoff; 632 struct xfs_iext_cursor icur; 633 int error = 0; 634 635 ifp = XFS_IFORK_PTR(ip, whichfork); 636 637 info.is_rt = whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip); 638 info.whichfork = whichfork; 639 info.is_shared = whichfork == XFS_DATA_FORK && xfs_is_reflink_inode(ip); 640 info.sc = sc; 641 642 switch (whichfork) { 643 case XFS_COW_FORK: 644 /* Non-existent CoW forks are ignorable. */ 645 if (!ifp) 646 goto out; 647 /* No CoW forks on non-reflink inodes/filesystems. */ 648 if (!xfs_is_reflink_inode(ip)) { 649 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 650 goto out; 651 } 652 break; 653 case XFS_ATTR_FORK: 654 if (!ifp) 655 goto out_check_rmap; 656 if (!xfs_sb_version_hasattr(&mp->m_sb) && 657 !xfs_sb_version_hasattr2(&mp->m_sb)) 658 xchk_ino_set_corrupt(sc, sc->ip->i_ino); 659 break; 660 default: 661 ASSERT(whichfork == XFS_DATA_FORK); 662 break; 663 } 664 665 /* Check the fork values */ 666 switch (XFS_IFORK_FORMAT(ip, whichfork)) { 667 case XFS_DINODE_FMT_UUID: 668 case XFS_DINODE_FMT_DEV: 669 case XFS_DINODE_FMT_LOCAL: 670 /* No mappings to check. */ 671 goto out; 672 case XFS_DINODE_FMT_EXTENTS: 673 if (!(ifp->if_flags & XFS_IFEXTENTS)) { 674 xchk_fblock_set_corrupt(sc, whichfork, 0); 675 goto out; 676 } 677 break; 678 case XFS_DINODE_FMT_BTREE: 679 if (whichfork == XFS_COW_FORK) { 680 xchk_fblock_set_corrupt(sc, whichfork, 0); 681 goto out; 682 } 683 684 error = xchk_bmap_btree(sc, whichfork, &info); 685 if (error) 686 goto out; 687 break; 688 default: 689 xchk_fblock_set_corrupt(sc, whichfork, 0); 690 goto out; 691 } 692 693 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 694 goto out; 695 696 /* Find the offset of the last extent in the mapping. */ 697 error = xfs_bmap_last_offset(ip, &endoff, whichfork); 698 if (!xchk_fblock_process_error(sc, whichfork, 0, &error)) 699 goto out; 700 701 /* Scrub extent records. */ 702 info.lastoff = 0; 703 ifp = XFS_IFORK_PTR(ip, whichfork); 704 for_each_xfs_iext(ifp, &icur, &irec) { 705 if (xchk_should_terminate(sc, &error) || 706 (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 707 goto out; 708 if (isnullstartblock(irec.br_startblock)) 709 continue; 710 if (irec.br_startoff >= endoff) { 711 xchk_fblock_set_corrupt(sc, whichfork, 712 irec.br_startoff); 713 goto out; 714 } 715 error = xchk_bmap_iextent(ip, &info, &irec); 716 if (error) 717 goto out; 718 } 719 720 out_check_rmap: 721 error = xchk_bmap_check_rmaps(sc, whichfork); 722 if (!xchk_fblock_xref_process_error(sc, whichfork, 0, &error)) 723 goto out; 724 out: 725 return error; 726 } 727 728 /* Scrub an inode's data fork. */ 729 int 730 xchk_bmap_data( 731 struct xfs_scrub *sc) 732 { 733 return xchk_bmap(sc, XFS_DATA_FORK); 734 } 735 736 /* Scrub an inode's attr fork. */ 737 int 738 xchk_bmap_attr( 739 struct xfs_scrub *sc) 740 { 741 return xchk_bmap(sc, XFS_ATTR_FORK); 742 } 743 744 /* Scrub an inode's CoW fork. */ 745 int 746 xchk_bmap_cow( 747 struct xfs_scrub *sc) 748 { 749 if (!xfs_is_reflink_inode(sc->ip)) 750 return -ENOENT; 751 752 return xchk_bmap(sc, XFS_COW_FORK); 753 } 754