Skip to content

Commit 271557d

Browse files
author
Darrick J. Wong
committed
xfs: reduce the rate of cond_resched calls inside scrub
We really don't want to call cond_resched every single time we go through a loop in scrub -- there may be billions of records, and probing into the scheduler itself has overhead. Reduce this overhead by only calling cond_resched 10x per second; and add a counter so that we only check jiffies once every 1000 records or so. Surprisingly, this reduces scrub-only fstests runtime by about 2%. I used the bmapinflate xfs_db command to produce a billion-extent file and this stupid gadget reduced the scrub runtime by about 4%. From a stupid microbenchmark of calling these things 1 billion times, I estimate that cond_resched costs about 5.5ns per call; jiffes costs about 0.3ns per read; and fatal_signal_pending costs about 0.4ns per call. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent 3f31406 commit 271557d

File tree

6 files changed

+74
-31
lines changed

6 files changed

+74
-31
lines changed

fs/xfs/scrub/common.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,6 @@
66
#ifndef __XFS_SCRUB_COMMON_H__
77
#define __XFS_SCRUB_COMMON_H__
88

9-
/*
10-
* We /could/ terminate a scrub/repair operation early. If we're not
11-
* in a good place to continue (fatal signal, etc.) then bail out.
12-
* Note that we're careful not to make any judgements about *error.
13-
*/
14-
static inline bool
15-
xchk_should_terminate(
16-
struct xfs_scrub *sc,
17-
int *error)
18-
{
19-
/*
20-
* If preemption is disabled, we need to yield to the scheduler every
21-
* few seconds so that we don't run afoul of the soft lockup watchdog
22-
* or RCU stall detector.
23-
*/
24-
cond_resched();
25-
26-
if (fatal_signal_pending(current)) {
27-
if (*error == 0)
28-
*error = -EINTR;
29-
return true;
30-
}
31-
return false;
32-
}
33-
349
int xchk_trans_alloc(struct xfs_scrub *sc, uint resblks);
3510
int xchk_trans_alloc_empty(struct xfs_scrub *sc);
3611
void xchk_trans_cancel(struct xfs_scrub *sc);

fs/xfs/scrub/scrub.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ xfs_scrub_metadata(
620620
sc->sm = sm;
621621
sc->ops = &meta_scrub_ops[sm->sm_type];
622622
sc->sick_mask = xchk_health_mask_for_scrub_type(sm->sm_type);
623+
sc->relax = INIT_XCHK_RELAX;
623624
retry_op:
624625
/*
625626
* When repairs are allowed, prevent freezing or readonly remount while

fs/xfs/scrub/scrub.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,49 @@
88

99
struct xfs_scrub;
1010

11+
struct xchk_relax {
12+
unsigned long next_resched;
13+
unsigned int resched_nr;
14+
bool interruptible;
15+
};
16+
17+
/* Yield to the scheduler at most 10x per second. */
18+
#define XCHK_RELAX_NEXT (jiffies + (HZ / 10))
19+
20+
#define INIT_XCHK_RELAX \
21+
(struct xchk_relax){ \
22+
.next_resched = XCHK_RELAX_NEXT, \
23+
.resched_nr = 0, \
24+
.interruptible = true, \
25+
}
26+
27+
/*
28+
* Relax during a scrub operation and exit if there's a fatal signal pending.
29+
*
30+
* If preemption is disabled, we need to yield to the scheduler every now and
31+
* then so that we don't run afoul of the soft lockup watchdog or RCU stall
32+
* detector. cond_resched calls are somewhat expensive (~5ns) so we want to
33+
* ratelimit this to 10x per second. Amortize the cost of the other checks by
34+
* only doing it once every 100 calls.
35+
*/
36+
static inline int xchk_maybe_relax(struct xchk_relax *widget)
37+
{
38+
/* Amortize the cost of scheduling and checking signals. */
39+
if (likely(++widget->resched_nr < 100))
40+
return 0;
41+
widget->resched_nr = 0;
42+
43+
if (unlikely(widget->next_resched <= jiffies)) {
44+
cond_resched();
45+
widget->next_resched = XCHK_RELAX_NEXT;
46+
}
47+
48+
if (widget->interruptible && fatal_signal_pending(current))
49+
return -EINTR;
50+
51+
return 0;
52+
}
53+
1154
/*
1255
* Standard flags for allocating memory within scrub. NOFS context is
1356
* configured by the process allocation scope. Scrub and repair must be able
@@ -123,6 +166,9 @@ struct xfs_scrub {
123166
*/
124167
unsigned int sick_mask;
125168

169+
/* next time we want to cond_resched() */
170+
struct xchk_relax relax;
171+
126172
/* State tracking for single-AG operations. */
127173
struct xchk_ag sa;
128174
};
@@ -167,6 +213,24 @@ struct xfs_scrub_subord *xchk_scrub_create_subord(struct xfs_scrub *sc,
167213
unsigned int subtype);
168214
void xchk_scrub_free_subord(struct xfs_scrub_subord *sub);
169215

