aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/RCU/stallwarn.txt5
-rw-r--r--kernel/rcu/tree.c32
-rw-r--r--kernel/rcu/tree.h2
3 files changed, 34 insertions, 5 deletions
diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt
index ed186a902d31..55f9707fe60a 100644
--- a/Documentation/RCU/stallwarn.txt
+++ b/Documentation/RCU/stallwarn.txt
@@ -187,6 +187,11 @@ o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the
187 behavior, you might need to replace some of the cond_resched() 187 behavior, you might need to replace some of the cond_resched()
188 calls with calls to cond_resched_rcu_qs(). 188 calls with calls to cond_resched_rcu_qs().
189 189
190o Anything that prevents RCU's grace-period kthreads from running.
191 This can result in the "All QSes seen" console-log message.
192 This message will include information on when the kthread last
193 ran and how often it should be expected to run.
194
190o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might 195o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might
191 happen to preempt a low-priority task in the middle of an RCU 196 happen to preempt a low-priority task in the middle of an RCU
192 read-side critical section. This is especially damaging if 197 read-side critical section. This is especially damaging if
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 654b15be1e36..a2ceb66bcd67 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1066,11 +1066,13 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp)
1066 } 1066 }
1067} 1067}
1068 1068
1069static void print_other_cpu_stall(struct rcu_state *rsp) 1069static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum)
1070{ 1070{
1071 int cpu; 1071 int cpu;
1072 long delta; 1072 long delta;
1073 unsigned long flags; 1073 unsigned long flags;
1074 unsigned long gpa;
1075 unsigned long j;
1074 int ndetected = 0; 1076 int ndetected = 0;
1075 struct rcu_node *rnp = rcu_get_root(rsp); 1077 struct rcu_node *rnp = rcu_get_root(rsp);
1076 long totqlen = 0; 1078 long totqlen = 0;
@@ -1123,10 +1125,22 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
1123 pr_cont("(detected by %d, t=%ld jiffies, g=%ld, c=%ld, q=%lu)\n", 1125 pr_cont("(detected by %d, t=%ld jiffies, g=%ld, c=%ld, q=%lu)\n",
1124 smp_processor_id(), (long)(jiffies - rsp->gp_start), 1126 smp_processor_id(), (long)(jiffies - rsp->gp_start),
1125 (long)rsp->gpnum, (long)rsp->completed, totqlen); 1127 (long)rsp->gpnum, (long)rsp->completed, totqlen);
1126 if (ndetected == 0) 1128 if (ndetected) {
1127 pr_err("INFO: Stall ended before state dump start\n");
1128 else
1129 rcu_dump_cpu_stacks(rsp); 1129 rcu_dump_cpu_stacks(rsp);
1130 } else {
1131 if (ACCESS_ONCE(rsp->gpnum) != gpnum ||
1132 ACCESS_ONCE(rsp->completed) == gpnum) {
1133 pr_err("INFO: Stall ended before state dump start\n");
1134 } else {
1135 j = jiffies;
1136 gpa = ACCESS_ONCE(rsp->gp_activity);
1137 pr_err("All QSes seen, last %s kthread activity %ld (%ld-%ld), jiffies_till_next_fqs=%ld\n",
1138 rsp->name, j - gpa, j, gpa,
1139 jiffies_till_next_fqs);
1140 /* In this case, the current CPU might be at fault. */
1141 sched_show_task(current);
1142 }
1143 }
1130 1144
1131 /* Complain about tasks blocking the grace period. */ 1145 /* Complain about tasks blocking the grace period. */
1132 1146
@@ -1226,7 +1240,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
1226 ULONG_CMP_GE(j, js + RCU_STALL_RAT_DELAY)) { 1240 ULONG_CMP_GE(j, js + RCU_STALL_RAT_DELAY)) {
1227 1241
1228 /* They had a few time units to dump stack, so complain. */ 1242 /* They had a few time units to dump stack, so complain. */
1229 print_other_cpu_stall(rsp); 1243 print_other_cpu_stall(rsp, gpnum);
1230 } 1244 }
1231} 1245}
1232 1246
@@ -1622,6 +1636,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
1622 struct rcu_data *rdp; 1636 struct rcu_data *rdp;
1623 struct rcu_node *rnp = rcu_get_root(rsp); 1637 struct rcu_node *rnp = rcu_get_root(rsp);
1624 1638
1639 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1625 rcu_bind_gp_kthread(); 1640 rcu_bind_gp_kthread();
1626 raw_spin_lock_irq(&rnp->lock); 1641 raw_spin_lock_irq(&rnp->lock);
1627 smp_mb__after_unlock_lock(); 1642 smp_mb__after_unlock_lock();
@@ -1682,6 +1697,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
1682 rnp->grphi, rnp->qsmask); 1697 rnp->grphi, rnp->qsmask);
1683 raw_spin_unlock_irq(&rnp->lock); 1698 raw_spin_unlock_irq(&rnp->lock);
1684 cond_resched_rcu_qs(); 1699 cond_resched_rcu_qs();
1700 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1685 } 1701 }
1686 1702
1687 mutex_unlock(&rsp->onoff_mutex); 1703 mutex_unlock(&rsp->onoff_mutex);
@@ -1698,6 +1714,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
1698 unsigned long maxj; 1714 unsigned long maxj;
1699 struct rcu_node *rnp = rcu_get_root(rsp); 1715 struct rcu_node *rnp = rcu_get_root(rsp);
1700 1716
1717 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1701 rsp->n_force_qs++; 1718 rsp->n_force_qs++;
1702 if (fqs_state == RCU_SAVE_DYNTICK) { 1719 if (fqs_state == RCU_SAVE_DYNTICK) {
1703 /* Collect dyntick-idle snapshots. */ 1720 /* Collect dyntick-idle snapshots. */
@@ -1736,6 +1753,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
1736 struct rcu_data *rdp; 1753 struct rcu_data *rdp;
1737 struct rcu_node *rnp = rcu_get_root(rsp); 1754 struct rcu_node *rnp = rcu_get_root(rsp);
1738 1755
1756 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1739 raw_spin_lock_irq(&rnp->lock); 1757 raw_spin_lock_irq(&rnp->lock);
1740 smp_mb__after_unlock_lock(); 1758 smp_mb__after_unlock_lock();
1741 gp_duration = jiffies - rsp->gp_start; 1759 gp_duration = jiffies - rsp->gp_start;
@@ -1772,6 +1790,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
1772 nocb += rcu_future_gp_cleanup(rsp, rnp); 1790 nocb += rcu_future_gp_cleanup(rsp, rnp);
1773 raw_spin_unlock_irq(&rnp->lock); 1791 raw_spin_unlock_irq(&rnp->lock);
1774 cond_resched_rcu_qs(); 1792 cond_resched_rcu_qs();
1793 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1775 } 1794 }
1776 rnp = rcu_get_root(rsp); 1795 rnp = rcu_get_root(rsp);
1777 raw_spin_lock_irq(&rnp->lock); 1796 raw_spin_lock_irq(&rnp->lock);
@@ -1821,6 +1840,7 @@ static int __noreturn rcu_gp_kthread(void *arg)
1821 if (rcu_gp_init(rsp)) 1840 if (rcu_gp_init(rsp))
1822 break; 1841 break;
1823 cond_resched_rcu_qs(); 1842 cond_resched_rcu_qs();
1843 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1824 WARN_ON(signal_pending(current)); 1844 WARN_ON(signal_pending(current));
1825 trace_rcu_grace_period(rsp->name, 1845 trace_rcu_grace_period(rsp->name,
1826 ACCESS_ONCE(rsp->gpnum), 1846 ACCESS_ONCE(rsp->gpnum),
@@ -1864,9 +1884,11 @@ static int __noreturn rcu_gp_kthread(void *arg)
1864 ACCESS_ONCE(rsp->gpnum), 1884 ACCESS_ONCE(rsp->gpnum),
1865 TPS("fqsend")); 1885 TPS("fqsend"));
1866 cond_resched_rcu_qs(); 1886 cond_resched_rcu_qs();
1887 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1867 } else { 1888 } else {
1868 /* Deal with stray signal. */ 1889 /* Deal with stray signal. */
1869 cond_resched_rcu_qs(); 1890 cond_resched_rcu_qs();
1891 ACCESS_ONCE(rsp->gp_activity) = jiffies;
1870 WARN_ON(signal_pending(current)); 1892 WARN_ON(signal_pending(current));
1871 trace_rcu_grace_period(rsp->name, 1893 trace_rcu_grace_period(rsp->name,
1872 ACCESS_ONCE(rsp->gpnum), 1894 ACCESS_ONCE(rsp->gpnum),
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index e300848cc0cf..5ec81cf938fd 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -488,6 +488,8 @@ struct rcu_state {
488 /* due to no GP active. */ 488 /* due to no GP active. */
489 unsigned long gp_start; /* Time at which GP started, */ 489 unsigned long gp_start; /* Time at which GP started, */
490 /* but in jiffies. */ 490 /* but in jiffies. */
491 unsigned long gp_activity; /* Time of last GP kthread */
492 /* activity in jiffies. */
491 unsigned long jiffies_stall; /* Time at which to check */ 493 unsigned long jiffies_stall; /* Time at which to check */
492 /* for CPU stalls. */ 494 /* for CPU stalls. */
493 unsigned long jiffies_resched; /* Time at which to resched */ 495 unsigned long jiffies_resched; /* Time at which to resched */