rcu-tasks: Add detailed debugging facility to RCU Tasks Trace CPU stall warning
This is a debug-only commit, for the moment, anyway.
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index ca9db80..0e384df 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5030,6 +5030,10 @@
A change in value does not take effect until
the beginning of the next grace period.
+ rcupdate.rcu_task_trc_detail_stall= [KNL]
+ Print detailed per-task information prior to a
+ RCU Tasks Trace CPU stall warning.
+
rcupdate.rcu_self_test= [KNL]
Run the RCU early boot self tests
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 16a7981..912851c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -846,6 +846,7 @@ struct task_struct {
int trc_ipi_to_cpu;
union rcu_special trc_reader_special;
struct list_head trc_holdout_list;
+ bool trc_needreport;
#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
struct sched_info sched_info;
diff --git a/init/init_task.c b/init/init_task.c
index 73cc8f0..6d510da 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -157,6 +157,7 @@ struct task_struct init_task
.trc_reader_nesting = 0,
.trc_reader_special.s = 0,
.trc_holdout_list = LIST_HEAD_INIT(init_task.trc_holdout_list),
+ .trc_needreport = false,
#endif
#ifdef CONFIG_CPUSETS
.mems_allowed_seq = SEQCNT_SPINLOCK_ZERO(init_task.mems_allowed_seq,
diff --git a/kernel/fork.c b/kernel/fork.c
index 9796897..f563cef 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1811,6 +1811,7 @@ static inline void rcu_copy_process(struct task_struct *p)
p->trc_reader_nesting = 0;
p->trc_reader_special.s = 0;
INIT_LIST_HEAD(&p->trc_holdout_list);
+ p->trc_needreport = false;
#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
}
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index 09417fe..3f7601e 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -161,6 +161,9 @@ module_param(rcu_task_contend_lim, int, 0444);
static int rcu_task_collapse_lim __read_mostly = 10;
module_param(rcu_task_collapse_lim, int, 0444);
+static int rcu_task_trc_detail_stall;
+module_param(rcu_task_trc_detail_stall, int, 0644);
+
/* RCU tasks grace-period state for debugging. */
#define RTGS_INIT 0
#define RTGS_WAIT_WAIT_CBS 1
@@ -1377,11 +1380,16 @@ static void trc_wait_for_one_reader(struct task_struct *t,
int cpu;
// If a previous IPI is still in flight, let it complete.
- if (smp_load_acquire(&t->trc_ipi_to_cpu) != -1) // Order IPI
+ if (smp_load_acquire(&t->trc_ipi_to_cpu) != -1) { // Order IPI
+ if (READ_ONCE(t->trc_needreport))
+ pr_info("%s(P%d/%d) IPI to task still in flight.\n", __func__, t->pid, task_cpu(t));
return;
+ }
// The current task had better be in a quiescent state.
if (t == current) {
+ if (READ_ONCE(t->trc_needreport))
+ pr_info("%s(P%d/%d) is currently running task.\n", __func__, t->pid, task_cpu(t));
rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED);
WARN_ON_ONCE(READ_ONCE(t->trc_reader_nesting));
return;
@@ -1390,6 +1398,8 @@ static void trc_wait_for_one_reader(struct task_struct *t,
// Attempt to nail down the task for inspection.
get_task_struct(t);
if (!task_call_func(t, trc_inspect_reader, NULL)) {
+ if (READ_ONCE(t->trc_needreport))
+ pr_info("%s(P%d/%d) task_call_func() succeeded.\n", __func__, t->pid, task_cpu(t));
put_task_struct(t);
return;
}
@@ -1550,6 +1560,8 @@ static void check_all_holdout_tasks_trace(struct list_head *hop,
list_for_each_entry_safe(t, g, hop, trc_holdout_list) {
// If safe and needed, try to check the current task.
+ if (READ_ONCE(rcu_task_trc_detail_stall))
+ t->trc_needreport = needreport;
if (READ_ONCE(t->trc_ipi_to_cpu) == -1 &&
!(rcu_ld_need_qs(t) & TRC_NEED_QS_CHECKED))
trc_wait_for_one_reader(t, hop);
@@ -1560,6 +1572,7 @@ static void check_all_holdout_tasks_trace(struct list_head *hop,
trc_del_holdout(t);
else if (needreport)
show_stalled_task_trace(t, firstreport);
+ t->trc_needreport = false;
}
// Re-enable CPU hotplug now that the holdout list scan has completed.