Skip to content

Commit 84ae910

Browse files
paulmckrcufbq
authored andcommitted
rcutorture: Include grace-period sequence numbers in failure/close-call
This commit includes the grace-period sequence numbers at the beginning and end of each segment in the "Failure/close-call rcutorture reader segments" list. These are in hexadecimal, and only the bottom byte. Currently, only RCU is supported, with its three sequence numbers (normal, expedited, and polled). Note that if all the grace-period sequence numbers remain the same across a given reader segment, only one copy of the number will be printed. Of course, if there is a change, both sets of values will be printed. Because the overhead of collecting this information can suppress heisenbugs, this information is collected and printed only in kernels built with CONFIG_RCU_TORTURE_TEST_LOG_GP=y. [ paulmck: Apply Nathan Chancellor feedback for IS_ENABLED(). ] [ paulmck: Apply feedback from kernel test robot. ] Signed-off-by: Paul E. McKenney <[email protected]> Tested-by: kernel test robot <[email protected]> Signed-off-by: Boqun Feng <[email protected]>
1 parent b8726c5 commit 84ae910

File tree

5 files changed

+84
-0
lines changed

5 files changed

+84
-0
lines changed

kernel/rcu/Kconfig.debug

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ config RCU_TORTURE_TEST_LOG_CPU
8484
Say Y here if you want CPU IDs logged.
8585
Say N if you are unsure.
8686

87+
config RCU_TORTURE_TEST_LOG_GP
88+
bool "Log grace-period numbers for rcutorture failures"
89+
depends on RCU_TORTURE_TEST
90+
default n
91+
help
92+
This option causes rcutorture to decorate each entry of its
93+
log of failure/close-call rcutorture reader segments with the
94+
corresponding grace-period sequence numbers. This information
95+
can be useful, but it does incur additional overhead, overhead
96+
that can make both failures and close calls less probable.
97+
98+
Say Y here if you want grace-period sequence numbers logged.
99+
Say N if you are unsure.
100+
87101
config RCU_REF_SCALE_TEST
88102
tristate "Scalability tests for read-side synchronization (RCU and others)"
89103
depends on DEBUG_KERNEL

