1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <djwong@kernel.org> 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_log_format.h" 13 #include "xfs_trans.h" 14 #include "xfs_inode.h" 15 #include "xfs_quota.h" 16 #include "xfs_qm.h" 17 #include "xfs_scrub.h" 18 #include "xfs_buf_mem.h" 19 #include "scrub/scrub.h" 20 #include "scrub/common.h" 21 #include "scrub/trace.h" 22 #include "scrub/repair.h" 23 #include "scrub/health.h" 24 #include "scrub/stats.h" 25 #include "scrub/xfile.h" 26 27 /* 28 * Online Scrub and Repair 29 * 30 * Traditionally, XFS (the kernel driver) did not know how to check or 31 * repair on-disk data structures. That task was left to the xfs_check 32 * and xfs_repair tools, both of which require taking the filesystem 33 * offline for a thorough but time consuming examination. Online 34 * scrub & repair, on the other hand, enables us to check the metadata 35 * for obvious errors while carefully stepping around the filesystem's 36 * ongoing operations, locking rules, etc. 37 * 38 * Given that most XFS metadata consist of records stored in a btree, 39 * most of the checking functions iterate the btree blocks themselves 40 * looking for irregularities. When a record block is encountered, each 41 * record can be checked for obviously bad values. Record values can 42 * also be cross-referenced against other btrees to look for potential 43 * misunderstandings between pieces of metadata. 44 * 45 * It is expected that the checkers responsible for per-AG metadata 46 * structures will lock the AG headers (AGI, AGF, AGFL), iterate the 47 * metadata structure, and perform any relevant cross-referencing before 48 * unlocking the AG and returning the results to userspace. These 49 * scrubbers must not keep an AG locked for too long to avoid tying up 50 * the block and inode allocators. 51 * 52 * Block maps and b-trees rooted in an inode present a special challenge 53 * because they can involve extents from any AG. The general scrubber 54 * structure of lock -> check -> xref -> unlock still holds, but AG 55 * locking order rules /must/ be obeyed to avoid deadlocks. The 56 * ordering rule, of course, is that we must lock in increasing AG 57 * order. Helper functions are provided to track which AG headers we've 58 * already locked. If we detect an imminent locking order violation, we 59 * can signal a potential deadlock, in which case the scrubber can jump 60 * out to the top level, lock all the AGs in order, and retry the scrub. 61 * 62 * For file data (directories, extended attributes, symlinks) scrub, we 63 * can simply lock the inode and walk the data. For btree data 64 * (directories and attributes) we follow the same btree-scrubbing 65 * strategy outlined previously to check the records. 66 * 67 * We use a bit of trickery with transactions to avoid buffer deadlocks 68 * if there is a cycle in the metadata. The basic problem is that 69 * travelling down a btree involves locking the current buffer at each 70 * tree level. If a pointer should somehow point back to a buffer that 71 * we've already examined, we will deadlock due to the second buffer 72 * locking attempt. Note however that grabbing a buffer in transaction 73 * context links the locked buffer to the transaction. If we try to 74 * re-grab the buffer in the context of the same transaction, we avoid 75 * the second lock attempt and continue. Between the verifier and the 76 * scrubber, something will notice that something is amiss and report 77 * the corruption. Therefore, each scrubber will allocate an empty 78 * transaction, attach buffers to it, and cancel the transaction at the 79 * end of the scrub run. Cancelling a non-dirty transaction simply 80 * unlocks the buffers. 81 * 82 * There are four pieces of data that scrub can communicate to 83 * userspace. The first is the error code (errno), which can be used to 84 * communicate operational errors in performing the scrub. There are 85 * also three flags that can be set in the scrub context. If the data 86 * structure itself is corrupt, the CORRUPT flag will be set. If 87 * the metadata is correct but otherwise suboptimal, the PREEN flag 88 * will be set. 89 * 90 * We perform secondary validation of filesystem metadata by 91 * cross-referencing every record with all other available metadata. 92 * For example, for block mapping extents, we verify that there are no 93 * records in the free space and inode btrees corresponding to that 94 * space extent and that there is a corresponding entry in the reverse 95 * mapping btree. Inconsistent metadata is noted by setting the 96 * XCORRUPT flag; btree query function errors are noted by setting the 97 * XFAIL flag and deleting the cursor to prevent further attempts to 98 * cross-reference with a defective btree. 99 * 100 * If a piece of metadata proves corrupt or suboptimal, the userspace 101 * program can ask the kernel to apply some tender loving care (TLC) to 102 * the metadata object by setting the REPAIR flag and re-calling the 103 * scrub ioctl. "Corruption" is defined by metadata violating the 104 * on-disk specification; operations cannot continue if the violation is 105 * left untreated. It is possible for XFS to continue if an object is 106 * "suboptimal", however performance may be degraded. Repairs are 107 * usually performed by rebuilding the metadata entirely out of 108 * redundant metadata. Optimizing, on the other hand, can sometimes be 109 * done without rebuilding entire structures. 110 * 111 * Generally speaking, the repair code has the following code structure: 112 * Lock -> scrub -> repair -> commit -> re-lock -> re-scrub -> unlock. 113 * The first check helps us figure out if we need to rebuild or simply 114 * optimize the structure so that the rebuild knows what to do. The 115 * second check evaluates the completeness of the repair; that is what 116 * is reported to userspace. 117 * 118 * A quick note on symbol prefixes: 119 * - "xfs_" are general XFS symbols. 120 * - "xchk_" are symbols related to metadata checking. 121 * - "xrep_" are symbols related to metadata repair. 122 * - "xfs_scrub_" are symbols that tie online fsck to the rest of XFS. 123 */ 124 125 /* 126 * Scrub probe -- userspace uses this to probe if we're willing to scrub 127 * or repair a given mountpoint. This will be used by xfs_scrub to 128 * probe the kernel's abilities to scrub (and repair) the metadata. We 129 * do this by validating the ioctl inputs from userspace, preparing the 130 * filesystem for a scrub (or a repair) operation, and immediately 131 * returning to userspace. Userspace can use the returned errno and 132 * structure state to decide (in broad terms) if scrub/repair are 133 * supported by the running kernel. 134 */ 135 static int 136 xchk_probe( 137 struct xfs_scrub *sc) 138 { 139 int error = 0; 140 141 if (xchk_should_terminate(sc, &error)) 142 return error; 143 144 return 0; 145 } 146 147 /* Scrub setup and teardown */ 148 149 static inline void 150 xchk_fsgates_disable( 151 struct xfs_scrub *sc) 152 { 153 if (!(sc->flags & XCHK_FSGATES_ALL)) 154 return; 155 156 trace_xchk_fsgates_disable(sc, sc->flags & XCHK_FSGATES_ALL); 157 158 if (sc->flags & XCHK_FSGATES_DRAIN) 159 xfs_drain_wait_disable(); 160 161 if (sc->flags & XCHK_FSGATES_QUOTA) 162 xfs_dqtrx_hook_disable(); 163 164 if (sc->flags & XCHK_FSGATES_DIRENTS) 165 xfs_dir_hook_disable(); 166 167 sc->flags &= ~XCHK_FSGATES_ALL; 168 } 169 170 /* Free all the resources and finish the transactions. */ 171 STATIC int 172 xchk_teardown( 173 struct xfs_scrub *sc, 174 int error) 175 { 176 xchk_ag_free(sc, &sc->sa); 177 if (sc->tp) { 178 if (error == 0 && (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) 179 error = xfs_trans_commit(sc->tp); 180 else 181 xfs_trans_cancel(sc->tp); 182 sc->tp = NULL; 183 } 184 if (sc->ip) { 185 if (sc->ilock_flags) 186 xchk_iunlock(sc, sc->ilock_flags); 187 xchk_irele(sc, sc->ip); 188 sc->ip = NULL; 189 } 190 if (sc->flags & XCHK_HAVE_FREEZE_PROT) { 191 sc->flags &= ~XCHK_HAVE_FREEZE_PROT; 192 mnt_drop_write_file(sc->file); 193 } 194 if (sc->xmbtp) { 195 xmbuf_free(sc->xmbtp); 196 sc->xmbtp = NULL; 197 } 198 if (sc->xfile) { 199 xfile_destroy(sc->xfile); 200 sc->xfile = NULL; 201 } 202 if (sc->buf) { 203 if (sc->buf_cleanup) 204 sc->buf_cleanup(sc->buf); 205 kvfree(sc->buf); 206 sc->buf_cleanup = NULL; 207 sc->buf = NULL; 208 } 209 210 xchk_fsgates_disable(sc); 211 return error; 212 } 213 214 /* Scrubbing dispatch. */ 215 216 static const struct xchk_meta_ops meta_scrub_ops[] = { 217 [XFS_SCRUB_TYPE_PROBE] = { /* ioctl presence test */ 218 .type = ST_NONE, 219 .setup = xchk_setup_fs, 220 .scrub = xchk_probe, 221 .repair = xrep_probe, 222 }, 223 [XFS_SCRUB_TYPE_SB] = { /* superblock */ 224 .type = ST_PERAG, 225 .setup = xchk_setup_agheader, 226 .scrub = xchk_superblock, 227 .repair = xrep_superblock, 228 }, 229 [XFS_SCRUB_TYPE_AGF] = { /* agf */ 230 .type = ST_PERAG, 231 .setup = xchk_setup_agheader, 232 .scrub = xchk_agf, 233 .repair = xrep_agf, 234 }, 235 [XFS_SCRUB_TYPE_AGFL]= { /* agfl */ 236 .type = ST_PERAG, 237 .setup = xchk_setup_agheader, 238 .scrub = xchk_agfl, 239 .repair = xrep_agfl, 240 }, 241 [XFS_SCRUB_TYPE_AGI] = { /* agi */ 242 .type = ST_PERAG, 243 .setup = xchk_setup_agheader, 244 .scrub = xchk_agi, 245 .repair = xrep_agi, 246 }, 247 [XFS_SCRUB_TYPE_BNOBT] = { /* bnobt */ 248 .type = ST_PERAG, 249 .setup = xchk_setup_ag_allocbt, 250 .scrub = xchk_allocbt, 251 .repair = xrep_allocbt, 252 .repair_eval = xrep_revalidate_allocbt, 253 }, 254 [XFS_SCRUB_TYPE_CNTBT] = { /* cntbt */ 255 .type = ST_PERAG, 256 .setup = xchk_setup_ag_allocbt, 257 .scrub = xchk_allocbt, 258 .repair = xrep_allocbt, 259 .repair_eval = xrep_revalidate_allocbt, 260 }, 261 [XFS_SCRUB_TYPE_INOBT] = { /* inobt */ 262 .type = ST_PERAG, 263 .setup = xchk_setup_ag_iallocbt, 264 .scrub = xchk_iallocbt, 265 .repair = xrep_iallocbt, 266 .repair_eval = xrep_revalidate_iallocbt, 267 }, 268 [XFS_SCRUB_TYPE_FINOBT] = { /* finobt */ 269 .type = ST_PERAG, 270 .setup = xchk_setup_ag_iallocbt, 271 .scrub = xchk_iallocbt, 272 .has = xfs_has_finobt, 273 .repair = xrep_iallocbt, 274 .repair_eval = xrep_revalidate_iallocbt, 275 }, 276 [XFS_SCRUB_TYPE_RMAPBT] = { /* rmapbt */ 277 .type = ST_PERAG, 278 .setup = xchk_setup_ag_rmapbt, 279 .scrub = xchk_rmapbt, 280 .has = xfs_has_rmapbt, 281 .repair = xrep_notsupported, 282 }, 283 [XFS_SCRUB_TYPE_REFCNTBT] = { /* refcountbt */ 284 .type = ST_PERAG, 285 .setup = xchk_setup_ag_refcountbt, 286 .scrub = xchk_refcountbt, 287 .has = xfs_has_reflink, 288 .repair = xrep_refcountbt, 289 }, 290 [XFS_SCRUB_TYPE_INODE] = { /* inode record */ 291 .type = ST_INODE, 292 .setup = xchk_setup_inode, 293 .scrub = xchk_inode, 294 .repair = xrep_inode, 295 }, 296 [XFS_SCRUB_TYPE_BMBTD] = { /* inode data fork */ 297 .type = ST_INODE, 298 .setup = xchk_setup_inode_bmap, 299 .scrub = xchk_bmap_data, 300 .repair = xrep_bmap_data, 301 }, 302 [XFS_SCRUB_TYPE_BMBTA] = { /* inode attr fork */ 303 .type = ST_INODE, 304 .setup = xchk_setup_inode_bmap, 305 .scrub = xchk_bmap_attr, 306 .repair = xrep_bmap_attr, 307 }, 308 [XFS_SCRUB_TYPE_BMBTC] = { /* inode CoW fork */ 309 .type = ST_INODE, 310 .setup = xchk_setup_inode_bmap, 311 .scrub = xchk_bmap_cow, 312 .repair = xrep_bmap_cow, 313 }, 314 [XFS_SCRUB_TYPE_DIR] = { /* directory */ 315 .type = ST_INODE, 316 .setup = xchk_setup_directory, 317 .scrub = xchk_directory, 318 .repair = xrep_notsupported, 319 }, 320 [XFS_SCRUB_TYPE_XATTR] = { /* extended attributes */ 321 .type = ST_INODE, 322 .setup = xchk_setup_xattr, 323 .scrub = xchk_xattr, 324 .repair = xrep_notsupported, 325 }, 326 [XFS_SCRUB_TYPE_SYMLINK] = { /* symbolic link */ 327 .type = ST_INODE, 328 .setup = xchk_setup_symlink, 329 .scrub = xchk_symlink, 330 .repair = xrep_notsupported, 331 }, 332 [XFS_SCRUB_TYPE_PARENT] = { /* parent pointers */ 333 .type = ST_INODE, 334 .setup = xchk_setup_parent, 335 .scrub = xchk_parent, 336 .repair = xrep_notsupported, 337 }, 338 [XFS_SCRUB_TYPE_RTBITMAP] = { /* realtime bitmap */ 339 .type = ST_FS, 340 .setup = xchk_setup_rtbitmap, 341 .scrub = xchk_rtbitmap, 342 .repair = xrep_rtbitmap, 343 }, 344 [XFS_SCRUB_TYPE_RTSUM] = { /* realtime summary */ 345 .type = ST_FS, 346 .setup = xchk_setup_rtsummary, 347 .scrub = xchk_rtsummary, 348 .repair = xrep_notsupported, 349 }, 350 [XFS_SCRUB_TYPE_UQUOTA] = { /* user quota */ 351 .type = ST_FS, 352 .setup = xchk_setup_quota, 353 .scrub = xchk_quota, 354 .repair = xrep_quota, 355 }, 356 [XFS_SCRUB_TYPE_GQUOTA] = { /* group quota */ 357 .type = ST_FS, 358 .setup = xchk_setup_quota, 359 .scrub = xchk_quota, 360 .repair = xrep_quota, 361 }, 362 [XFS_SCRUB_TYPE_PQUOTA] = { /* project quota */ 363 .type = ST_FS, 364 .setup = xchk_setup_quota, 365 .scrub = xchk_quota, 366 .repair = xrep_quota, 367 }, 368 [XFS_SCRUB_TYPE_FSCOUNTERS] = { /* fs summary counters */ 369 .type = ST_FS, 370 .setup = xchk_setup_fscounters, 371 .scrub = xchk_fscounters, 372 .repair = xrep_fscounters, 373 }, 374 [XFS_SCRUB_TYPE_QUOTACHECK] = { /* quota counters */ 375 .type = ST_FS, 376 .setup = xchk_setup_quotacheck, 377 .scrub = xchk_quotacheck, 378 .repair = xrep_quotacheck, 379 }, 380 [XFS_SCRUB_TYPE_NLINKS] = { /* inode link counts */ 381 .type = ST_FS, 382 .setup = xchk_setup_nlinks, 383 .scrub = xchk_nlinks, 384 .repair = xrep_nlinks, 385 }, 386 [XFS_SCRUB_TYPE_HEALTHY] = { /* fs healthy; clean all reminders */ 387 .type = ST_FS, 388 .setup = xchk_setup_fs, 389 .scrub = xchk_health_record, 390 .repair = xrep_notsupported, 391 }, 392 }; 393 394 static int 395 xchk_validate_inputs( 396 struct xfs_mount *mp, 397 struct xfs_scrub_metadata *sm) 398 { 399 int error; 400 const struct xchk_meta_ops *ops; 401 402 error = -EINVAL; 403 /* Check our inputs. */ 404 sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; 405 if (sm->sm_flags & ~XFS_SCRUB_FLAGS_IN) 406 goto out; 407 /* sm_reserved[] must be zero */ 408 if (memchr_inv(sm->sm_reserved, 0, sizeof(sm->sm_reserved))) 409 goto out; 410 411 error = -ENOENT; 412 /* Do we know about this type of metadata? */ 413 if (sm->sm_type >= XFS_SCRUB_TYPE_NR) 414 goto out; 415 ops = &meta_scrub_ops[sm->sm_type]; 416 if (ops->setup == NULL || ops->scrub == NULL) 417 goto out; 418 /* Does this fs even support this type of metadata? */ 419 if (ops->has && !ops->has(mp)) 420 goto out; 421 422 error = -EINVAL; 423 /* restricting fields must be appropriate for type */ 424 switch (ops->type) { 425 case ST_NONE: 426 case ST_FS: 427 if (sm->sm_ino || sm->sm_gen || sm->sm_agno) 428 goto out; 429 break; 430 case ST_PERAG: 431 if (sm->sm_ino || sm->sm_gen || 432 sm->sm_agno >= mp->m_sb.sb_agcount) 433 goto out; 434 break; 435 case ST_INODE: 436 if (sm->sm_agno || (sm->sm_gen && !sm->sm_ino)) 437 goto out; 438 break; 439 default: 440 goto out; 441 } 442 443 /* No rebuild without repair. */ 444 if ((sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) && 445 !(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) 446 return -EINVAL; 447 448 /* 449 * We only want to repair read-write v5+ filesystems. Defer the check 450 * for ops->repair until after our scrub confirms that we need to 451 * perform repairs so that we avoid failing due to not supporting 452 * repairing an object that doesn't need repairs. 453 */ 454 if (sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) { 455 error = -EOPNOTSUPP; 456 if (!xfs_has_crc(mp)) 457 goto out; 458 459 error = -EROFS; 460 if (xfs_is_readonly(mp)) 461 goto out; 462 } 463 464 error = 0; 465 out: 466 return error; 467 } 468 469 #ifdef CONFIG_XFS_ONLINE_REPAIR 470 static inline void xchk_postmortem(struct xfs_scrub *sc) 471 { 472 /* 473 * Userspace asked us to repair something, we repaired it, rescanned 474 * it, and the rescan says it's still broken. Scream about this in 475 * the system logs. 476 */ 477 if ((sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) && 478 (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT | 479 XFS_SCRUB_OFLAG_XCORRUPT))) 480 xrep_failure(sc->mp); 481 } 482 #else 483 static inline void xchk_postmortem(struct xfs_scrub *sc) 484 { 485 /* 486 * Userspace asked us to scrub something, it's broken, and we have no 487 * way of fixing it. Scream in the logs. 488 */ 489 if (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT | 490 XFS_SCRUB_OFLAG_XCORRUPT)) 491 xfs_alert_ratelimited(sc->mp, 492 "Corruption detected during scrub."); 493 } 494 #endif /* CONFIG_XFS_ONLINE_REPAIR */ 495 496 /* Dispatch metadata scrubbing. */ 497 int 498 xfs_scrub_metadata( 499 struct file *file, 500 struct xfs_scrub_metadata *sm) 501 { 502 struct xchk_stats_run run = { }; 503 struct xfs_scrub *sc; 504 struct xfs_mount *mp = XFS_I(file_inode(file))->i_mount; 505 u64 check_start; 506 int error = 0; 507 508 BUILD_BUG_ON(sizeof(meta_scrub_ops) != 509 (sizeof(struct xchk_meta_ops) * XFS_SCRUB_TYPE_NR)); 510 511 trace_xchk_start(XFS_I(file_inode(file)), sm, error); 512 513 /* Forbidden if we are shut down or mounted norecovery. */ 514 error = -ESHUTDOWN; 515 if (xfs_is_shutdown(mp)) 516 goto out; 517 error = -ENOTRECOVERABLE; 518 if (xfs_has_norecovery(mp)) 519 goto out; 520 521 error = xchk_validate_inputs(mp, sm); 522 if (error) 523 goto out; 524 525 xfs_warn_mount(mp, XFS_OPSTATE_WARNED_SCRUB, 526 "EXPERIMENTAL online scrub feature in use. Use at your own risk!"); 527 528 sc = kzalloc(sizeof(struct xfs_scrub), XCHK_GFP_FLAGS); 529 if (!sc) { 530 error = -ENOMEM; 531 goto out; 532 } 533 534 sc->mp = mp; 535 sc->file = file; 536 sc->sm = sm; 537 sc->ops = &meta_scrub_ops[sm->sm_type]; 538 sc->sick_mask = xchk_health_mask_for_scrub_type(sm->sm_type); 539 retry_op: 540 /* 541 * When repairs are allowed, prevent freezing or readonly remount while 542 * scrub is running with a real transaction. 543 */ 544 if (sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) { 545 error = mnt_want_write_file(sc->file); 546 if (error) 547 goto out_sc; 548 549 sc->flags |= XCHK_HAVE_FREEZE_PROT; 550 } 551 552 /* Set up for the operation. */ 553 error = sc->ops->setup(sc); 554 if (error == -EDEADLOCK && !(sc->flags & XCHK_TRY_HARDER)) 555 goto try_harder; 556 if (error == -ECHRNG && !(sc->flags & XCHK_NEED_DRAIN)) 557 goto need_drain; 558 if (error) 559 goto out_teardown; 560 561 /* Scrub for errors. */ 562 check_start = xchk_stats_now(); 563 if ((sc->flags & XREP_ALREADY_FIXED) && sc->ops->repair_eval != NULL) 564 error = sc->ops->repair_eval(sc); 565 else 566 error = sc->ops->scrub(sc); 567 run.scrub_ns += xchk_stats_elapsed_ns(check_start); 568 if (error == -EDEADLOCK && !(sc->flags & XCHK_TRY_HARDER)) 569 goto try_harder; 570 if (error == -ECHRNG && !(sc->flags & XCHK_NEED_DRAIN)) 571 goto need_drain; 572 if (error || (sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)) 573 goto out_teardown; 574 575 xchk_update_health(sc); 576 577 if (xchk_could_repair(sc)) { 578 /* 579 * If userspace asked for a repair but it wasn't necessary, 580 * report that back to userspace. 581 */ 582 if (!xrep_will_attempt(sc)) { 583 sc->sm->sm_flags |= XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED; 584 goto out_nofix; 585 } 586 587 /* 588 * If it's broken, userspace wants us to fix it, and we haven't 589 * already tried to fix it, then attempt a repair. 590 */ 591 error = xrep_attempt(sc, &run); 592 if (error == -EAGAIN) { 593 /* 594 * Either the repair function succeeded or it couldn't 595 * get all the resources it needs; either way, we go 596 * back to the beginning and call the scrub function. 597 */ 598 error = xchk_teardown(sc, 0); 599 if (error) { 600 xrep_failure(mp); 601 goto out_sc; 602 } 603 goto retry_op; 604 } 605 } 606 607 out_nofix: 608 xchk_postmortem(sc); 609 out_teardown: 610 error = xchk_teardown(sc, error); 611 out_sc: 612 if (error != -ENOENT) 613 xchk_stats_merge(mp, sm, &run); 614 kfree(sc); 615 out: 616 trace_xchk_done(XFS_I(file_inode(file)), sm, error); 617 if (error == -EFSCORRUPTED || error == -EFSBADCRC) { 618 sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; 619 error = 0; 620 } 621 return error; 622 need_drain: 623 error = xchk_teardown(sc, 0); 624 if (error) 625 goto out_sc; 626 sc->flags |= XCHK_NEED_DRAIN; 627 run.retries++; 628 goto retry_op; 629 try_harder: 630 /* 631 * Scrubbers return -EDEADLOCK to mean 'try harder'. Tear down 632 * everything we hold, then set up again with preparation for 633 * worst-case scenarios. 634 */ 635 error = xchk_teardown(sc, 0); 636 if (error) 637 goto out_sc; 638 sc->flags |= XCHK_TRY_HARDER; 639 run.retries++; 640 goto retry_op; 641 } 642