Forcing in_interrupt() to return true if we're not in a bona fide interrupt confuses the softirq code. This fixes warnings like: NOHZ: local_softirq_pending 282 that can happen when running things like selftests/x86. Cc: stable@xxxxxxxxxxxxxxx Fixes: 959274753857 ("x86, traps: Track entry into and exit from IST context") Signed-off-by: Andy Lutomirski <luto@xxxxxxxxxx> --- This is intended for x86/urgent. arch/x86/kernel/traps.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index d1590486204a..25a905674acd 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -96,6 +96,20 @@ static inline void cond_local_irq_disable(struct pt_regs *regs) local_irq_disable(); } +/* + * We want to cause in_atomic() to return true while in an IST handler + * so that attempts to schedule will warn. + * + * We cannot add use HARDIRQ_OFFSET or otherwise cause in_interrupt() to + * return true: the softirq code assumes that in_interrupt() only + * returns true if we will soon execute softirqs, and we can't do that + * if an IST entry interrupts kernel code with interrupts disabled. + * + * Using 3 * PREEMPT_OFFSET instead of just PREEMPT_OFFSET is pure + * paranoia. + */ +#define IST_OFFSET (3 * PREEMPT_OFFSET) + void ist_enter(struct pt_regs *regs) { if (user_mode(regs)) { @@ -116,7 +130,7 @@ void ist_enter(struct pt_regs *regs) * on x86_64 and entered from user mode, in which case we're * still atomic unless ist_begin_non_atomic is called. */ - preempt_count_add(HARDIRQ_OFFSET); + preempt_count_add(IST_OFFSET); /* This code is a bit fragile. Test it. */ RCU_LOCKDEP_WARN(!rcu_is_watching(), "ist_enter didn't work"); @@ -124,7 +138,7 @@ void ist_enter(struct pt_regs *regs) void ist_exit(struct pt_regs *regs) { - preempt_count_sub(HARDIRQ_OFFSET); + preempt_count_sub(IST_OFFSET); if (!user_mode(regs)) rcu_nmi_exit(); @@ -155,7 +169,7 @@ void ist_begin_non_atomic(struct pt_regs *regs) BUG_ON((unsigned long)(current_top_of_stack() - current_stack_pointer()) >= THREAD_SIZE); - preempt_count_sub(HARDIRQ_OFFSET); + preempt_count_sub(IST_OFFSET); } /** @@ -165,7 +179,7 @@ void ist_begin_non_atomic(struct pt_regs *regs) */ void ist_end_non_atomic(void) { - preempt_count_add(HARDIRQ_OFFSET); + preempt_count_add(IST_OFFSET); } static nokprobe_inline int -- 2.5.5 -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html