aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcu
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2016-01-03 23:29:57 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2016-03-31 16:34:50 -0400
commit8c7c4829a81c1838f18c12ce5a3a5c29a08bf0a8 (patch)
tree0d06174a9f214fb1eb96919d48c490c0fae0db1c /kernel/rcu
parentfcfd0a237bfcf0c314005007e9d76e55a25e2bad (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.c39
-rw-r--r--kernel/rcu/tree.h2
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
386static ulong jiffies_till_first_fqs = ULONG_MAX; 386static ulong jiffies_till_first_fqs = ULONG_MAX;
387static ulong jiffies_till_next_fqs = ULONG_MAX; 387static ulong jiffies_till_next_fqs = ULONG_MAX;
388static bool rcu_kick_kthreads;
388 389
389module_param(jiffies_till_first_fqs, ulong, 0644); 390module_param(jiffies_till_first_fqs, ulong, 0644);
390module_param(jiffies_till_next_fqs, ulong, 0644); 391module_param(jiffies_till_next_fqs, ulong, 0644);
392module_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 */
1260static 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
1254static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) 1274static 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 */