diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 10:46:49 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-10-22 16:40:41 -0700 |
commit | 56e64bc06b8e46f9f93f04a7ca3bbbbd0f5a519b (patch) | |
tree | dc87d90e4d4236b2a988fe1971984321a9b7306d | |
parent | 4df10bbc938c350114ff81e77affaec3a553ccf7 (diff) |
xfs: repair summary countersrepair-hard-problems_2021-10-22
Use the same summary counter calculation infrastructure to generate new
values for the in-core summary counters. The difference between the
scrubber and the repairer is that the repairer will freeze the fs during
setup, which means that the values should match exactly.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r-- | fs/xfs/Makefile | 1 | ||||
-rw-r--r-- | fs/xfs/scrub/fscounters.c | 20 | ||||
-rw-r--r-- | fs/xfs/scrub/fscounters_repair.c | 63 | ||||
-rw-r--r-- | fs/xfs/scrub/repair.h | 2 | ||||
-rw-r--r-- | fs/xfs/scrub/scrub.c | 2 | ||||
-rw-r--r-- | fs/xfs/scrub/trace.h | 18 |
6 files changed, 99 insertions, 7 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 62462ed164d4..1a86a5730088 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -174,6 +174,7 @@ xfs-y += $(addprefix scrub/, \ alloc_repair.o \ bitmap.o \ bmap_repair.o \ + fscounters_repair.o \ ialloc_repair.o \ inode_repair.o \ refcount_repair.o \ diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c index 9d3edd931f5a..3d81d808464e 100644 --- a/fs/xfs/scrub/fscounters.c +++ b/fs/xfs/scrub/fscounters.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019 Oracle. All Rights Reserved. * Author: Darrick J. Wong <darrick.wong@oracle.com> @@ -43,6 +43,10 @@ * structures as quickly as it can. We snapshot the percpu counters before and * after this operation and use the difference in counter values to guess at * our tolerance for mismatch between expected and actual counter values. + * + * NOTE: If the calling application has permitted us to repair the counters, + * we /must/ prevent all other filesystem activity by freezing it. Since we've + * frozen the filesystem, we can require an exact match. */ /* @@ -135,8 +139,14 @@ xchk_setup_fscounters( * likelihood of background perturbations to the counters throwing off * our calculations. If a previous check failed and userspace told us * to freeze the fs, do that instead. + * + * If we're repairing, we need to prevent any other thread from + * changing the global fs summary counters while we're repairing them. + * This requires the fs to be frozen, which will disable background + * reclaim and purge all inactive inodes. */ - if (sc->flags & XCHK_TRY_HARDER) { + if ((sc->flags & XCHK_TRY_HARDER) || + (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) { error = xchk_fs_freeze(sc); if (error) return error; @@ -356,6 +366,8 @@ xchk_fscount_check_frextents( * Otherwise, we /might/ have a problem. If the change in the summations is * more than we want to tolerate, the filesystem is probably busy and we should * just send back INCOMPLETE and see if userspace will try again. + * + * If we're repairing then we require an exact match. */ static inline bool xchk_fscount_within_range( @@ -378,6 +390,10 @@ xchk_fscount_within_range( if (curr_value == expected) return true; + /* We require exact matches when repair is running. */ + if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) + return false; + min_value = min(old_value, curr_value); max_value = max(old_value, curr_value); diff --git a/fs/xfs/scrub/fscounters_repair.c b/fs/xfs/scrub/fscounters_repair.c new file mode 100644 index 000000000000..1d802fb290b7 --- /dev/null +++ b/fs/xfs/scrub/fscounters_repair.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Oracle. All Rights Reserved. + * Author: Darrick J. Wong <djwong@kernel.org> + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_bit.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_inode.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_rmap.h" +#include "xfs_health.h" +#include "scrub/xfs_scrub.h" +#include "scrub/scrub.h" +#include "scrub/common.h" +#include "scrub/trace.h" +#include "scrub/repair.h" + +/* + * FS Summary Counters + * =================== + * + * We correct errors in the filesystem summary counters by setting them to the + * values computed during the obligatory scrub phase. However, we must be + * careful not to allow any other thread to change the counters while we're + * computing and setting new values. To achieve this, we freeze the + * filesystem for the whole operation if the REPAIR flag is set. The checking + * function is stricter when we've frozen the fs. + */ + +/* + * Reset the superblock counters. Caller is responsible for freezing the + * filesystem during the calculation and reset phases. + */ +int +xrep_fscounters( + struct xfs_scrub *sc) +{ + struct xfs_mount *mp = sc->mp; + struct xchk_fscounters *fsc = sc->buf; + + /* + * Reinitialize the in-core counters from what we computed. We froze + * the filesystem, so there shouldn't be anyone else trying to modify + * these counters. + */ + ASSERT(sc->flags & XCHK_FS_FROZEN); + percpu_counter_set(&mp->m_icount, fsc->icount); + percpu_counter_set(&mp->m_ifree, fsc->ifree); + percpu_counter_set(&mp->m_fdblocks, fsc->fdblocks); + + return 0; +} diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h index b8e36bbfb6b5..6a8b85dd71be 100644 --- a/fs/xfs/scrub/repair.h +++ b/fs/xfs/scrub/repair.h @@ -97,6 +97,7 @@ int xrep_inode(struct xfs_scrub *sc); int xrep_bmap_data(struct xfs_scrub *sc); int xrep_bmap_attr(struct xfs_scrub *sc); int xrep_symlink(struct xfs_scrub *sc); +int xrep_fscounters(struct xfs_scrub *sc); #ifdef CONFIG_XFS_QUOTA int xrep_quota(struct xfs_scrub *sc); @@ -226,6 +227,7 @@ xrep_setup_ag_rmapbt( #define xrep_symlink xrep_notsupported #define xrep_quota xrep_notsupported #define xrep_quotacheck xrep_notsupported +#define xrep_fscounters xrep_notsupported #endif /* CONFIG_XFS_ONLINE_REPAIR */ diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c index 612d8024eb8e..29d1ae5476e5 100644 --- a/fs/xfs/scrub/scrub.c +++ b/fs/xfs/scrub/scrub.c @@ -352,7 +352,7 @@ static const struct xchk_meta_ops meta_scrub_ops[] = { .type = ST_FS, .setup = xchk_setup_fscounters, .scrub = xchk_fscounters, - .repair = xrep_notsupported, + .repair = xrep_fscounters, }, [XFS_SCRUB_TYPE_QUOTACHECK] = { /* quota counters */ .type = ST_FS, diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h index c52720da103f..f188e17cac49 100644 --- a/fs/xfs/scrub/trace.h +++ b/fs/xfs/scrub/trace.h @@ -1226,16 +1226,26 @@ TRACE_EVENT(xrep_calc_ag_resblks_btsize, __entry->refcbt_sz) ) TRACE_EVENT(xrep_reset_counters, - TP_PROTO(struct xfs_mount *mp), - TP_ARGS(mp), + TP_PROTO(struct xfs_mount *mp, int64_t icount_adj, int64_t ifree_adj, + int64_t fdblocks_adj), + TP_ARGS(mp, icount_adj, ifree_adj, fdblocks_adj), TP_STRUCT__entry( __field(dev_t, dev) + __field(int64_t, icount_adj) + __field(int64_t, ifree_adj) + __field(int64_t, fdblocks_adj) ), TP_fast_assign( __entry->dev = mp->m_super->s_dev; + __entry->icount_adj = icount_adj; + __entry->ifree_adj = ifree_adj; + __entry->fdblocks_adj = fdblocks_adj; ), - TP_printk("dev %d:%d", - MAJOR(__entry->dev), MINOR(__entry->dev)) + TP_printk("dev %d:%d icount %lld ifree %lld fdblocks %lld", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->icount_adj, + __entry->ifree_adj, + __entry->fdblocks_adj) ) DECLARE_EVENT_CLASS(xrep_newbt_extent_class, |