diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2016-01-03 23:29:57 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2016-03-31 16:34:50 -0400 |
commit | 8c7c4829a81c1838f18c12ce5a3a5c29a08bf0a8 (patch) | |
tree | 0d06174a9f214fb1eb96919d48c490c0fae0db1c /kernel/rcu | |
parent | fcfd0a237bfcf0c314005007e9d76e55a25e2bad (diff) |
rcu: Awaken grace-period kthread if too long since FQS
Recent kernels can fail to awaken the grace-period kthread for
quiescent-state forcing. This commit is a crude hack that does
a wakeup if a scheduling-clock interrupt sees that it has been
too long since force-quiescent-state (FQS) processing.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcu')
-rw-r--r-- | kernel/rcu/tree.c | 39 | ||||
-rw-r--r-- | kernel/rcu/tree.h | 2 |
2 files changed, 39 insertions, 2 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 6116cfad18ff..a739292be605 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -385,9 +385,11 @@ module_param(qlowmark, long, 0444); | |||
385 | 385 | ||
386 | static ulong jiffies_till_first_fqs = ULONG_MAX; | 386 | static ulong jiffies_till_first_fqs = ULONG_MAX; |
387 | static ulong jiffies_till_next_fqs = ULONG_MAX; | 387 | static ulong jiffies_till_next_fqs = ULONG_MAX; |
388 | static bool rcu_kick_kthreads; | ||
388 | 389 | ||
389 | module_param(jiffies_till_first_fqs, ulong, 0644); | 390 | module_param(jiffies_till_first_fqs, ulong, 0644); |
390 | module_param(jiffies_till_next_fqs, ulong, 0644); | 391 | module_param(jiffies_till_next_fqs, ulong, 0644); |
392 | module_param(rcu_kick_kthreads, bool, 0644); | ||
391 | 393 | ||
392 | /* | 394 | /* |
393 | * How long the grace period must be before we start recruiting | 395 | * How long the grace period must be before we start recruiting |
@@ -1251,6 +1253,24 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp) | |||
1251 | } | 1253 | } |
1252 | } | 1254 | } |
1253 | 1255 | ||
1256 | /* | ||
1257 | * If too much time has passed in the current grace period, and if | ||
1258 | * so configured, go kick the relevant kthreads. | ||
1259 | */ | ||
1260 | static void rcu_stall_kick_kthreads(struct rcu_state *rsp) | ||
1261 | { | ||
1262 | unsigned long j; | ||
1263 | |||
1264 | if (!rcu_kick_kthreads) | ||
1265 | return; | ||
1266 | j = READ_ONCE(rsp->jiffies_kick_kthreads); | ||
1267 | if (time_after(jiffies, j) && rsp->gp_kthread) { | ||
1268 | WARN_ONCE(1, "Kicking %s grace-period kthread\n", rsp->name); | ||
1269 | wake_up_process(rsp->gp_kthread); | ||
1270 | WRITE_ONCE(rsp->jiffies_kick_kthreads, j + HZ); | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1254 | static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) | 1274 | static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) |
1255 | { | 1275 | { |
1256 | int cpu; | 1276 | int cpu; |
@@ -1262,6 +1282,11 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) | |||
1262 | struct rcu_node *rnp = rcu_get_root(rsp); | 1282 | struct rcu_node *rnp = rcu_get_root(rsp); |
1263 | long totqlen = 0; | 1283 | long totqlen = 0; |
1264 | 1284 | ||
1285 | /* Kick and suppress, if so configured. */ | ||
1286 | rcu_stall_kick_kthreads(rsp); | ||
1287 | if (rcu_cpu_stall_suppress) | ||
1288 | return; | ||
1289 | |||
1265 | /* Only let one CPU complain about others per time interval. */ | 1290 | /* Only let one CPU complain about others per time interval. */ |
1266 | 1291 | ||
1267 | raw_spin_lock_irqsave_rcu_node(rnp, flags); | 1292 | raw_spin_lock_irqsave_rcu_node(rnp, flags); |
@@ -1335,6 +1360,11 @@ static void print_cpu_stall(struct rcu_state *rsp) | |||
1335 | struct rcu_node *rnp = rcu_get_root(rsp); | 1360 | struct rcu_node *rnp = rcu_get_root(rsp); |
1336 | long totqlen = 0; | 1361 | long totqlen = 0; |
1337 | 1362 | ||
1363 | /* Kick and suppress, if so configured. */ | ||
1364 | rcu_stall_kick_kthreads(rsp); | ||
1365 | if (rcu_cpu_stall_suppress) | ||
1366 | return; | ||
1367 | |||
1338 | /* | 1368 | /* |
1339 | * OK, time to rat on ourselves... | 1369 | * OK, time to rat on ourselves... |
1340 | * See Documentation/RCU/stallwarn.txt for info on how to debug | 1370 | * See Documentation/RCU/stallwarn.txt for info on how to debug |
@@ -1379,8 +1409,10 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1379 | unsigned long js; | 1409 | unsigned long js; |
1380 | struct rcu_node *rnp; | 1410 | struct rcu_node *rnp; |
1381 | 1411 | ||
1382 | if (rcu_cpu_stall_suppress || !rcu_gp_in_progress(rsp)) | 1412 | if ((rcu_cpu_stall_suppress && !rcu_kick_kthreads) || |
1413 | !rcu_gp_in_progress(rsp)) | ||
1383 | return; | 1414 | return; |
1415 | rcu_stall_kick_kthreads(rsp); | ||
1384 | j = jiffies; | 1416 | j = jiffies; |
1385 | 1417 | ||
1386 | /* | 1418 | /* |
@@ -2119,8 +2151,11 @@ static int __noreturn rcu_gp_kthread(void *arg) | |||
2119 | } | 2151 | } |
2120 | ret = 0; | 2152 | ret = 0; |
2121 | for (;;) { | 2153 | for (;;) { |
2122 | if (!ret) | 2154 | if (!ret) { |
2123 | rsp->jiffies_force_qs = jiffies + j; | 2155 | rsp->jiffies_force_qs = jiffies + j; |
2156 | WRITE_ONCE(rsp->jiffies_kick_kthreads, | ||
2157 | jiffies + 3 * j); | ||
2158 | } | ||
2124 | trace_rcu_grace_period(rsp->name, | 2159 | trace_rcu_grace_period(rsp->name, |
2125 | READ_ONCE(rsp->gpnum), | 2160 | READ_ONCE(rsp->gpnum), |
2126 | TPS("fqswait")); | 2161 | TPS("fqswait")); |
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index df668c0f9e64..34d3973f7223 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h | |||
@@ -513,6 +513,8 @@ struct rcu_state { | |||
513 | 513 | ||
514 | unsigned long jiffies_force_qs; /* Time at which to invoke */ | 514 | unsigned long jiffies_force_qs; /* Time at which to invoke */ |
515 | /* force_quiescent_state(). */ | 515 | /* force_quiescent_state(). */ |
516 | unsigned long jiffies_kick_kthreads; /* Time at which to kick */ | ||
517 | /* kthreads, if configured. */ | ||
516 | unsigned long n_force_qs; /* Number of calls to */ | 518 | unsigned long n_force_qs; /* Number of calls to */ |
517 | /* force_quiescent_state(). */ | 519 | /* force_quiescent_state(). */ |
518 | unsigned long n_force_qs_lh; /* ~Number of calls leaving */ | 520 | unsigned long n_force_qs_lh; /* ~Number of calls leaving */ |