Re: [PATCH 5/5] irqtime: drop local_irq_save/restore from irqtime_account_irq

From: Paolo Bonzini
Date: Thu Jun 23 2016 - 09:52:43 EST




On 22/06/2016 23:55, Rik van Riel wrote:
> > > + hardirq_time = READ_ONCE(per_cpu(cpu_hardirq_time,
> > > cpu));
> > Which makes this per_cpu(,cpu) usage somewhat curious. What's wrong
> > with __this_cpu_read() ?
>
> I played around with it a bit, and it seems that
> __this_cpu_read does not want to nest inside
> READ_ONCE. Nobody else seems to be doing that,
> either.

According to arch/x86/include/asm/percpu.h, this_cpu_read always has
READ_ONCE semantics, but I cannot find that in include/asm-generic
/percpu.h. It probably just works because of all the layers of goo, but
something like this (101% untested) would make me feel safer:

diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 4d9f233c4ba8..d057568f1926 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -67,7 +67,7 @@ extern void setup_per_cpu_areas(void);

#define raw_cpu_generic_to_op(pcp, val, op) \
do { \
- *raw_cpu_ptr(&(pcp)) op val; \
+ ACCESS_ONCE(*raw_cpu_ptr(&(pcp))) op val; \
} while (0)

#define raw_cpu_generic_add_return(pcp, val) \
@@ -109,7 +109,7 @@ do {
({ \
typeof(pcp) __ret; \
preempt_disable(); \
- __ret = *this_cpu_ptr(&(pcp)); \
+ __ret = READ_ONCE(this_cpu_ptr(&(pcp))); \
preempt_enable(); \
__ret; \
})
@@ -118,7 +118,7 @@ do {
do { \
unsigned long __flags; \
raw_local_irq_save(__flags); \
- *raw_cpu_ptr(&(pcp)) op val; \
+ ACCESS_ONCE(*raw_cpu_ptr(&(pcp))) op val; \
raw_local_irq_restore(__flags); \
} while (0)

@@ -168,16 +168,16 @@ do {
})

#ifndef raw_cpu_read_1
-#define raw_cpu_read_1(pcp) (*raw_cpu_ptr(&(pcp)))
+#define raw_cpu_read_1(pcp) READ_ONCE(raw_cpu_ptr(&(pcp)))
#endif
#ifndef raw_cpu_read_2
-#define raw_cpu_read_2(pcp) (*raw_cpu_ptr(&(pcp)))
+#define raw_cpu_read_2(pcp) READ_ONCE(raw_cpu_ptr(&(pcp)))
#endif
#ifndef raw_cpu_read_4
-#define raw_cpu_read_4(pcp) (*raw_cpu_ptr(&(pcp)))
+#define raw_cpu_read_4(pcp) READ_ONCE(raw_cpu_ptr(&(pcp)))
#endif
#ifndef raw_cpu_read_8
-#define raw_cpu_read_8(pcp) (*raw_cpu_ptr(&(pcp)))
+#define raw_cpu_read_8(pcp) READ_ONCE(raw_cpu_ptr(&(pcp)))
#endif

#ifndef raw_cpu_write_1


> Back to READ_ONCE(per_cpu(,cpu)) it is...

What about READ_ONCE(this_cpu_ptr())?

Paolo