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