Skip to content

Commit 55b2dcf

Browse files
committed
rcu: Allow rcutorture to starve grace-period kthread
This commit provides an rcutorture.stall_gp_kthread module parameter to allow rcutorture to starve the grace-period kthread. This allows testing the code that detects such starvation. Signed-off-by: Paul E. McKenney <[email protected]>
1 parent df59168 commit 55b2dcf

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4221,6 +4221,13 @@
42214221
rcutorture.stall_cpu_irqsoff= [KNL]
42224222
Disable interrupts while stalling if set.
42234223

4224+
rcutorture.stall_gp_kthread= [KNL]
4225+
Duration (s) of forced sleep within RCU
4226+
grace-period kthread to test RCU CPU stall
4227+
warnings, zero to disable. If both stall_cpu
4228+
and stall_gp_kthread are specified, the
4229+
kthread is starved first, then the CPU.
4230+
42244231
rcutorture.stat_interval= [KNL]
42254232
Time (s) between statistics printk()s.
42264233

kernel/rcu/rcu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ void do_trace_rcu_torture_read(const char *rcutorturename,
454454
unsigned long secs,
455455
unsigned long c_old,
456456
unsigned long c);
457+
void rcu_gp_set_torture_wait(int duration);
457458
#else
458459
static inline void rcutorture_get_gp_data(enum rcutorture_type test_type,
459460
int *flags, unsigned long *gp_seq)
@@ -471,6 +472,7 @@ void do_trace_rcu_torture_read(const char *rcutorturename,
471472
#define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
472473
do { } while (0)
473474
#endif
475+
static inline void rcu_gp_set_torture_wait(int duration) { }
474476
#endif
475477

476478
#if IS_ENABLED(CONFIG_RCU_TORTURE_TEST) || IS_MODULE(CONFIG_RCU_TORTURE_TEST)

kernel/rcu/rcutorture.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ torture_param(int, stall_cpu_holdoff, 10,
115115
"Time to wait before starting stall (s).");
116116
torture_param(int, stall_cpu_irqsoff, 0, "Disable interrupts while stalling.");
117117
torture_param(int, stall_cpu_block, 0, "Sleep while stalling.");
118+
torture_param(int, stall_gp_kthread, 0,
119+
"Grace-period kthread stall duration (s).");
118120
torture_param(int, stat_interval, 60,
119121
"Number of seconds between stats printk()s");
120122
torture_param(int, stutter, 5, "Number of seconds to run/halt test");
@@ -1623,7 +1625,17 @@ static int rcu_torture_stall(void *args)
16231625
schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
16241626
VERBOSE_TOROUT_STRING("rcu_torture_stall end holdoff");
16251627
}
1626-
if (!kthread_should_stop()) {
1628+
if (!kthread_should_stop() && stall_gp_kthread > 0) {
1629+
VERBOSE_TOROUT_STRING("rcu_torture_stall begin GP stall");
1630+
rcu_gp_set_torture_wait(stall_gp_kthread * HZ);
1631+
for (idx = 0; idx < stall_gp_kthread + 2; idx++) {
1632+
if (kthread_should_stop())
1633+
break;
1634+
schedule_timeout_uninterruptible(HZ);
1635+
}
1636+
}
1637+
if (!kthread_should_stop() && stall_cpu > 0) {
1638+
VERBOSE_TOROUT_STRING("rcu_torture_stall begin CPU stall");
16271639
stop_at = ktime_get_seconds() + stall_cpu;
16281640
/* RCU CPU stall is expected behavior in following code. */
16291641
idx = cur_ops->readlock();
@@ -1642,8 +1654,8 @@ static int rcu_torture_stall(void *args)
16421654
else if (!stall_cpu_block)
16431655
preempt_enable();
16441656
cur_ops->readunlock(idx);
1645-
pr_alert("rcu_torture_stall end.\n");
16461657
}
1658+
pr_alert("rcu_torture_stall end.\n");
16471659
torture_shutdown_absorb("rcu_torture_stall");
16481660
while (!kthread_should_stop())
16491661
schedule_timeout_interruptible(10 * HZ);
@@ -1653,7 +1665,7 @@ static int rcu_torture_stall(void *args)
16531665
/* Spawn CPU-stall kthread, if stall_cpu specified. */
16541666
static int __init rcu_torture_stall_init(void)
16551667
{
1656-
if (stall_cpu <= 0)
1668+
if (stall_cpu <= 0 && stall_gp_kthread <= 0)
16571669
return 0;
16581670
return torture_create_kthread(rcu_torture_stall, NULL, stall_task);
16591671
}

kernel/rcu/tree.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,31 @@ static void rcu_gp_slow(int delay)
14861486
schedule_timeout_uninterruptible(delay);
14871487
}
14881488

1489+
static unsigned long sleep_duration;
1490+
1491+
/* Allow rcutorture to stall the grace-period kthread. */
1492+
void rcu_gp_set_torture_wait(int duration)
1493+
{
1494+
if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST) && duration > 0)
1495+
WRITE_ONCE(sleep_duration, duration);
1496+
}
1497+
EXPORT_SYMBOL_GPL(rcu_gp_set_torture_wait);
1498+
1499+
/* Actually implement the aforementioned wait. */
1500+
static void rcu_gp_torture_wait(void)
1501+
{
1502+
unsigned long duration;
1503+
1504+
if (!IS_ENABLED(CONFIG_RCU_TORTURE_TEST))
1505+
return;
1506+
duration = xchg(&sleep_duration, 0UL);
1507+
if (duration > 0) {
1508+
pr_alert("%s: Waiting %lu jiffies\n", __func__, duration);
1509+
schedule_timeout_uninterruptible(duration);
1510+
pr_alert("%s: Wait complete\n", __func__);
1511+
}
1512+
}
1513+
14891514
/*
14901515
* Initialize a new grace period. Return false if no grace period required.
14911516
*/
@@ -1686,6 +1711,7 @@ static void rcu_gp_fqs_loop(void)
16861711
rcu_state.gp_state = RCU_GP_WAIT_FQS;
16871712
ret = swait_event_idle_timeout_exclusive(
16881713
rcu_state.gp_wq, rcu_gp_fqs_check_wake(&gf), j);
1714+
rcu_gp_torture_wait();
16891715
rcu_state.gp_state = RCU_GP_DOING_FQS;
16901716
/* Locking provides needed memory barriers. */
16911717
/* If grace period done, leave loop. */
@@ -1834,6 +1860,7 @@ static int __noreturn rcu_gp_kthread(void *unused)
18341860
swait_event_idle_exclusive(rcu_state.gp_wq,
18351861
READ_ONCE(rcu_state.gp_flags) &
18361862
RCU_GP_FLAG_INIT);
1863+
rcu_gp_torture_wait();
18371864
rcu_state.gp_state = RCU_GP_DONE_GPS;
18381865
/* Locking provides needed memory barrier. */
18391866
if (rcu_gp_init())

0 commit comments

Comments
 (0)