diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-09-23 16:57:18 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-12-03 13:10:18 -0500 |
commit | 6193c76aba8ec3cc5f083c35efbab9ed924125f6 (patch) | |
tree | ff0d5698840948f5aef0fab9e7949d47a5d52ff4 /kernel/rcu/tree.c | |
parent | dc1ccc48159d63eca5089e507c82c7d22ef60839 (diff) |
rcu: Kick CPU halfway to RCU CPU stall warning
When an RCU CPU stall warning occurs, the CPU invokes resched_cpu() on
itself. This can help move the grace period forward in some situations,
but it would be even better to do this -before- the RCU CPU stall warning.
This commit therefore causes resched_cpu() to be called every five jiffies
once the system is halfway to an RCU CPU stall warning.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcu/tree.c')
-rw-r--r-- | kernel/rcu/tree.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index dd081987a8ec..5243ebea0fc1 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -755,6 +755,12 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp, | |||
755 | } | 755 | } |
756 | 756 | ||
757 | /* | 757 | /* |
758 | * This function really isn't for public consumption, but RCU is special in | ||
759 | * that context switches can allow the state machine to make progress. | ||
760 | */ | ||
761 | extern void resched_cpu(int cpu); | ||
762 | |||
763 | /* | ||
758 | * Return true if the specified CPU has passed through a quiescent | 764 | * Return true if the specified CPU has passed through a quiescent |
759 | * state by virtue of being in or having passed through an dynticks | 765 | * state by virtue of being in or having passed through an dynticks |
760 | * idle state since the last call to dyntick_save_progress_counter() | 766 | * idle state since the last call to dyntick_save_progress_counter() |
@@ -812,16 +818,34 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, | |||
812 | */ | 818 | */ |
813 | rcu_kick_nohz_cpu(rdp->cpu); | 819 | rcu_kick_nohz_cpu(rdp->cpu); |
814 | 820 | ||
821 | /* | ||
822 | * Alternatively, the CPU might be running in the kernel | ||
823 | * for an extended period of time without a quiescent state. | ||
824 | * Attempt to force the CPU through the scheduler to gain the | ||
825 | * needed quiescent state, but only if the grace period has gone | ||
826 | * on for an uncommonly long time. If there are many stuck CPUs, | ||
827 | * we will beat on the first one until it gets unstuck, then move | ||
828 | * to the next. Only do this for the primary flavor of RCU. | ||
829 | */ | ||
830 | if (rdp->rsp == rcu_state && | ||
831 | ULONG_CMP_GE(ACCESS_ONCE(jiffies), rdp->rsp->jiffies_resched)) { | ||
832 | rdp->rsp->jiffies_resched += 5; | ||
833 | resched_cpu(rdp->cpu); | ||
834 | } | ||
835 | |||
815 | return 0; | 836 | return 0; |
816 | } | 837 | } |
817 | 838 | ||
818 | static void record_gp_stall_check_time(struct rcu_state *rsp) | 839 | static void record_gp_stall_check_time(struct rcu_state *rsp) |
819 | { | 840 | { |
820 | unsigned long j = ACCESS_ONCE(jiffies); | 841 | unsigned long j = ACCESS_ONCE(jiffies); |
842 | unsigned long j1; | ||
821 | 843 | ||
822 | rsp->gp_start = j; | 844 | rsp->gp_start = j; |
823 | smp_wmb(); /* Record start time before stall time. */ | 845 | smp_wmb(); /* Record start time before stall time. */ |
824 | rsp->jiffies_stall = j + rcu_jiffies_till_stall_check(); | 846 | j1 = rcu_jiffies_till_stall_check(); |
847 | rsp->jiffies_stall = j + j1; | ||
848 | rsp->jiffies_resched = j + j1 / 2; | ||
825 | } | 849 | } |
826 | 850 | ||
827 | /* | 851 | /* |