aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-07-01 21:16:30 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-09-07 19:27:26 -0400
commit52db30ab23b6d00cf80b22a510c4ea4be4458031 (patch)
tree98fdbf7de60a00768af1c62662f6f3e1e9ec6b27 /kernel
parentf1a828f5fa3537456c417a81ad534c14022c268c (diff)
rcu: Add stall-warning checks for RCU-tasks
This commit adds a ten-minute RCU-tasks stall warning. The actual time is controlled by the boot/sysfs parameter rcu_task_stall_timeout, with values less than or equal to zero disabling the stall warnings. The default value is ten minutes, which means that the tasks that have not yet responded will get their stacks dumped every ten minutes, until they pass through a voluntary context switch. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/rcu/update.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index aef8109152ce..bad7dbd4c2e3 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -371,7 +371,7 @@ static DEFINE_RAW_SPINLOCK(rcu_tasks_cbs_lock);
371DEFINE_SRCU(tasks_rcu_exit_srcu); 371DEFINE_SRCU(tasks_rcu_exit_srcu);
372 372
373/* Control stall timeouts. Disable with <= 0, otherwise jiffies till stall. */ 373/* Control stall timeouts. Disable with <= 0, otherwise jiffies till stall. */
374static int rcu_task_stall_timeout __read_mostly = HZ * 60 * 3; 374static int rcu_task_stall_timeout __read_mostly = HZ * 60 * 10;
375module_param(rcu_task_stall_timeout, int, 0644); 375module_param(rcu_task_stall_timeout, int, 0644);
376 376
377/* Post an RCU-tasks callback. */ 377/* Post an RCU-tasks callback. */
@@ -445,8 +445,9 @@ void rcu_barrier_tasks(void)
445} 445}
446EXPORT_SYMBOL_GPL(rcu_barrier_tasks); 446EXPORT_SYMBOL_GPL(rcu_barrier_tasks);
447 447
448/* See if the current task has stopped holding out, remove from list if so. */ 448/* See if tasks are still holding out, complain if so. */
449static void check_holdout_task(struct task_struct *t) 449static void check_holdout_task(struct task_struct *t,
450 bool needreport, bool *firstreport)
450{ 451{
451 if (!ACCESS_ONCE(t->rcu_tasks_holdout) || 452 if (!ACCESS_ONCE(t->rcu_tasks_holdout) ||
452 t->rcu_tasks_nvcsw != ACCESS_ONCE(t->nvcsw) || 453 t->rcu_tasks_nvcsw != ACCESS_ONCE(t->nvcsw) ||
@@ -454,7 +455,15 @@ static void check_holdout_task(struct task_struct *t)
454 ACCESS_ONCE(t->rcu_tasks_holdout) = false; 455 ACCESS_ONCE(t->rcu_tasks_holdout) = false;
455 list_del_rcu(&t->rcu_tasks_holdout_list); 456 list_del_rcu(&t->rcu_tasks_holdout_list);
456 put_task_struct(t); 457 put_task_struct(t);
458 return;
457 } 459 }
460 if (!needreport)
461 return;
462 if (*firstreport) {
463 pr_err("INFO: rcu_tasks detected stalls on tasks:\n");
464 *firstreport = false;
465 }
466 sched_show_task(t);
458} 467}
459 468
460/* RCU-tasks kthread that detects grace periods and invokes callbacks. */ 469/* RCU-tasks kthread that detects grace periods and invokes callbacks. */
@@ -462,6 +471,7 @@ static int __noreturn rcu_tasks_kthread(void *arg)
462{ 471{
463 unsigned long flags; 472 unsigned long flags;
464 struct task_struct *g, *t; 473 struct task_struct *g, *t;
474 unsigned long lastreport;
465 struct rcu_head *list; 475 struct rcu_head *list;
466 struct rcu_head *next; 476 struct rcu_head *next;
467 LIST_HEAD(rcu_tasks_holdouts); 477 LIST_HEAD(rcu_tasks_holdouts);
@@ -540,13 +550,24 @@ static int __noreturn rcu_tasks_kthread(void *arg)
540 * of holdout tasks, removing any that are no longer 550 * of holdout tasks, removing any that are no longer
541 * holdouts. When the list is empty, we are done. 551 * holdouts. When the list is empty, we are done.
542 */ 552 */
553 lastreport = jiffies;
543 while (!list_empty(&rcu_tasks_holdouts)) { 554 while (!list_empty(&rcu_tasks_holdouts)) {
555 bool firstreport;
556 bool needreport;
557 int rtst;
558
544 schedule_timeout_interruptible(HZ); 559 schedule_timeout_interruptible(HZ);
560 rtst = ACCESS_ONCE(rcu_task_stall_timeout);
561 needreport = rtst > 0 &&
562 time_after(jiffies, lastreport + rtst);
563 if (needreport)
564 lastreport = jiffies;
565 firstreport = true;
545 WARN_ON(signal_pending(current)); 566 WARN_ON(signal_pending(current));
546 rcu_read_lock(); 567 rcu_read_lock();
547 list_for_each_entry_rcu(t, &rcu_tasks_holdouts, 568 list_for_each_entry_rcu(t, &rcu_tasks_holdouts,
548 rcu_tasks_holdout_list) 569 rcu_tasks_holdout_list)
549 check_holdout_task(t); 570 check_holdout_task(t, needreport, &firstreport);
550 rcu_read_unlock(); 571 rcu_read_unlock();
551 } 572 }
552 573