| .. | .. |
|---|
| 9 | 9 | #include "xfs_format.h" |
|---|
| 10 | 10 | #include "xfs_trans_resv.h" |
|---|
| 11 | 11 | #include "xfs_mount.h" |
|---|
| 12 | | -#include "xfs_defer.h" |
|---|
| 13 | | -#include "xfs_btree.h" |
|---|
| 14 | | -#include "xfs_bit.h" |
|---|
| 15 | 12 | #include "xfs_log_format.h" |
|---|
| 16 | 13 | #include "xfs_trans.h" |
|---|
| 17 | | -#include "xfs_sb.h" |
|---|
| 18 | 14 | #include "xfs_inode.h" |
|---|
| 19 | | -#include "xfs_icache.h" |
|---|
| 20 | | -#include "xfs_itable.h" |
|---|
| 21 | | -#include "xfs_alloc.h" |
|---|
| 22 | | -#include "xfs_alloc_btree.h" |
|---|
| 23 | | -#include "xfs_bmap.h" |
|---|
| 24 | | -#include "xfs_bmap_btree.h" |
|---|
| 25 | | -#include "xfs_ialloc.h" |
|---|
| 26 | | -#include "xfs_ialloc_btree.h" |
|---|
| 27 | | -#include "xfs_refcount.h" |
|---|
| 28 | | -#include "xfs_refcount_btree.h" |
|---|
| 29 | | -#include "xfs_rmap.h" |
|---|
| 30 | | -#include "xfs_rmap_btree.h" |
|---|
| 31 | 15 | #include "xfs_quota.h" |
|---|
| 32 | 16 | #include "xfs_qm.h" |
|---|
| 33 | 17 | #include "xfs_errortag.h" |
|---|
| 34 | 18 | #include "xfs_error.h" |
|---|
| 35 | | -#include "xfs_log.h" |
|---|
| 36 | | -#include "xfs_trans_priv.h" |
|---|
| 37 | | -#include "scrub/xfs_scrub.h" |
|---|
| 19 | +#include "xfs_scrub.h" |
|---|
| 38 | 20 | #include "scrub/scrub.h" |
|---|
| 39 | 21 | #include "scrub/common.h" |
|---|
| 40 | 22 | #include "scrub/trace.h" |
|---|
| 41 | | -#include "scrub/btree.h" |
|---|
| 42 | 23 | #include "scrub/repair.h" |
|---|
| 24 | +#include "scrub/health.h" |
|---|
| 43 | 25 | |
|---|
| 44 | 26 | /* |
|---|
| 45 | 27 | * Online Scrub and Repair |
|---|
| .. | .. |
|---|
| 186 | 168 | xfs_irele(sc->ip); |
|---|
| 187 | 169 | sc->ip = NULL; |
|---|
| 188 | 170 | } |
|---|
| 189 | | - if (sc->has_quotaofflock) |
|---|
| 171 | + sb_end_write(sc->mp->m_super); |
|---|
| 172 | + if (sc->flags & XCHK_REAPING_DISABLED) |
|---|
| 173 | + xchk_start_reaping(sc); |
|---|
| 174 | + if (sc->flags & XCHK_HAS_QUOTAOFFLOCK) { |
|---|
| 190 | 175 | mutex_unlock(&sc->mp->m_quotainfo->qi_quotaofflock); |
|---|
| 176 | + sc->flags &= ~XCHK_HAS_QUOTAOFFLOCK; |
|---|
| 177 | + } |
|---|
| 191 | 178 | if (sc->buf) { |
|---|
| 192 | 179 | kmem_free(sc->buf); |
|---|
| 193 | 180 | sc->buf = NULL; |
|---|
| .. | .. |
|---|
| 347 | 334 | .scrub = xchk_quota, |
|---|
| 348 | 335 | .repair = xrep_notsupported, |
|---|
| 349 | 336 | }, |
|---|
| 337 | + [XFS_SCRUB_TYPE_FSCOUNTERS] = { /* fs summary counters */ |
|---|
| 338 | + .type = ST_FS, |
|---|
| 339 | + .setup = xchk_setup_fscounters, |
|---|
| 340 | + .scrub = xchk_fscounters, |
|---|
| 341 | + .repair = xrep_notsupported, |
|---|
| 342 | + }, |
|---|
| 350 | 343 | }; |
|---|
| 351 | 344 | |
|---|
| 352 | 345 | /* This isn't a stable feature, warn once per day. */ |
|---|
| .. | .. |
|---|
| 412 | 405 | goto out; |
|---|
| 413 | 406 | } |
|---|
| 414 | 407 | |
|---|
| 415 | | - error = -EOPNOTSUPP; |
|---|
| 416 | | - /* |
|---|
| 417 | | - * We won't scrub any filesystem that doesn't have the ability |
|---|
| 418 | | - * to record unwritten extents. The option was made default in |
|---|
| 419 | | - * 2003, removed from mkfs in 2007, and cannot be disabled in |
|---|
| 420 | | - * v5, so if we find a filesystem without this flag it's either |
|---|
| 421 | | - * really old or totally unsupported. Avoid it either way. |
|---|
| 422 | | - * We also don't support v1-v3 filesystems, which aren't |
|---|
| 423 | | - * mountable. |
|---|
| 424 | | - */ |
|---|
| 425 | | - if (!xfs_sb_version_hasextflgbit(&mp->m_sb)) |
|---|
| 426 | | - goto out; |
|---|
| 427 | | - |
|---|
| 428 | 408 | /* |
|---|
| 429 | 409 | * We only want to repair read-write v5+ filesystems. Defer the check |
|---|
| 430 | 410 | * for ops->repair until after our scrub confirms that we need to |
|---|
| .. | .. |
|---|
| 479 | 459 | struct xfs_inode *ip, |
|---|
| 480 | 460 | struct xfs_scrub_metadata *sm) |
|---|
| 481 | 461 | { |
|---|
| 482 | | - struct xfs_scrub sc; |
|---|
| 462 | + struct xfs_scrub sc = { |
|---|
| 463 | + .mp = ip->i_mount, |
|---|
| 464 | + .sm = sm, |
|---|
| 465 | + .sa = { |
|---|
| 466 | + .agno = NULLAGNUMBER, |
|---|
| 467 | + }, |
|---|
| 468 | + }; |
|---|
| 483 | 469 | struct xfs_mount *mp = ip->i_mount; |
|---|
| 484 | | - bool try_harder = false; |
|---|
| 485 | | - bool already_fixed = false; |
|---|
| 486 | 470 | int error = 0; |
|---|
| 487 | 471 | |
|---|
| 488 | 472 | BUILD_BUG_ON(sizeof(meta_scrub_ops) != |
|---|
| .. | .. |
|---|
| 504 | 488 | |
|---|
| 505 | 489 | xchk_experimental_warning(mp); |
|---|
| 506 | 490 | |
|---|
| 507 | | -retry_op: |
|---|
| 508 | | - /* Set up for the operation. */ |
|---|
| 509 | | - memset(&sc, 0, sizeof(sc)); |
|---|
| 510 | | - sc.mp = ip->i_mount; |
|---|
| 511 | | - sc.sm = sm; |
|---|
| 512 | 491 | sc.ops = &meta_scrub_ops[sm->sm_type]; |
|---|
| 513 | | - sc.try_harder = try_harder; |
|---|
| 514 | | - sc.sa.agno = NULLAGNUMBER; |
|---|
| 492 | + sc.sick_mask = xchk_health_mask_for_scrub_type(sm->sm_type); |
|---|
| 493 | +retry_op: |
|---|
| 494 | + /* |
|---|
| 495 | + * If freeze runs concurrently with a scrub, the freeze can be delayed |
|---|
| 496 | + * indefinitely as we walk the filesystem and iterate over metadata |
|---|
| 497 | + * buffers. Freeze quiesces the log (which waits for the buffer LRU to |
|---|
| 498 | + * be emptied) and that won't happen while checking is running. |
|---|
| 499 | + */ |
|---|
| 500 | + sb_start_write(mp->m_super); |
|---|
| 501 | + |
|---|
| 502 | + /* Set up for the operation. */ |
|---|
| 515 | 503 | error = sc.ops->setup(&sc, ip); |
|---|
| 516 | 504 | if (error) |
|---|
| 517 | 505 | goto out_teardown; |
|---|
| 518 | 506 | |
|---|
| 519 | 507 | /* Scrub for errors. */ |
|---|
| 520 | 508 | error = sc.ops->scrub(&sc); |
|---|
| 521 | | - if (!try_harder && error == -EDEADLOCK) { |
|---|
| 509 | + if (!(sc.flags & XCHK_TRY_HARDER) && error == -EDEADLOCK) { |
|---|
| 522 | 510 | /* |
|---|
| 523 | 511 | * Scrubbers return -EDEADLOCK to mean 'try harder'. |
|---|
| 524 | 512 | * Tear down everything we hold, then set up again with |
|---|
| .. | .. |
|---|
| 527 | 515 | error = xchk_teardown(&sc, ip, 0); |
|---|
| 528 | 516 | if (error) |
|---|
| 529 | 517 | goto out; |
|---|
| 530 | | - try_harder = true; |
|---|
| 518 | + sc.flags |= XCHK_TRY_HARDER; |
|---|
| 531 | 519 | goto retry_op; |
|---|
| 532 | 520 | } else if (error) |
|---|
| 533 | 521 | goto out_teardown; |
|---|
| 534 | 522 | |
|---|
| 535 | | - if ((sc.sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) && !already_fixed) { |
|---|
| 523 | + xchk_update_health(&sc); |
|---|
| 524 | + |
|---|
| 525 | + if ((sc.sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) && |
|---|
| 526 | + !(sc.flags & XREP_ALREADY_FIXED)) { |
|---|
| 536 | 527 | bool needs_fix; |
|---|
| 537 | 528 | |
|---|
| 538 | 529 | /* Let debug users force us into the repair routines. */ |
|---|
| .. | .. |
|---|
| 555 | 546 | * If it's broken, userspace wants us to fix it, and we haven't |
|---|
| 556 | 547 | * already tried to fix it, then attempt a repair. |
|---|
| 557 | 548 | */ |
|---|
| 558 | | - error = xrep_attempt(ip, &sc, &already_fixed); |
|---|
| 549 | + error = xrep_attempt(ip, &sc); |
|---|
| 559 | 550 | if (error == -EAGAIN) { |
|---|
| 560 | | - if (sc.try_harder) |
|---|
| 561 | | - try_harder = true; |
|---|
| 551 | + /* |
|---|
| 552 | + * Either the repair function succeeded or it couldn't |
|---|
| 553 | + * get all the resources it needs; either way, we go |
|---|
| 554 | + * back to the beginning and call the scrub function. |
|---|
| 555 | + */ |
|---|
| 562 | 556 | error = xchk_teardown(&sc, ip, 0); |
|---|
| 563 | 557 | if (error) { |
|---|
| 564 | 558 | xrep_failure(mp); |
|---|