mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-29 04:41:21 -04:00
Merge tag 'scrub-fscounters-enhancements-6.2_2022-11-16' of git://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.2-mergeA
xfs: enhance fs summary counter scrubber This series makes two changes to the fs summary counter scrubber: first, we should mark the scrub incomplete when we can't read the AG headers. Second, it fixes a functionality gap where we don't actually check the free rt extent count. v23.2: fix pointless inline Signed-off-by: Darrick J. Wong <djwong@kernel.org> * tag 'scrub-fscounters-enhancements-6.2_2022-11-16' of git://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux: xfs: online checking of the free rt extent count xfs: skip fscounters comparisons when the scan is incomplete
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -138,6 +151,18 @@ xchk_setup_fscounters(
|
||||
return xchk_trans_alloc(sc, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Part 1: Collecting filesystem summary counts. For each AG, we add its
|
||||
* summary counts (total inodes, free inodes, free data blocks) to an incore
|
||||
* copy of the overall filesystem summary counts.
|
||||
*
|
||||
* To avoid false corruption reports in part 2, any failure in this part must
|
||||
* set the INCOMPLETE flag even when a negative errno is returned. This care
|
||||
* must be taken with certain errno values (i.e. EFSBADCRC, EFSCORRUPTED,
|
||||
* ECANCELED) that are absorbed into a scrub state flag update by
|
||||
* xchk_*_process_error.
|
||||
*/
|
||||
|
||||
/* Count free space btree blocks manually for pre-lazysbcount filesystems. */
|
||||
static int
|
||||
xchk_fscount_btreeblks(
|
||||
@@ -225,8 +250,10 @@ xchk_fscount_aggregate_agcounts(
|
||||
}
|
||||
if (pag)
|
||||
xfs_perag_put(pag);
|
||||
if (error)
|
||||
if (error) {
|
||||
xchk_set_incomplete(sc);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* The global incore space reservation is taken from the incore
|
||||
@@ -267,6 +294,64 @@ xchk_fscount_aggregate_agcounts(
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Is the @counter reasonably close to the @expected value?
|
||||
*
|
||||
@@ -333,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. */
|
||||
@@ -353,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.
|
||||
@@ -367,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);
|
||||
@@ -378,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__ */
|
||||
|
||||
Reference in New Issue
Block a user