xfs: online checking of the free rt extent count
Teach the summary count checker to count the number of free realtime extents and compare that to the superblock copy. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
This commit is contained in:
parent
11f97e6845
commit
e74331d6fa
|
@ -14,6 +14,8 @@
|
|||
#include "xfs_health.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_ag.h"
|
||||
#include "xfs_rtalloc.h"
|
||||
#include "xfs_inode.h"
|
||||
#include "scrub/scrub.h"
|
||||
#include "scrub/common.h"
|
||||
#include "scrub/trace.h"
|
||||
|
@ -43,6 +45,16 @@
|
|||
* our tolerance for mismatch between expected and actual counter values.
|
||||
*/
|
||||
|
||||
struct xchk_fscounters {
|
||||
struct xfs_scrub *sc;
|
||||
uint64_t icount;
|
||||
uint64_t ifree;
|
||||
uint64_t fdblocks;
|
||||
uint64_t frextents;
|
||||
unsigned long long icount_min;
|
||||
unsigned long long icount_max;
|
||||
};
|
||||
|
||||
/*
|
||||
* Since the expected value computation is lockless but only browses incore
|
||||
* values, the percpu counters should be fairly close to each other. However,
|
||||
|
@ -120,6 +132,7 @@ xchk_setup_fscounters(
|
|||
if (!sc->buf)
|
||||
return -ENOMEM;
|
||||
fsc = sc->buf;
|
||||
fsc->sc = sc;
|
||||
|
||||
xfs_icount_range(sc->mp, &fsc->icount_min, &fsc->icount_max);
|
||||
|
||||
|
@ -281,6 +294,59 @@ retry:
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XFS_RT
|
||||
STATIC int
|
||||
xchk_fscount_add_frextent(
|
||||
struct xfs_mount *mp,
|
||||
struct xfs_trans *tp,
|
||||
const struct xfs_rtalloc_rec *rec,
|
||||
void *priv)
|
||||
{
|
||||
struct xchk_fscounters *fsc = priv;
|
||||
int error = 0;
|
||||
|
||||
fsc->frextents += rec->ar_extcount;
|
||||
|
||||
xchk_should_terminate(fsc->sc, &error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Calculate the number of free realtime extents from the realtime bitmap. */
|
||||
STATIC int
|
||||
xchk_fscount_count_frextents(
|
||||
struct xfs_scrub *sc,
|
||||
struct xchk_fscounters *fsc)
|
||||
{
|
||||
struct xfs_mount *mp = sc->mp;
|
||||
int error;
|
||||
|
||||
fsc->frextents = 0;
|
||||
if (!xfs_has_realtime(mp))
|
||||
return 0;
|
||||
|
||||
xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
|
||||
error = xfs_rtalloc_query_all(sc->mp, sc->tp,
|
||||
xchk_fscount_add_frextent, fsc);
|
||||
if (error) {
|
||||
xchk_set_incomplete(sc);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
|
||||
return error;
|
||||
}
|
||||
#else
|
||||
STATIC int
|
||||
xchk_fscount_count_frextents(
|
||||
struct xfs_scrub *sc,
|
||||
struct xchk_fscounters *fsc)
|
||||
{
|
||||
fsc->frextents = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
/*
|
||||
* Part 2: Comparing filesystem summary counters. All we have to do here is
|
||||
* sum the percpu counters and compare them to what we've observed.
|
||||
|
@ -352,16 +418,17 @@ xchk_fscounters(
|
|||
{
|
||||
struct xfs_mount *mp = sc->mp;
|
||||
struct xchk_fscounters *fsc = sc->buf;
|
||||
int64_t icount, ifree, fdblocks;
|
||||
int64_t icount, ifree, fdblocks, frextents;
|
||||
int error;
|
||||
|
||||
/* Snapshot the percpu counters. */
|
||||
icount = percpu_counter_sum(&mp->m_icount);
|
||||
ifree = percpu_counter_sum(&mp->m_ifree);
|
||||
fdblocks = percpu_counter_sum(&mp->m_fdblocks);
|
||||
frextents = percpu_counter_sum(&mp->m_frextents);
|
||||
|
||||
/* No negative values, please! */
|
||||
if (icount < 0 || ifree < 0 || fdblocks < 0)
|
||||
if (icount < 0 || ifree < 0 || fdblocks < 0 || frextents < 0)
|
||||
xchk_set_corrupt(sc);
|
||||
|
||||
/* See if icount is obviously wrong. */
|
||||
|
@ -372,6 +439,10 @@ xchk_fscounters(
|
|||
if (fdblocks > mp->m_sb.sb_dblocks)
|
||||
xchk_set_corrupt(sc);
|
||||
|
||||
/* See if frextents is obviously wrong. */
|
||||
if (frextents > mp->m_sb.sb_rextents)
|
||||
xchk_set_corrupt(sc);
|
||||
|
||||
/*
|
||||
* If ifree exceeds icount by more than the minimum variance then
|
||||
* something's probably wrong with the counters.
|
||||
|
@ -386,6 +457,13 @@ xchk_fscounters(
|
|||
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)
|
||||
return 0;
|
||||
|
||||
/* Count the free extents counter for rt volumes. */
|
||||
error = xchk_fscount_count_frextents(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);
|
||||
|
@ -397,5 +475,9 @@ xchk_fscounters(
|
|||
fsc->fdblocks))
|
||||
xchk_set_corrupt(sc);
|
||||
|
||||
if (!xchk_fscount_within_range(sc, frextents, &mp->m_frextents,
|
||||
fsc->frextents))
|
||||
xchk_set_corrupt(sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -169,12 +169,4 @@ void xchk_xref_is_used_rt_space(struct xfs_scrub *sc, xfs_rtblock_t rtbno,
|
|||
# define xchk_xref_is_used_rt_space(sc, rtbno, len) do { } while (0)
|
||||
#endif
|
||||
|
||||
struct xchk_fscounters {
|
||||
uint64_t icount;
|
||||
uint64_t ifree;
|
||||
uint64_t fdblocks;
|
||||
unsigned long long icount_min;
|
||||
unsigned long long icount_max;
|
||||
};
|
||||
|
||||
#endif /* __XFS_SCRUB_SCRUB_H__ */
|
||||
|
|
Loading…
Reference in New Issue