Skip to content

Commit 5d1bd19

Browse files
author
Chandan Babu R
committed
Merge tag 'repair-fscounters-6.9_2024-02-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.9-mergeC
xfs: online repair for fs summary counters A longstanding deficiency in the online fs summary counter scrubbing code is that it hasn't any means to quiesce the incore percpu counters while it's running. There is no way to coordinate with other threads are reserving or freeing free space simultaneously, which leads to false error reports. Right now, if the discrepancy is large, we just sort of shrug and bail out with an incomplete flag, but this is lame. For repair activity, we actually /do/ need to stabilize the counters to get an accurate reading and install it in the percpu counter. To improve the former and enable the latter, allow the fscounters online fsck code to perform an exclusive mini-freeze on the filesystem. The exclusivity prevents userspace from thawing while we're running, and the mini-freeze means that we don't wait for the log to quiesce, which will make both speedier. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Chandan Babu R <chandanbabu@kernel.org> * tag 'repair-fscounters-6.9_2024-02-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux: xfs: repair summary counters
2 parents f107757 + 4ed080c commit 5d1bd19

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)