Skip to content

Commit 4ed080c

Browse files
author
Darrick J. Wong
committed
xfs: repair summary counters
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> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent a1f3e0c commit 4ed080c

8 files changed

Lines changed: 128 additions & 18 deletions

File tree

fs/xfs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ xfs-y += $(addprefix scrub/, \
191191
alloc_repair.o \
192192
bmap_repair.o \
193193
cow_repair.o \
194+
fscounters_repair.o \
194195
ialloc_repair.o \
195196
inode_repair.o \
196197
newbt.o \

fs/xfs/scrub/fscounters.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "scrub/scrub.h"
2323
#include "scrub/common.h"
2424
#include "scrub/trace.h"
25+
#include "scrub/fscounters.h"
2526

2627
/*
2728
* FS Summary Counters
@@ -48,17 +49,6 @@
4849
* our tolerance for mismatch between expected and actual counter values.
4950
*/
5051

51-
struct xchk_fscounters {
52-
struct xfs_scrub *sc;
53-
uint64_t icount;
54-
uint64_t ifree;
55-
uint64_t fdblocks;
56-
uint64_t frextents;
57-
unsigned long long icount_min;
58-
unsigned long long icount_max;
59-
bool frozen;
60-
};
61-
6252
/*
6353
* Since the expected value computation is lockless but only browses incore
6454
* values, the percpu counters should be fairly close to each other. However,
@@ -235,8 +225,13 @@ xchk_setup_fscounters(
235225
* Pause all writer activity in the filesystem while we're scrubbing to
236226
* reduce the likelihood of background perturbations to the counters
237227
* throwing off our calculations.
228+
*
229+
* If we're repairing, we need to prevent any other thread from
230+
* changing the global fs summary counters while we're repairing them.
231+
* This requires the fs to be frozen, which will disable background
232+
* reclaim and purge all inactive inodes.
238233
*/
239-
if (sc->flags & XCHK_TRY_HARDER) {
234+
if ((sc->flags & XCHK_TRY_HARDER) || xchk_could_repair(sc)) {
240235
error = xchk_fscounters_freeze(sc);
241236
if (error)
242237
return error;
@@ -254,7 +249,9 @@ xchk_setup_fscounters(
254249
* set the INCOMPLETE flag even when a negative errno is returned. This care
255250
* must be taken with certain errno values (i.e. EFSBADCRC, EFSCORRUPTED,
256251
* ECANCELED) that are absorbed into a scrub state flag update by
257-
* xchk_*_process_error.
252+
* xchk_*_process_error. Scrub and repair share the same incore data
253+
* structures, so the INCOMPLETE flag is critical to prevent a repair based on
254+
* insufficient information.
258255
*/
259256

260257
/* Count free space btree blocks manually for pre-lazysbcount filesystems. */
@@ -482,6 +479,10 @@ xchk_fscount_within_range(
482479
if (curr_value == expected)
483480
return true;
484481

482+
/* We require exact matches when repair is running. */
483+
if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)
484+
return false;
485+
485486
min_value = min(old_value, curr_value);
486487
max_value = max(old_value, curr_value);
487488

fs/xfs/scrub/fscounters.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright (c) 2021-2024 Oracle. All Rights Reserved.
4+
* Author: Darrick J. Wong <djwong@kernel.org>
5+
*/
6+
#ifndef __XFS_SCRUB_FSCOUNTERS_H__
7+
#define __XFS_SCRUB_FSCOUNTERS_H__
8+
9+
struct xchk_fscounters {
10+
struct xfs_scrub *sc;
11+
uint64_t icount;
12+
uint64_t ifree;
13+
uint64_t fdblocks;
14+
uint64_t frextents;
15+
unsigned long long icount_min;
16+
unsigned long long icount_max;
17+
bool frozen;
18+
};
19+
20+
#endif /* __XFS_SCRUB_FSCOUNTERS_H__ */

fs/xfs/scrub/fscounters_repair.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2018-2024 Oracle. All Rights Reserved.
4+
* Author: Darrick J. Wong <djwong@kernel.org>
5+
*/
6+
#include "xfs.h"
7+
#include "xfs_fs.h"
8+
#include "xfs_shared.h"
9+
#include "xfs_format.h"
10+
#include "xfs_trans_resv.h"
11+
#include "xfs_mount.h"
12+
#include "xfs_defer.h"
13+
#include "xfs_btree.h"
14+
#include "xfs_bit.h"
15+
#include "xfs_log_format.h"
16+
#include "xfs_trans.h"
17+
#include "xfs_sb.h"
18+
#include "xfs_inode.h"
19+
#include "xfs_alloc.h"
20+
#include "xfs_ialloc.h"
21+
#include "xfs_rmap.h"
22+
#include "xfs_health.h"
23+
#include "scrub/xfs_scrub.h"
24+
#include "scrub/scrub.h"
25+
#include "scrub/common.h"
26+
#include "scrub/trace.h"
27+
#include "scrub/repair.h"
28+
#include "scrub/fscounters.h"
29+
30+
/*
31+
* FS Summary Counters
32+
* ===================
33+
*
34+
* We correct errors in the filesystem summary counters by setting them to the
35+
* values computed during the obligatory scrub phase. However, we must be
36+
* careful not to allow any other thread to change the counters while we're
37+
* computing and setting new values. To achieve this, we freeze the
38+
* filesystem for the whole operation if the REPAIR flag is set. The checking
39+
* function is stricter when we've frozen the fs.
40+
*/
41+
42+
/*
43+
* Reset the superblock counters. Caller is responsible for freezing the
44+
* filesystem during the calculation and reset phases.
45+
*/
46+
int
47+
xrep_fscounters(
48+
struct xfs_scrub *sc)
49+
{
50+
struct xfs_mount *mp = sc->mp;
51+
struct xchk_fscounters *fsc = sc->buf;
52+
53+
/*
54+
* Reinitialize the in-core counters from what we computed. We froze
55+
* the filesystem, so there shouldn't be anyone else trying to modify
56+
* these counters.
57+
*/
58+
if (!fsc->frozen) {
59+
ASSERT(fsc->frozen);
60+
return -EFSCORRUPTED;
61+
}
62+
63+
trace_xrep_reset_counters(mp, fsc);
64+
65+
percpu_counter_set(&mp->m_icount, fsc->icount);
66+
percpu_counter_set(&mp->m_ifree, fsc->ifree);
67+
percpu_counter_set(&mp->m_fdblocks, fsc->fdblocks);
68+
percpu_counter_set(&mp->m_frextents, fsc->frextents);
69+
mp->m_sb.sb_frextents = fsc->frextents;
70+
71+
return 0;
72+
}

fs/xfs/scrub/repair.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ int xrep_bmap_data(struct xfs_scrub *sc);
117117
int xrep_bmap_attr(struct xfs_scrub *sc);
118118
int xrep_bmap_cow(struct xfs_scrub *sc);
119119
int xrep_nlinks(struct xfs_scrub *sc);
120+
int xrep_fscounters(struct xfs_scrub *sc);
120121

121122
#ifdef CONFIG_XFS_RT
122123
int xrep_rtbitmap(struct xfs_scrub *sc);
@@ -198,6 +199,7 @@ xrep_setup_nothing(
198199
#define xrep_quota xrep_notsupported
199200
#define xrep_quotacheck xrep_notsupported
200201
#define xrep_nlinks xrep_notsupported
202+
#define xrep_fscounters xrep_notsupported
201203

202204
#endif /* CONFIG_XFS_ONLINE_REPAIR */
203205

fs/xfs/scrub/scrub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
364364
.type = ST_FS,
365365
.setup = xchk_setup_fscounters,
366366
.scrub = xchk_fscounters,
367-
.repair = xrep_notsupported,
367+
.repair = xrep_fscounters,
368368
},
369369
[XFS_SCRUB_TYPE_QUOTACHECK] = { /* quota counters */
370370
.type = ST_FS,

fs/xfs/scrub/trace.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "scrub/quota.h"
2525
#include "scrub/iscan.h"
2626
#include "scrub/nlinks.h"
27+
#include "scrub/fscounters.h"
2728

2829
/* Figure out which block the btree cursor was pointing to. */
2930
static inline xfs_fsblock_t

fs/xfs/scrub/trace.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct xfarray_sortinfo;
2424
struct xchk_dqiter;
2525
struct xchk_iscan;
2626
struct xchk_nlink;
27+
struct xchk_fscounters;
2728

2829
/*
2930
* ftrace's __print_symbolic requires that all enum values be wrapped in the
@@ -1804,16 +1805,28 @@ TRACE_EVENT(xrep_calc_ag_resblks_btsize,
18041805
__entry->refcbt_sz)
18051806
)
18061807
TRACE_EVENT(xrep_reset_counters,
1807-
TP_PROTO(struct xfs_mount *mp),
1808-
TP_ARGS(mp),
1808+
TP_PROTO(struct xfs_mount *mp, struct xchk_fscounters *fsc),
1809+
TP_ARGS(mp, fsc),
18091810
TP_STRUCT__entry(
18101811
__field(dev_t, dev)
1812+
__field(uint64_t, icount)
1813+
__field(uint64_t, ifree)
1814+
__field(uint64_t, fdblocks)
1815+
__field(uint64_t, frextents)
18111816
),
18121817
TP_fast_assign(
18131818
__entry->dev = mp->m_super->s_dev;
1819+
__entry->icount = fsc->icount;
1820+
__entry->ifree = fsc->ifree;
1821+
__entry->fdblocks = fsc->fdblocks;
1822+
__entry->frextents = fsc->frextents;
18141823
),
1815-
TP_printk("dev %d:%d",
1816-
MAJOR(__entry->dev), MINOR(__entry->dev))
1824+
TP_printk("dev %d:%d icount %llu ifree %llu fdblocks %llu frextents %llu",
1825+
MAJOR(__entry->dev), MINOR(__entry->dev),
1826+
__entry->icount,
1827+
__entry->ifree,
1828+
__entry->fdblocks,
1829+
__entry->frextents)
18171830
)
18181831

18191832
DECLARE_EVENT_CLASS(xrep_newbt_extent_class,

0 commit comments

Comments
 (0)