x86/entry: Remove unwanted instrumentation in common_interrupt()

[ Upstream commit 477d81a1c47a1b79b9c08fc92b5dea3c5143800b ]

common_interrupt() and related variants call kvm_set_cpu_l1tf_flush_l1d(),
which is neither marked noinstr nor __always_inline.

So compiler puts it out of line and adds instrumentation to it.  Since the
call is inside of instrumentation_begin/end(), objtool does not warn about
it.

The manifestation is that KCOV produces spurious coverage in
kvm_set_cpu_l1tf_flush_l1d() in random places because the call happens when
preempt count is not yet updated to say that the kernel is in an interrupt.

Mark kvm_set_cpu_l1tf_flush_l1d() as __always_inline and move it out of the
instrumentation_begin/end() section.  It only calls __this_cpu_write()
which is already safe to call in noinstr contexts.

Fixes: 6368558c37 ("x86/entry: Provide IDTENTRY_SYSVEC")
Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Alexander Potapenko <glider@google.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/all/3f9a1de9e415fcb53d07dc9e19fa8481bb021b1b.1718092070.git.dvyukov@google.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Dmitry Vyukov 2024-06-11 09:50:30 +02:00 committed by Greg Kroah-Hartman
parent d5c5afdb9e
commit 32e93cae4d
2 changed files with 9 additions and 5 deletions

View file

@ -63,7 +63,11 @@ extern u64 arch_irq_stat(void);
#define local_softirq_pending_ref pcpu_hot.softirq_pending #define local_softirq_pending_ref pcpu_hot.softirq_pending
#if IS_ENABLED(CONFIG_KVM_INTEL) #if IS_ENABLED(CONFIG_KVM_INTEL)
static inline void kvm_set_cpu_l1tf_flush_l1d(void) /*
* This function is called from noinstr interrupt contexts
* and must be inlined to not get instrumentation.
*/
static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void)
{ {
__this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1); __this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
} }
@ -78,7 +82,7 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void)
return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d); return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
} }
#else /* !IS_ENABLED(CONFIG_KVM_INTEL) */ #else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
static inline void kvm_set_cpu_l1tf_flush_l1d(void) { } static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */ #endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
#endif /* _ASM_X86_HARDIRQ_H */ #endif /* _ASM_X86_HARDIRQ_H */

View file

@ -212,8 +212,8 @@ __visible noinstr void func(struct pt_regs *regs, \
irqentry_state_t state = irqentry_enter(regs); \ irqentry_state_t state = irqentry_enter(regs); \
u32 vector = (u32)(u8)error_code; \ u32 vector = (u32)(u8)error_code; \
\ \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \ instrumentation_begin(); \
kvm_set_cpu_l1tf_flush_l1d(); \
run_irq_on_irqstack_cond(__##func, regs, vector); \ run_irq_on_irqstack_cond(__##func, regs, vector); \
instrumentation_end(); \ instrumentation_end(); \
irqentry_exit(regs, state); \ irqentry_exit(regs, state); \
@ -250,7 +250,6 @@ static void __##func(struct pt_regs *regs); \
\ \
static __always_inline void instr_##func(struct pt_regs *regs) \ static __always_inline void instr_##func(struct pt_regs *regs) \
{ \ { \
kvm_set_cpu_l1tf_flush_l1d(); \
run_sysvec_on_irqstack_cond(__##func, regs); \ run_sysvec_on_irqstack_cond(__##func, regs); \
} \ } \
\ \
@ -258,6 +257,7 @@ __visible noinstr void func(struct pt_regs *regs) \
{ \ { \
irqentry_state_t state = irqentry_enter(regs); \ irqentry_state_t state = irqentry_enter(regs); \
\ \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \ instrumentation_begin(); \
instr_##func (regs); \ instr_##func (regs); \
instrumentation_end(); \ instrumentation_end(); \
@ -288,7 +288,6 @@ static __always_inline void __##func(struct pt_regs *regs); \
static __always_inline void instr_##func(struct pt_regs *regs) \ static __always_inline void instr_##func(struct pt_regs *regs) \
{ \ { \
__irq_enter_raw(); \ __irq_enter_raw(); \
kvm_set_cpu_l1tf_flush_l1d(); \
__##func (regs); \ __##func (regs); \
__irq_exit_raw(); \ __irq_exit_raw(); \
} \ } \
@ -297,6 +296,7 @@ __visible noinstr void func(struct pt_regs *regs) \
{ \ { \
irqentry_state_t state = irqentry_enter(regs); \ irqentry_state_t state = irqentry_enter(regs); \
\ \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \ instrumentation_begin(); \
instr_##func (regs); \ instr_##func (regs); \
instrumentation_end(); \ instrumentation_end(); \