aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/rcu/tree.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 7f73c5edf8cf..9e3c20f117cd 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -2950,6 +2950,9 @@ static int synchronize_sched_expedited_cpu_stop(void *data)
2950 */ 2950 */
2951void synchronize_sched_expedited(void) 2951void synchronize_sched_expedited(void)
2952{ 2952{
2953 cpumask_var_t cm;
2954 bool cma = false;
2955 int cpu;
2953 long firstsnap, s, snap; 2956 long firstsnap, s, snap;
2954 int trycount = 0; 2957 int trycount = 0;
2955 struct rcu_state *rsp = &rcu_sched_state; 2958 struct rcu_state *rsp = &rcu_sched_state;
@@ -2984,11 +2987,26 @@ void synchronize_sched_expedited(void)
2984 } 2987 }
2985 WARN_ON_ONCE(cpu_is_offline(raw_smp_processor_id())); 2988 WARN_ON_ONCE(cpu_is_offline(raw_smp_processor_id()));
2986 2989
2990 /* Offline CPUs, idle CPUs, and any CPU we run on are quiescent. */
2991 cma = zalloc_cpumask_var(&cm, GFP_KERNEL);
2992 if (cma) {
2993 cpumask_copy(cm, cpu_online_mask);
2994 cpumask_clear_cpu(raw_smp_processor_id(), cm);
2995 for_each_cpu(cpu, cm) {
2996 struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
2997
2998 if (!(atomic_add_return(0, &rdtp->dynticks) & 0x1))
2999 cpumask_clear_cpu(cpu, cm);
3000 }
3001 if (cpumask_weight(cm) == 0)
3002 goto all_cpus_idle;
3003 }
3004
2987 /* 3005 /*
2988 * Each pass through the following loop attempts to force a 3006 * Each pass through the following loop attempts to force a
2989 * context switch on each CPU. 3007 * context switch on each CPU.
2990 */ 3008 */
2991 while (try_stop_cpus(cpu_online_mask, 3009 while (try_stop_cpus(cma ? cm : cpu_online_mask,
2992 synchronize_sched_expedited_cpu_stop, 3010 synchronize_sched_expedited_cpu_stop,
2993 NULL) == -EAGAIN) { 3011 NULL) == -EAGAIN) {
2994 put_online_cpus(); 3012 put_online_cpus();
@@ -3000,6 +3018,7 @@ void synchronize_sched_expedited(void)
3000 /* ensure test happens before caller kfree */ 3018 /* ensure test happens before caller kfree */
3001 smp_mb__before_atomic(); /* ^^^ */ 3019 smp_mb__before_atomic(); /* ^^^ */
3002 atomic_long_inc(&rsp->expedited_workdone1); 3020 atomic_long_inc(&rsp->expedited_workdone1);
3021 free_cpumask_var(cm);
3003 return; 3022 return;
3004 } 3023 }
3005 3024
@@ -3009,6 +3028,7 @@ void synchronize_sched_expedited(void)
3009 } else { 3028 } else {
3010 wait_rcu_gp(call_rcu_sched); 3029 wait_rcu_gp(call_rcu_sched);
3011 atomic_long_inc(&rsp->expedited_normal); 3030 atomic_long_inc(&rsp->expedited_normal);
3031 free_cpumask_var(cm);
3012 return; 3032 return;
3013 } 3033 }
3014 3034
@@ -3018,6 +3038,7 @@ void synchronize_sched_expedited(void)
3018 /* ensure test happens before caller kfree */ 3038 /* ensure test happens before caller kfree */
3019 smp_mb__before_atomic(); /* ^^^ */ 3039 smp_mb__before_atomic(); /* ^^^ */
3020 atomic_long_inc(&rsp->expedited_workdone2); 3040 atomic_long_inc(&rsp->expedited_workdone2);
3041 free_cpumask_var(cm);
3021 return; 3042 return;
3022 } 3043 }
3023 3044
@@ -3032,6 +3053,7 @@ void synchronize_sched_expedited(void)
3032 /* CPU hotplug operation in flight, use normal GP. */ 3053 /* CPU hotplug operation in flight, use normal GP. */
3033 wait_rcu_gp(call_rcu_sched); 3054 wait_rcu_gp(call_rcu_sched);
3034 atomic_long_inc(&rsp->expedited_normal); 3055 atomic_long_inc(&rsp->expedited_normal);
3056 free_cpumask_var(cm);
3035 return; 3057 return;
3036 } 3058 }
3037 snap = atomic_long_read(&rsp->expedited_start); 3059 snap = atomic_long_read(&rsp->expedited_start);
@@ -3039,6 +3061,9 @@ void synchronize_sched_expedited(void)
3039 } 3061 }
3040 atomic_long_inc(&rsp->expedited_stoppedcpus); 3062 atomic_long_inc(&rsp->expedited_stoppedcpus);
3041 3063
3064all_cpus_idle:
3065 free_cpumask_var(cm);
3066
3042 /* 3067 /*
3043 * Everyone up to our most recent fetch is covered by our grace 3068 * Everyone up to our most recent fetch is covered by our grace
3044 * period. Update the counter, but only if our work is still 3069 * period. Update the counter, but only if our work is still