kernel/rcu/rcu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ void do_trace_rcu_torture_read(const char *rcutorturename,
590590
#endif
591591
static inline void rcu_gp_set_torture_wait(int duration) { }
592592
#endif
593+
unsigned long rcutorture_gather_gp_seqs(void);
594+
void rcutorture_format_gp_seqs(unsigned long seqs, char *cp);
593595

594596
#ifdef CONFIG_TINY_SRCU
595597

kernel/rcu/rcutorture.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ struct rt_read_seg {
273273
bool rt_preempted;
274274
int rt_cpu;
275275
int rt_end_cpu;
276+
unsigned long rt_gp_seq;
277+
unsigned long rt_gp_seq_end;
276278
};
277279
static int err_segs_recorded;
278280
static struct rt_read_seg err_segs[RCUTORTURE_RDR_MAX_SEGS];
@@ -407,6 +409,8 @@ struct rcu_torture_ops {
407409
void (*gp_slow_register)(atomic_t *rgssp);
408410
void (*gp_slow_unregister)(atomic_t *rgssp);
409411
bool (*reader_blocked)(void);
412+
unsigned long (*gather_gp_seqs)(void);
413+
void (*format_gp_seqs)(unsigned long seqs, char *cp);
410414
long cbflood_max;
411415
int irq_capable;
412416
int can_boost;
@@ -611,6 +615,8 @@ static struct rcu_torture_ops rcu_ops = {
611615
.reader_blocked = IS_ENABLED(CONFIG_RCU_TORTURE_TEST_LOG_CPU)
612616
? has_rcu_reader_blocked
613617
: NULL,
618+
.gather_gp_seqs = rcutorture_gather_gp_seqs,
619+
.format_gp_seqs = rcutorture_format_gp_seqs,
614620
.irq_capable = 1,
615621
.can_boost = IS_ENABLED(CONFIG_RCU_BOOST),
616622
.extendables = RCUTORTURE_MAX_EXTEND,
@@ -656,6 +662,8 @@ static struct rcu_torture_ops rcu_busted_ops = {
656662
.sync = synchronize_rcu_busted,
657663
.exp_sync = synchronize_rcu_busted,
658664
.call = call_rcu_busted,
665+
.gather_gp_seqs = rcutorture_gather_gp_seqs,
666+
.format_gp_seqs = rcutorture_format_gp_seqs,
659667
.irq_capable = 1,
660668
.extendables = RCUTORTURE_MAX_EXTEND,
661669
.name = "busted"
@@ -1978,6 +1986,12 @@ static void rcutorture_one_extend(int *readstate, int newstate, bool insoftirq,
19781986
rtrsp[-1].rt_preempted = cur_ops->reader_blocked();
19791987
}
19801988
}
1989+
// Sample grace-period sequence number, as good a place as any.
1990+
if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST_LOG_GP) && cur_ops->gather_gp_seqs) {
1991+
rtrsp->rt_gp_seq = cur_ops->gather_gp_seqs();
1992+
if (!first)
1993+
rtrsp[-1].rt_gp_seq_end = rtrsp->rt_gp_seq;
1994+
}
19811995

19821996
/*
19831997
* Next, remove old protection, in decreasing order of strength
@@ -3566,6 +3580,7 @@ rcu_torture_cleanup(void)
35663580
int flags = 0;
35673581
unsigned long gp_seq = 0;
35683582
int i;
3583+
int j;
35693584

35703585
if (torture_cleanup_begin()) {
35713586
if (cur_ops->cb_barrier != NULL) {
@@ -3661,6 +3676,25 @@ rcu_torture_cleanup(void)
36613676
else
36623677
pr_cont(" ...");
36633678
}
3679+
if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST_LOG_GP) &&
3680+
cur_ops->gather_gp_seqs && cur_ops->format_gp_seqs) {
3681+
char buf1[16+1];
3682+
char buf2[16+1];
3683+
char sepchar = '-';
3684+
3685+
cur_ops->format_gp_seqs(err_segs[i].rt_gp_seq, buf1);
3686+
cur_ops->format_gp_seqs(err_segs[i].rt_gp_seq_end, buf2);
3687+
if (err_segs[i].rt_gp_seq == err_segs[i].rt_gp_seq_end) {
3688+
if (buf2[0]) {
3689+
for (j = 0; buf2[j]; j++)
3690+
buf2[j] = '.';
3691+
if (j)
3692+
buf2[j - 1] = ' ';
3693+
}
3694+
sepchar = ' ';
3695+
}
3696+
pr_cont(" %s%c%s", buf1, sepchar, buf2);
3697+
}
36643698
if (err_segs[i].rt_delay_ms != 0) {
36653699
pr_cont(" %s%ldms", firsttime ? "" : "+",
36663700
err_segs[i].rt_delay_ms);

kernel/rcu/tiny.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,20 @@ void kvfree_call_rcu(struct rcu_head *head, void *ptr)
257257
EXPORT_SYMBOL_GPL(kvfree_call_rcu);
258258
#endif
259259

260+
#if IS_ENABLED(CONFIG_RCU_TORTURE_TEST)
261+
unsigned long rcutorture_gather_gp_seqs(void)
262+
{
263+
return READ_ONCE(rcu_ctrlblk.gp_seq) & 0xff;
264+
}
265+
EXPORT_SYMBOL_GPL(rcutorture_gather_gp_seqs);
266+
267+
void rcutorture_format_gp_seqs(unsigned long seqs, char *cp)
268+
{
269+
snprintf(cp, 8, "g%02lx", seqs & 0xff);
270+
}
271+
EXPORT_SYMBOL_GPL(rcutorture_format_gp_seqs);
272+
#endif
273+
260274
void __init rcu_init(void)
261275
{
262276
open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);

kernel/rcu/tree.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,26 @@ void rcutorture_get_gp_data(int *flags, unsigned long *gp_seq)
538538
}
539539
EXPORT_SYMBOL_GPL(rcutorture_get_gp_data);
540540

541+
/* Gather grace-period sequence numbers for rcutorture diagnostics. */
542+
unsigned long rcutorture_gather_gp_seqs(void)
543+
{
544+
return ((READ_ONCE(rcu_state.gp_seq) & 0xff) << 16) |
545+
((READ_ONCE(rcu_state.expedited_sequence) & 0xff) << 8) |
546+
(READ_ONCE(rcu_state.gp_seq_polled) & 0xff);
547+
}
548+
EXPORT_SYMBOL_GPL(rcutorture_gather_gp_seqs);
549+
550+
/* Format grace-period sequence numbers for rcutorture diagnostics. */
551+
void rcutorture_format_gp_seqs(unsigned long seqs, char *cp)
552+
{
553+
unsigned int egp = (seqs >> 8) & 0xff;
554+
unsigned int ggp = (seqs >> 16) & 0xff;
555+
unsigned int pgp = seqs & 0xff;
556+
557+
snprintf(cp, 16, "g%02x:e%02x:p%02x", ggp, egp, pgp);
558+
}
559+
EXPORT_SYMBOL_GPL(rcutorture_format_gp_seqs);
560+
541561
#if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
542562
/*
543563
* An empty function that will trigger a reschedule on

0 commit comments

Comments
 (0)