Skip to content

Commit c951587

Browse files
qiangzh3paulmckrcu
authored andcommitted
rcu: Add per-CPU rcuc task dumps to RCU CPU stall warnings
When the rcutree.use_softirq kernel boot parameter is set to zero, all RCU_SOFTIRQ processing is carried out by the per-CPU rcuc kthreads. If these kthreads are being starved, quiescent states will not be reported, which in turn means that the grace period will not end, which can in turn trigger RCU CPU stall warnings. This commit therefore dumps stack traces of stalled CPUs' rcuc kthreads, which can help identify what is preventing those kthreads from running. Suggested-by: Ammar Faizi <ammarfaizi2@gnuweeb.org> Reviewed-by: Ammar Faizi <ammarfaizi2@gnuweeb.org> Signed-off-by: Zqiang <qiang1.zhang@intel.com> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent 10c5357 commit c951587

File tree

4 files changed

+42
-0
lines changed

4 files changed

+42
-0
lines changed

kernel/rcu/tree.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,10 +2850,12 @@ static void rcu_cpu_kthread(unsigned int cpu)
28502850
{
28512851
unsigned int *statusp = this_cpu_ptr(&rcu_data.rcu_cpu_kthread_status);
28522852
char work, *workp = this_cpu_ptr(&rcu_data.rcu_cpu_has_work);
2853+
unsigned long *j = this_cpu_ptr(&rcu_data.rcuc_activity);
28532854
int spincnt;
28542855

28552856
trace_rcu_utilization(TPS("Start CPU kthread@rcu_run"));
28562857
for (spincnt = 0; spincnt < 10; spincnt++) {
2858+
WRITE_ONCE(*j, jiffies);
28572859
local_bh_disable();
28582860
*statusp = RCU_KTHREAD_RUNNING;
28592861
local_irq_disable();
@@ -2874,6 +2876,7 @@ static void rcu_cpu_kthread(unsigned int cpu)
28742876
schedule_timeout_idle(2);
28752877
trace_rcu_utilization(TPS("End CPU kthread@rcu_yield"));
28762878
*statusp = RCU_KTHREAD_WAITING;
2879+
WRITE_ONCE(*j, jiffies);
28772880
}
28782881

28792882
static struct smp_hotplug_thread rcu_cpu_thread_spec = {

kernel/rcu/tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ struct rcu_data {
239239
/* rcuc per-CPU kthread or NULL. */
240240
unsigned int rcu_cpu_kthread_status;
241241
char rcu_cpu_has_work;
242+
unsigned long rcuc_activity;
242243

243244
/* 7) Diagnostic data, including RCU CPU stall warnings. */
244245
unsigned int softirq_snap; /* Snapshot of softirq activity. */

kernel/rcu/tree_plugin.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,12 +996,15 @@ dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
996996
*/
997997
static void rcu_cpu_kthread_setup(unsigned int cpu)
998998
{
999+
struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
9991000
#ifdef CONFIG_RCU_BOOST
10001001
struct sched_param sp;
10011002

10021003
sp.sched_priority = kthread_prio;
10031004
sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
10041005
#endif /* #ifdef CONFIG_RCU_BOOST */
1006+
1007+
WRITE_ONCE(rdp->rcuc_activity, jiffies);
10051008
}
10061009

10071010
#ifdef CONFIG_RCU_BOOST

kernel/rcu/tree_stall.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,15 @@ static bool rcu_is_gp_kthread_starving(unsigned long *jp)
379379
return j > 2 * HZ;
380380
}
381381

382+
static bool rcu_is_rcuc_kthread_starving(struct rcu_data *rdp, unsigned long *jp)
383+
{
384+
unsigned long j = jiffies - READ_ONCE(rdp->rcuc_activity);
385+
386+
if (jp)
387+
*jp = j;
388+
return j > 2 * HZ;
389+
}
390+
382391
/*
383392
* Print out diagnostic information for the specified stalled CPU.
384393
*
@@ -430,6 +439,29 @@ static void print_cpu_stall_info(int cpu)
430439
falsepositive ? " (false positive?)" : "");
431440
}
432441

442+
static void rcuc_kthread_dump(struct rcu_data *rdp)
443+
{
444+
int cpu;
445+
unsigned long j;
446+
struct task_struct *rcuc;
447+
448+
rcuc = rdp->rcu_cpu_kthread_task;
449+
if (!rcuc)
450+
return;
451+
452+
cpu = task_cpu(rcuc);
453+
if (cpu_is_offline(cpu) || idle_cpu(cpu))
454+
return;
455+
456+
if (!rcu_is_rcuc_kthread_starving(rdp, &j))
457+
return;
458+
459+
pr_err("%s kthread starved for %ld jiffies\n", rcuc->comm, j);
460+
sched_show_task(rcuc);
461+
if (!trigger_single_cpu_backtrace(cpu))
462+
dump_cpu_task(cpu);
463+
}
464+
433465
/* Complain about starvation of grace-period kthread. */
434466
static void rcu_check_gp_kthread_starvation(void)
435467
{
@@ -601,6 +633,9 @@ static void print_cpu_stall(unsigned long gps)
601633
rcu_check_gp_kthread_expired_fqs_timer();
602634
rcu_check_gp_kthread_starvation();
603635

636+
if (!use_softirq)
637+
rcuc_kthread_dump(rdp);
638+
604639
rcu_dump_cpu_stacks();
605640

606641
raw_spin_lock_irqsave_rcu_node(rnp, flags);

0 commit comments

Comments
 (0)