Skip to content

Commit f87032a

Browse files
author
Ingo Molnar
committed
Merge branch 'locking/nmi' into x86/entry
Resolve conflicts with ongoing lockdep work that fixed the NMI entry code. Conflicts: arch/x86/entry/common.c arch/x86/include/asm/idtentry.h Signed-off-by: Ingo Molnar <[email protected]>
2 parents d25c8be + ba1f2b2 commit f87032a

File tree

12 files changed

+315
-213
lines changed

12 files changed

+315
-213
lines changed

arch/x86/entry/common.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,40 @@ SYSCALL_DEFINE0(ni_syscall)
198198
return -ENOSYS;
199199
}
200200

201+
noinstr bool idtentry_enter_nmi(struct pt_regs *regs)
202+
{
203+
bool irq_state = lockdep_hardirqs_enabled();
204+
205+
__nmi_enter();
206+
lockdep_hardirqs_off(CALLER_ADDR0);
207+
lockdep_hardirq_enter();
208+
rcu_nmi_enter();
209+
210+
instrumentation_begin();
211+
trace_hardirqs_off_finish();
212+
ftrace_nmi_enter();
213+
instrumentation_end();
214+
215+
return irq_state;
216+
}
217+
218+
noinstr void idtentry_exit_nmi(struct pt_regs *regs, bool restore)
219+
{
220+
instrumentation_begin();
221+
ftrace_nmi_exit();
222+
if (restore) {
223+
trace_hardirqs_on_prepare();
224+
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
225+
}
226+
instrumentation_end();
227+
228+
rcu_nmi_exit();
229+
lockdep_hardirq_exit();
230+
if (restore)
231+
lockdep_hardirqs_on(CALLER_ADDR0);
232+
__nmi_exit();
233+
}
234+
201235
#ifdef CONFIG_XEN_PV
202236
#ifndef CONFIG_PREEMPTION
203237
/*

arch/x86/include/asm/idtentry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
#include <asm/irq_stack.h>
1313

14+
bool idtentry_enter_nmi(struct pt_regs *regs);
15+
void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state);
16+
1417
/**
1518
* DECLARE_IDTENTRY - Declare functions for simple IDT entry points
1619
* No error code pushed by hardware

arch/x86/kernel/nmi.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,6 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
330330
__this_cpu_write(last_nmi_rip, regs->ip);
331331

332332
instrumentation_begin();
333-
trace_hardirqs_off_finish();
334333

335334
handled = nmi_handle(NMI_LOCAL, regs);
336335
__this_cpu_add(nmi_stats.normal, handled);
@@ -417,8 +416,6 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
417416
unknown_nmi_error(reason, regs);
418417

419418
out:
420-
if (regs->flags & X86_EFLAGS_IF)
421-
trace_hardirqs_on_prepare();
422419
instrumentation_end();
423420
}
424421

@@ -478,6 +475,8 @@ static DEFINE_PER_CPU(unsigned long, nmi_dr7);
478475

479476
DEFINE_IDTENTRY_RAW(exc_nmi)
480477
{
478+
bool irq_state;
479+
481480
if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id()))
482481
return;
483482

@@ -491,14 +490,14 @@ DEFINE_IDTENTRY_RAW(exc_nmi)
491490

492491
this_cpu_write(nmi_dr7, local_db_save());
493492

494-
nmi_enter();
493+
irq_state = idtentry_enter_nmi(regs);
495494

496495
inc_irq_stat(__nmi_count);
497496

498497
if (!ignore_nmis)
499498
default_do_nmi(regs);
500499

501-
nmi_exit();
500+
idtentry_exit_nmi(regs, irq_state);
502501

503502
local_db_restore(this_cpu_read(nmi_dr7));
504503

arch/x86/kernel/traps.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ DEFINE_IDTENTRY_DF(exc_double_fault)
405405
}
406406
#endif
407407

408-
nmi_enter();
408+
idtentry_enter_nmi(regs);
409409
instrumentation_begin();
410410
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
411411

@@ -651,15 +651,12 @@ DEFINE_IDTENTRY_RAW(exc_int3)
651651
instrumentation_end();
652652
irqentry_exit_to_user_mode(regs);
653653
} else {
654-
nmi_enter();
654+
bool irq_state = idtentry_enter_nmi(regs);
655655
instrumentation_begin();
656-
trace_hardirqs_off_finish();
657656
if (!do_int3(regs))
658657
die("int3", regs, 0);
659-
if (regs->flags & X86_EFLAGS_IF)
660-
trace_hardirqs_on_prepare();
661658
instrumentation_end();
662-
nmi_exit();
659+
idtentry_exit_nmi(regs, irq_state);
663660
}
664661
}
665662

@@ -867,9 +864,8 @@ static void handle_debug(struct pt_regs *regs, unsigned long dr6, bool user)
867864
static __always_inline void exc_debug_kernel(struct pt_regs *regs,
868865
unsigned long dr6)
869866
{
870-
nmi_enter();
867+
bool irq_state = idtentry_enter_nmi(regs);
871868
instrumentation_begin();
872-
trace_hardirqs_off_finish();
873869

874870
/*
875871
* If something gets miswired and we end up here for a user mode
@@ -886,10 +882,8 @@ static __always_inline void exc_debug_kernel(struct pt_regs *regs,
886882

887883
handle_debug(regs, dr6, false);
888884

889-
if (regs->flags & X86_EFLAGS_IF)
890-
trace_hardirqs_on_prepare();
891885
instrumentation_end();
892-
nmi_exit();
886+
idtentry_exit_nmi(regs, irq_state);
893887
}
894888

895889
static __always_inline void exc_debug_user(struct pt_regs *regs,
@@ -905,6 +899,7 @@ static __always_inline void exc_debug_user(struct pt_regs *regs,
905899
instrumentation_begin();
906900

907901
handle_debug(regs, dr6, true);
902+
908903
instrumentation_end();
909904
irqentry_exit_to_user_mode(regs);
910905
}

include/linux/hardirq.h

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,32 +111,42 @@ extern void rcu_nmi_exit(void);
111111
/*
112112
* nmi_enter() can nest up to 15 times; see NMI_BITS.
113113
*/
114-
#define nmi_enter() \
114+
#define __nmi_enter() \
115115
do { \
116+
lockdep_off(); \
116117
arch_nmi_enter(); \
117118
printk_nmi_enter(); \
118-
lockdep_off(); \
119119
BUG_ON(in_nmi() == NMI_MASK); \
120120
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
121-
rcu_nmi_enter(); \
121+
} while (0)
122+
123+
#define nmi_enter() \
124+
do { \
125+
__nmi_enter(); \
122126
lockdep_hardirq_enter(); \
127+
rcu_nmi_enter(); \
123128
instrumentation_begin(); \
124129
ftrace_nmi_enter(); \
125130
instrumentation_end(); \
126131
} while (0)
127132

133+
#define __nmi_exit() \
134+
do { \
135+
BUG_ON(!in_nmi()); \
136+
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
137+
printk_nmi_exit(); \
138+
arch_nmi_exit(); \
139+
lockdep_on(); \
140+
} while (0)
141+
128142
#define nmi_exit() \
129143
do { \
130144
instrumentation_begin(); \
131145
ftrace_nmi_exit(); \
132146
instrumentation_end(); \
133-
lockdep_hardirq_exit(); \
134147
rcu_nmi_exit(); \
135-
BUG_ON(!in_nmi()); \
136-
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
137-
lockdep_on(); \
138-
printk_nmi_exit(); \
139-
arch_nmi_exit(); \
148+
lockdep_hardirq_exit(); \
149+
__nmi_exit(); \
140150
} while (0)
141151

142152
#endif /* LINUX_HARDIRQ_H */

0 commit comments

Comments
 (0)