diff options
-rw-r--r-- | fs/xfs/scrub/fscounters.c | 72 |
1 files changed, 48 insertions, 24 deletions
diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c index 5761fa94964a..9d3edd931f5a 100644 --- a/fs/xfs/scrub/fscounters.c +++ b/fs/xfs/scrub/fscounters.c @@ -133,9 +133,16 @@ xchk_setup_fscounters( /* * Pause background reclaim while we're scrubbing to reduce the * likelihood of background perturbations to the counters throwing off - * our calculations. + * our calculations. If a previous check failed and userspace told us + * to freeze the fs, do that instead. */ - xchk_stop_reaping(sc); + if (sc->flags & XCHK_TRY_HARDER) { + error = xchk_fs_freeze(sc); + if (error) + return error; + } else { + xchk_stop_reaping(sc); + } return xchk_trans_alloc(sc, 0); } @@ -262,8 +269,7 @@ retry: if (fsc->ifree > fsc->icount) { if (tries--) goto retry; - xchk_set_incomplete(sc); - return 0; + return -EDEADLOCK; } return 0; @@ -311,8 +317,12 @@ xchk_fscount_check_frextents( trace_xchk_fscounters_frextents_within_range(sc->mp, fsc->frextents, mp->m_sb.sb_frextents); - if (fsc->frextents != mp->m_sb.sb_frextents) - xchk_set_corrupt(sc); + if (fsc->frextents != mp->m_sb.sb_frextents) { + if (sc->flags & XCHK_FS_FROZEN) + xchk_set_corrupt(sc); + else + error = -EDEADLOCK; + } spin_unlock(&mp->m_sb_lock); out_unlock: @@ -379,16 +389,9 @@ xchk_fscount_within_range( * If the difference between the two summations is too large, the fs * might just be busy and so we'll mark the scrub incomplete. Return * true here so that we don't mark the counter corrupt. - * - * XXX: In the future when userspace can grant scrub permission to - * quiesce the filesystem to solve the outsized variance problem, this - * check should be moved up and the return code changed to signal to - * userspace that we need quiesce permission. */ - if (max_value - min_value >= XCHK_FSCOUNT_MIN_VARIANCE) { - xchk_set_incomplete(sc); - return true; - } + if (max_value - min_value >= XCHK_FSCOUNT_MIN_VARIANCE) + return false; return false; } @@ -401,6 +404,8 @@ xchk_fscounters( struct xfs_mount *mp = sc->mp; struct xchk_fscounters *fsc = sc->buf; int64_t icount, ifree, fdblocks; + bool frozen = sc->flags & XCHK_FS_FROZEN; + bool try_again = false; int error; /* Snapshot the percpu counters. */ @@ -431,19 +436,38 @@ xchk_fscounters( error = xchk_fscount_aggregate_agcounts(sc, fsc); if (!xchk_process_error(sc, 0, XFS_SB_BLOCK(mp), &error)) return error; - if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) - return 0; - /* Compare the in-core counters with whatever we counted. */ - if (!xchk_fscount_within_range(sc, icount, &mp->m_icount, fsc->icount)) - xchk_set_corrupt(sc); + /* + * Compare the in-core counters with whatever we counted. If the fs is + * frozen, we treat the discrepancy as a corruption because the freeze + * should have stabilized the counter values. Otherwise, we need + * userspace to call us back having granted us freeze permission. + */ + if (!xchk_fscount_within_range(sc, icount, &mp->m_icount, + fsc->icount)) { + if (frozen) + xchk_set_corrupt(sc); + else + try_again = true; + } - if (!xchk_fscount_within_range(sc, ifree, &mp->m_ifree, fsc->ifree)) - xchk_set_corrupt(sc); + if (!xchk_fscount_within_range(sc, ifree, &mp->m_ifree, fsc->ifree)) { + if (frozen) + xchk_set_corrupt(sc); + else + try_again = true; + } if (!xchk_fscount_within_range(sc, fdblocks, &mp->m_fdblocks, - fsc->fdblocks)) - xchk_set_corrupt(sc); + fsc->fdblocks)) { + if (frozen) + xchk_set_corrupt(sc); + else + try_again = true; + } + + if (try_again) + return -EDEADLOCK; /* Check the free extents counter for rt volumes. */ error = xchk_fscount_check_frextents(sc, fsc); |