diff options
-rw-r--r-- | kernel/rcu/tree.c | 26 | ||||
-rw-r--r-- | kernel/rcu/tree.h | 2 |
2 files changed, 27 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 | /* |
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 52be957c9fe2..8e34d8674a4e 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h | |||
@@ -453,6 +453,8 @@ struct rcu_state { | |||
453 | /* but in jiffies. */ | 453 | /* but in jiffies. */ |
454 | unsigned long jiffies_stall; /* Time at which to check */ | 454 | unsigned long jiffies_stall; /* Time at which to check */ |
455 | /* for CPU stalls. */ | 455 | /* for CPU stalls. */ |
456 | unsigned long jiffies_resched; /* Time at which to resched */ | ||
457 | /* a reluctant CPU. */ | ||
456 | unsigned long gp_max; /* Maximum GP duration in */ | 458 | unsigned long gp_max; /* Maximum GP duration in */ |
457 | /* jiffies. */ | 459 | /* jiffies. */ |
458 | const char *name; /* Name of structure. */ | 460 | const char *name; /* Name of structure. */ |