aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2011-03-29 20:48:28 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-05-06 02:16:56 -0400
commitd71df90eadfc35aa549ff9a850842673febca71f (patch)
treedd275a3f4848784bc6625574341c11befc1b3823 /kernel
parent0ac3d136b2e3cdf1161178223bc5da14a06241d0 (diff)
rcu: add tracing for RCU's kthread run states.
Add tracing to help debugging situations when RCU's kthreads are not running but are supposed to be. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/rcutree.c11
-rw-r--r--kernel/rcutree.h11
-rw-r--r--kernel/rcutree_plugin.h3
-rw-r--r--kernel/rcutree_trace.c23
4 files changed, 44 insertions, 4 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 198e4df7d83e..d8917401cbbc 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -91,8 +91,9 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active);
91 * handle all flavors of RCU. 91 * handle all flavors of RCU.
92 */ 92 */
93static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task); 93static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
94DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
94static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq); 95static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq);
95static DEFINE_PER_CPU(char, rcu_cpu_has_work); 96DEFINE_PER_CPU(char, rcu_cpu_has_work);
96static char rcu_kthreads_spawnable; 97static char rcu_kthreads_spawnable;
97 98
98static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu); 99static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
@@ -1563,11 +1564,13 @@ static int rcu_cpu_kthread(void *arg)
1563 int cpu = (int)(long)arg; 1564 int cpu = (int)(long)arg;
1564 unsigned long flags; 1565 unsigned long flags;
1565 int spincnt = 0; 1566 int spincnt = 0;
1567 unsigned int *statusp = &per_cpu(rcu_cpu_kthread_status, cpu);
1566 wait_queue_head_t *wqp = &per_cpu(rcu_cpu_wq, cpu); 1568 wait_queue_head_t *wqp = &per_cpu(rcu_cpu_wq, cpu);
1567 char work; 1569 char work;
1568 char *workp = &per_cpu(rcu_cpu_has_work, cpu); 1570 char *workp = &per_cpu(rcu_cpu_has_work, cpu);
1569 1571
1570 for (;;) { 1572 for (;;) {
1573 *statusp = RCU_KTHREAD_WAITING;
1571 wait_event_interruptible(*wqp, 1574 wait_event_interruptible(*wqp,
1572 *workp != 0 || kthread_should_stop()); 1575 *workp != 0 || kthread_should_stop());
1573 local_bh_disable(); 1576 local_bh_disable();
@@ -1575,6 +1578,7 @@ static int rcu_cpu_kthread(void *arg)
1575 local_bh_enable(); 1578 local_bh_enable();
1576 break; 1579 break;
1577 } 1580 }
1581 *statusp = RCU_KTHREAD_RUNNING;
1578 local_irq_save(flags); 1582 local_irq_save(flags);
1579 work = *workp; 1583 work = *workp;
1580 *workp = 0; 1584 *workp = 0;
@@ -1587,10 +1591,12 @@ static int rcu_cpu_kthread(void *arg)
1587 else 1591 else
1588 spincnt = 0; 1592 spincnt = 0;
1589 if (spincnt > 10) { 1593 if (spincnt > 10) {
1594 *statusp = RCU_KTHREAD_YIELDING;
1590 rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu); 1595 rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu);
1591 spincnt = 0; 1596 spincnt = 0;
1592 } 1597 }
1593 } 1598 }
1599 *statusp = RCU_KTHREAD_STOPPED;
1594 return 0; 1600 return 0;
1595} 1601}
1596 1602
@@ -1637,10 +1643,12 @@ static int rcu_node_kthread(void *arg)
1637 struct task_struct *t; 1643 struct task_struct *t;
1638 1644
1639 for (;;) { 1645 for (;;) {
1646 rnp->node_kthread_status = RCU_KTHREAD_WAITING;
1640 wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0 || 1647 wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0 ||
1641 kthread_should_stop()); 1648 kthread_should_stop());
1642 if (kthread_should_stop()) 1649 if (kthread_should_stop())
1643 break; 1650 break;
1651 rnp->node_kthread_status = RCU_KTHREAD_RUNNING;
1644 raw_spin_lock_irqsave(&rnp->lock, flags); 1652 raw_spin_lock_irqsave(&rnp->lock, flags);
1645 mask = rnp->wakemask; 1653 mask = rnp->wakemask;
1646 rnp->wakemask = 0; 1654 rnp->wakemask = 0;
@@ -1661,6 +1669,7 @@ static int rcu_node_kthread(void *arg)
1661 preempt_enable(); 1669 preempt_enable();
1662 } 1670 }
1663 } 1671 }
1672 rnp->node_kthread_status = RCU_KTHREAD_STOPPED;
1664 return 0; 1673 return 0;
1665} 1674}
1666 1675
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index d49046c79c59..67341dbebd95 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -89,6 +89,13 @@ struct rcu_dynticks {
89 atomic_t dynticks; /* Even value for dynticks-idle, else odd. */ 89 atomic_t dynticks; /* Even value for dynticks-idle, else odd. */
90}; 90};
91 91
92/* RCU's kthread states for tracing. */
93#define RCU_KTHREAD_STOPPED 0
94#define RCU_KTHREAD_RUNNING 1
95#define RCU_KTHREAD_WAITING 2
96#define RCU_KTHREAD_YIELDING 3
97#define RCU_KTHREAD_MAX 3
98
92/* 99/*
93 * Definition for node within the RCU grace-period-detection hierarchy. 100 * Definition for node within the RCU grace-period-detection hierarchy.
94 */ 101 */
@@ -152,6 +159,8 @@ struct rcu_node {
152 wait_queue_head_t boost_wq; 159 wait_queue_head_t boost_wq;
153 /* Wait queue on which to park the boost */ 160 /* Wait queue on which to park the boost */
154 /* kthread. */ 161 /* kthread. */
162 unsigned int boost_kthread_status;
163 /* State of boost_kthread_task for tracing. */
155 unsigned long n_tasks_boosted; 164 unsigned long n_tasks_boosted;
156 /* Total number of tasks boosted. */ 165 /* Total number of tasks boosted. */
157 unsigned long n_exp_boosts; 166 unsigned long n_exp_boosts;
@@ -179,6 +188,8 @@ struct rcu_node {
179 wait_queue_head_t node_wq; 188 wait_queue_head_t node_wq;
180 /* Wait queue on which to park the per-node */ 189 /* Wait queue on which to park the per-node */
181 /* kthread. */ 190 /* kthread. */
191 unsigned int node_kthread_status;
192 /* State of node_kthread_task for tracing. */
182} ____cacheline_internodealigned_in_smp; 193} ____cacheline_internodealigned_in_smp;
183 194
184/* 195/*
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 07d346445d12..22a6a46de7c6 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -1198,11 +1198,13 @@ static int rcu_boost_kthread(void *arg)
1198 int more2boost; 1198 int more2boost;
1199 1199
1200 for (;;) { 1200 for (;;) {
1201 rnp->boost_kthread_status = RCU_KTHREAD_WAITING;
1201 wait_event_interruptible(rnp->boost_wq, rnp->boost_tasks || 1202 wait_event_interruptible(rnp->boost_wq, rnp->boost_tasks ||
1202 rnp->exp_tasks || 1203 rnp->exp_tasks ||
1203 kthread_should_stop()); 1204 kthread_should_stop());
1204 if (kthread_should_stop()) 1205 if (kthread_should_stop())
1205 break; 1206 break;
1207 rnp->boost_kthread_status = RCU_KTHREAD_RUNNING;
1206 more2boost = rcu_boost(rnp); 1208 more2boost = rcu_boost(rnp);
1207 if (more2boost) 1209 if (more2boost)
1208 spincnt++; 1210 spincnt++;
@@ -1213,6 +1215,7 @@ static int rcu_boost_kthread(void *arg)
1213 spincnt = 0; 1215 spincnt = 0;
1214 } 1216 }
1215 } 1217 }
1218 rnp->boost_kthread_status = RCU_KTHREAD_STOPPED;
1216 return 0; 1219 return 0;
1217} 1220}
1218 1221
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index afd262f91262..fc40e89a028c 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -46,6 +46,16 @@
46#define RCU_TREE_NONCORE 46#define RCU_TREE_NONCORE
47#include "rcutree.h" 47#include "rcutree.h"
48 48
49DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
50DECLARE_PER_CPU(char, rcu_cpu_has_work);
51
52static char convert_kthread_status(unsigned int kthread_status)
53{
54 if (kthread_status > RCU_KTHREAD_MAX)
55 return '?';
56 return "SRWY"[kthread_status];
57}
58
49static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) 59static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
50{ 60{
51 if (!rdp->beenonline) 61 if (!rdp->beenonline)
@@ -64,7 +74,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
64 rdp->dynticks_fqs); 74 rdp->dynticks_fqs);
65#endif /* #ifdef CONFIG_NO_HZ */ 75#endif /* #ifdef CONFIG_NO_HZ */
66 seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); 76 seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
67 seq_printf(m, " ql=%ld qs=%c%c%c%c b=%ld", 77 seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c b=%ld",
68 rdp->qlen, 78 rdp->qlen,
69 ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != 79 ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
70 rdp->nxttail[RCU_NEXT_TAIL]], 80 rdp->nxttail[RCU_NEXT_TAIL]],
@@ -73,6 +83,9 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
73 ".W"[rdp->nxttail[RCU_DONE_TAIL] != 83 ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
74 rdp->nxttail[RCU_WAIT_TAIL]], 84 rdp->nxttail[RCU_WAIT_TAIL]],
75 ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]], 85 ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]],
86 per_cpu(rcu_cpu_has_work, rdp->cpu),
87 convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
88 rdp->cpu)),
76 rdp->blimit); 89 rdp->blimit);
77 seq_printf(m, " ci=%lu co=%lu ca=%lu\n", 90 seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
78 rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); 91 rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
@@ -130,7 +143,7 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
130 rdp->dynticks_fqs); 143 rdp->dynticks_fqs);
131#endif /* #ifdef CONFIG_NO_HZ */ 144#endif /* #ifdef CONFIG_NO_HZ */
132 seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); 145 seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
133 seq_printf(m, ",%ld,\"%c%c%c%c\",%ld", rdp->qlen, 146 seq_printf(m, ",%ld,\"%c%c%c%c\",%d,\"%c\",%ld", rdp->qlen,
134 ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != 147 ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
135 rdp->nxttail[RCU_NEXT_TAIL]], 148 rdp->nxttail[RCU_NEXT_TAIL]],
136 ".R"[rdp->nxttail[RCU_WAIT_TAIL] != 149 ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
@@ -138,6 +151,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
138 ".W"[rdp->nxttail[RCU_DONE_TAIL] != 151 ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
139 rdp->nxttail[RCU_WAIT_TAIL]], 152 rdp->nxttail[RCU_WAIT_TAIL]],
140 ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]], 153 ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]],
154 per_cpu(rcu_cpu_has_work, rdp->cpu),
155 convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
156 rdp->cpu)),
141 rdp->blimit); 157 rdp->blimit);
142 seq_printf(m, ",%lu,%lu,%lu\n", 158 seq_printf(m, ",%lu,%lu,%lu\n",
143 rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); 159 rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
@@ -178,13 +194,14 @@ static const struct file_operations rcudata_csv_fops = {
178 194
179static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp) 195static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp)
180{ 196{
181 seq_printf(m, "%d:%d tasks=%c%c%c%c ntb=%lu neb=%lu nnb=%lu " 197 seq_printf(m, "%d:%d tasks=%c%c%c%c kt=%c ntb=%lu neb=%lu nnb=%lu "
182 "j=%04x bt=%04x\n", 198 "j=%04x bt=%04x\n",
183 rnp->grplo, rnp->grphi, 199 rnp->grplo, rnp->grphi,
184 "T."[list_empty(&rnp->blkd_tasks)], 200 "T."[list_empty(&rnp->blkd_tasks)],
185 "N."[!rnp->gp_tasks], 201 "N."[!rnp->gp_tasks],
186 "E."[!rnp->exp_tasks], 202 "E."[!rnp->exp_tasks],
187 "B."[!rnp->boost_tasks], 203 "B."[!rnp->boost_tasks],
204 convert_kthread_status(rnp->boost_kthread_status),
188 rnp->n_tasks_boosted, rnp->n_exp_boosts, 205 rnp->n_tasks_boosted, rnp->n_exp_boosts,
189 rnp->n_normal_boosts, 206 rnp->n_normal_boosts,
190 (int)(jiffies & 0xffff), 207 (int)(jiffies & 0xffff),