216+
/*
217+
* We /could/ terminate a scrub/repair operation early. If we're not
218+
* in a good place to continue (fatal signal, etc.) then bail out.
219+
* Note that we're careful not to make any judgements about *error.
220+
*/
221+
static inline bool
222+
xchk_should_terminate(
223+
struct xfs_scrub *sc,
224+
int *error)
225+
{
226+
if (xchk_maybe_relax(&sc->relax)) {
227+
if (*error == 0)
228+
*error = -EINTR;
229+
return true;
230+
}
231+
return false;
232+
}
233+
170234
/* Metadata scrubbers */
171235
int xchk_tester(struct xfs_scrub *sc);
172236
int xchk_superblock(struct xfs_scrub *sc);

fs/xfs/scrub/xfarray.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
#include "xfs_fs.h"
88
#include "xfs_shared.h"
99
#include "xfs_format.h"
10+
#include "scrub/scrub.h"
1011
#include "scrub/xfile.h"
1112
#include "scrub/xfarray.h"
12-
#include "scrub/scrub.h"
1313
#include "scrub/trace.h"
1414

1515
/*
@@ -486,6 +486,9 @@ xfarray_sortinfo_alloc(
486486

487487
xfarray_sortinfo_lo(si)[0] = 0;
488488
xfarray_sortinfo_hi(si)[0] = array->nr - 1;
489+
si->relax = INIT_XCHK_RELAX;
490+
if (flags & XFARRAY_SORT_KILLABLE)
491+
si->relax.interruptible = false;
489492

490493
trace_xfarray_sort(si, nr_bytes);
491494
*infop = si;
@@ -503,10 +506,7 @@ xfarray_sort_terminated(
503506
* few seconds so that we don't run afoul of the soft lockup watchdog
504507
* or RCU stall detector.
505508
*/
506-
cond_resched();
507-
508-
if ((si->flags & XFARRAY_SORT_KILLABLE) &&
509-
fatal_signal_pending(current)) {
509+
if (xchk_maybe_relax(&si->relax)) {
510510
if (*error == 0)
511511
*error = -EINTR;
512512
return true;

fs/xfs/scrub/xfarray.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ struct xfarray_sortinfo {
127127
/* XFARRAY_SORT_* flags; see below. */
128128
unsigned int flags;
129129

130+
/* next time we want to cond_resched() */
131+
struct xchk_relax relax;
132+
130133
/* Cache a folio here for faster scanning for pivots */
131134
struct folio *folio;
132135

fs/xfs/scrub/xfile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
#include "xfs_log_format.h"
1111
#include "xfs_trans_resv.h"
1212
#include "xfs_mount.h"
13+
#include "scrub/scrub.h"
1314
#include "scrub/xfile.h"
1415
#include "scrub/xfarray.h"
15-
#include "scrub/scrub.h"
1616
#include "scrub/trace.h"
1717
#include <linux/shmem_fs.h>
1818

0 commit comments

Comments
 (0)