When per_cpu_ptr() is used, the caller should have preemption disabled, as otherwise the pointer is meaningless. If the user wants an "unstable" pointer he should call raw_cpu_ptr().
Add an assertion to check that indeed preemption is disabled, and distinguish between the two cases to allow further, per-arch optimizations. Signed-off-by: Nadav Amit <na...@vmware.com> --- include/asm-generic/percpu.h | 12 ++++++++++++ include/linux/percpu-defs.h | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index c2de013b2cf4..7853605f4210 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -36,6 +36,14 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; #define my_cpu_offset __my_cpu_offset #endif +/* + * Determine the offset of the current active processor when preemption is + * disabled. Can be overriden by arch code. + */ +#ifndef __raw_my_cpu_offset +#define __raw_my_cpu_offset __my_cpu_offset +#endif + /* * Arch may define arch_raw_cpu_ptr() to provide more efficient address * translations for raw_cpu_ptr(). @@ -44,6 +52,10 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; #define arch_raw_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset) #endif +#ifndef arch_raw_cpu_ptr_preemptable +#define arch_raw_cpu_ptr_preemptable(ptr) SHIFT_PERCPU_PTR(ptr, __raw_my_cpu_offset) +#endif + #ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA extern void setup_per_cpu_areas(void); #endif diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index a6fabd865211..13afca8a37e7 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -237,20 +237,51 @@ do { \ SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu))); \ }) +#ifndef arch_raw_cpu_ptr_preemption_disabled +#define arch_raw_cpu_ptr_preemption_disabled(ptr) \ + arch_raw_cpu_ptr(ptr) +#endif + +#define raw_cpu_ptr_preemption_disabled(ptr) \ +({ \ + __verify_pcpu_ptr(ptr); \ + arch_raw_cpu_ptr_preemption_disabled(ptr); \ +}) + +/* + * If preemption is enabled, we need to read the pointer atomically on + * raw_cpu_ptr(). However if it is disabled, we can use the + * raw_cpu_ptr_nopreempt(), which is potentially more efficient. Similarly, we + * can use the preemption-disabled version if the kernel is non-preemptable or + * if voluntary preemption is used. + */ +#ifdef CONFIG_PREEMPT + #define raw_cpu_ptr(ptr) \ ({ \ __verify_pcpu_ptr(ptr); \ arch_raw_cpu_ptr(ptr); \ }) +#else + +#define raw_cpu_ptr(ptr) raw_cpu_ptr_preemption_disabled(ptr) + +#endif + #ifdef CONFIG_DEBUG_PREEMPT +/* + * Unlike other this_cpu_* operations, this_cpu_ptr() requires that preemption + * will be disabled. In contrast, raw_cpu_ptr() does not require that. + */ #define this_cpu_ptr(ptr) \ ({ \ + __this_cpu_preempt_check("ptr"); \ __verify_pcpu_ptr(ptr); \ SHIFT_PERCPU_PTR(ptr, my_cpu_offset); \ }) #else -#define this_cpu_ptr(ptr) raw_cpu_ptr(ptr) +#define this_cpu_ptr(ptr) raw_cpu_ptr_preemption_disabled(ptr) #endif #else /* CONFIG_SMP */ -- 2.17.1