Skip to content

Commit 7f99362

Browse files
paulmckrcuFrederic Weisbecker
authored andcommitted
locktorture: Add call_rcu_chains module parameter
When running locktorture on large systems, there will normally be enough RCU activity to ensure that there is a grace period in flight at all times. However, on smaller systems, RCU might well be idle the majority of the time. This situation can be inconvenient in cases where the RCU CPU stall warning is part of the debugging process. This commit therefore adds an call_rcu_chains module parameter to locktorture, allowing the user to specify the desired number of self-propagating call_rcu() chains. For good measure, immediately before invoking call_rcu(), the self-propagating RCU callback invokes start_poll_synchronize_rcu() to force the immediate start of a grace period, with the call_rcu() forcing another to start shortly thereafter. Booting with locktorture.call_rcu_chains=2 increases the probability of a stuck locking primitive resulting in an RCU CPU stall warning from about 25% to nearly 100%. Signed-off-by: Paul E. McKenney <[email protected]> Signed-off-by: Frederic Weisbecker <[email protected]>
1 parent 00c24c9 commit 7f99362

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2913,6 +2913,13 @@
29132913
to extract confidential information from the kernel
29142914
are also disabled.
29152915

2916+
locktorture.call_rcu_chains= [KNL]
2917+
Specify the number of self-propagating call_rcu()
2918+
chains to set up. These are used to ensure that
2919+
there is a high probability of an RCU grace period
2920+
in progress at any given time. Defaults to 0,
2921+
which disables these call_rcu() chains.
2922+
29162923
locktorture.nreaders_stress= [KNL]
29172924
Set the number of locking read-acquisition kthreads.
29182925
Defaults to being automatically set based on the

kernel/locking/locktorture.c

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ MODULE_LICENSE("GPL");
3434
MODULE_AUTHOR("Paul E. McKenney <[email protected]>");
3535

3636
torture_param(int, acq_writer_lim, 0, "Write_acquisition time limit (jiffies).");
37+
torture_param(int, call_rcu_chains, 0, "Self-propagate call_rcu() chains during test (0=disable).");
3738
torture_param(int, long_hold, 100, "Do occasional long hold of lock (ms), 0=disable");
3839
torture_param(int, nested_locks, 0, "Number of nested locks (max = 8)");
3940
torture_param(int, nreaders_stress, -1, "Number of read-locking stress-test threads");
@@ -119,6 +120,12 @@ struct lock_stress_stats {
119120
long n_lock_acquired;
120121
};
121122

123+
struct call_rcu_chain {
124+
struct rcu_head crc_rh;
125+
bool crc_stop;
126+
};
127+
struct call_rcu_chain *call_rcu_chain;
128+
122129
/* Forward reference. */
123130
static void lock_torture_cleanup(void);
124131

@@ -1037,15 +1044,60 @@ lock_torture_print_module_parms(struct lock_torture_ops *cur_ops,
10371044

10381045
cpumask_setall(&cpumask_all);
10391046
pr_alert("%s" TORTURE_FLAG
1040-
"--- %s%s: acq_writer_lim=%d long_hold=%d nested_locks=%d nreaders_stress=%d nwriters_stress=%d onoff_holdoff=%d onoff_interval=%d rt_boost=%d rt_boost_factor=%d shuffle_interval=%d shutdown_secs=%d stat_interval=%d stutter=%d verbose=%d writer_fifo=%d readers_bind=%*pbl writers_bind=%*pbl\n",
1047+
"--- %s%s: acq_writer_lim=%d call_rcu_chains=%d long_hold=%d nested_locks=%d nreaders_stress=%d nwriters_stress=%d onoff_holdoff=%d onoff_interval=%d rt_boost=%d rt_boost_factor=%d shuffle_interval=%d shutdown_secs=%d stat_interval=%d stutter=%d verbose=%d writer_fifo=%d readers_bind=%*pbl writers_bind=%*pbl\n",
10411048
torture_type, tag, cxt.debug_lock ? " [debug]": "",
1042-
acq_writer_lim, long_hold, nested_locks, cxt.nrealreaders_stress,
1049+
acq_writer_lim, call_rcu_chains, long_hold, nested_locks, cxt.nrealreaders_stress,
10431050
cxt.nrealwriters_stress, onoff_holdoff, onoff_interval, rt_boost,
10441051
rt_boost_factor, shuffle_interval, shutdown_secs, stat_interval, stutter,
10451052
verbose, writer_fifo,
10461053
cpumask_pr_args(rcmp), cpumask_pr_args(wcmp));
10471054
}
10481055

1056+
// If requested, maintain call_rcu() chains to keep a grace period always
1057+
// in flight. These increase the probability of getting an RCU CPU stall
1058+
// warning and associated diagnostics when a locking primitive stalls.
1059+
1060+
static void call_rcu_chain_cb(struct rcu_head *rhp)
1061+
{
1062+
struct call_rcu_chain *crcp = container_of(rhp, struct call_rcu_chain, crc_rh);
1063+
1064+
if (!smp_load_acquire(&crcp->crc_stop)) {
1065+
(void)start_poll_synchronize_rcu(); // Start one grace period...
1066+
call_rcu(&crcp->crc_rh, call_rcu_chain_cb); // ... and later start another.
1067+
}
1068+
}
1069+
1070+
// Start the requested number of call_rcu() chains.
1071+
static int call_rcu_chain_init(void)
1072+
{
1073+
int i;
1074+
1075+
if (call_rcu_chains <= 0)
1076+
return 0;
1077+
call_rcu_chain = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain), GFP_KERNEL);
1078+
if (!call_rcu_chains)
1079+
return -ENOMEM;
1080+
for (i = 0; i < call_rcu_chains; i++) {
1081+
call_rcu_chain[i].crc_stop = false;
1082+
call_rcu(&call_rcu_chain[i].crc_rh, call_rcu_chain_cb);
1083+
}
1084+
return 0;
1085+
}
1086+
1087+
// Stop all of the call_rcu() chains.
1088+
static void call_rcu_chain_cleanup(void)
1089+
{
1090+
int i;
1091+
1092+
if (!call_rcu_chain)
1093+
return;
1094+
for (i = 0; i < call_rcu_chains; i++)
1095+
smp_store_release(&call_rcu_chain[i].crc_stop, true);
1096+
rcu_barrier();
1097+
kfree(call_rcu_chain);
1098+
call_rcu_chain = NULL;
1099+
}
1100+
10491101
static void lock_torture_cleanup(void)
10501102
{
10511103
int i;
@@ -1096,6 +1148,8 @@ static void lock_torture_cleanup(void)
10961148
kfree(cxt.lrsa);
10971149
cxt.lrsa = NULL;
10981150

1151+
call_rcu_chain_cleanup();
1152+
10991153
end:
11001154
if (cxt.init_called) {
11011155
if (cxt.cur_ops->exit)
@@ -1225,6 +1279,10 @@ static int __init lock_torture_init(void)
12251279
}
12261280
}
12271281

1282+
firsterr = call_rcu_chain_init();
1283+
if (torture_init_error(firsterr))
1284+
goto unwind;
1285+
12281286
lock_torture_print_module_parms(cxt.cur_ops, "Start of test");
12291287

12301288
/* Prepare torture context. */

0 commit comments

Comments
 (0)