Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rcu: Avoid IPIing idle CPUs from synchronize_sched_expedited()

Currently, synchronize_sched_expedited() sends IPIs to all online CPUs,
even those that are idle or executing in nohz_full= userspace. Because
idle CPUs and nohz_full= userspace CPUs are in extended quiescent states,
there is no need to IPI them in the first place. This commit therefore
avoids IPIing CPUs that are already in extended quiescent states.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

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