Safe interrupts in oops_begin/end From: Jan Beulich Rather than blindly re-enabling interrupts in oops_end(), save their state in oope_begin() and then restore that state. Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen Index: linux/arch/x86_64/kernel/traps.c =================================================================== --- linux.orig/arch/x86_64/kernel/traps.c +++ linux/arch/x86_64/kernel/traps.c @@ -343,30 +343,33 @@ void out_of_line_bug(void) static DEFINE_SPINLOCK(die_lock); static int die_owner = -1; -void oops_begin(void) +unsigned long oops_begin(void) { - int cpu = safe_smp_processor_id(); - /* racy, but better than risking deadlock. */ - local_irq_disable(); + int cpu = safe_smp_processor_id(); + unsigned long flags; + + /* racy, but better than risking deadlock. */ + local_irq_save(flags); if (!spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; else - spin_lock(&die_lock); + spin_lock(&die_lock); } - die_owner = cpu; + die_owner = cpu; console_verbose(); - bust_spinlocks(1); + bust_spinlocks(1); + return flags; } -void oops_end(void) +void oops_end(unsigned long flags) { die_owner = -1; - bust_spinlocks(0); - spin_unlock(&die_lock); + bust_spinlocks(0); + spin_unlock_irqrestore(&die_lock, flags); if (panic_on_oops) - panic("Oops"); -} + panic("Oops"); +} void __die(const char * str, struct pt_regs * regs, long err) { @@ -392,10 +395,11 @@ void __die(const char * str, struct pt_r void die(const char * str, struct pt_regs * regs, long err) { - oops_begin(); + unsigned long flags = oops_begin(); + handle_BUG(regs); __die(str, regs, err); - oops_end(); + oops_end(flags); do_exit(SIGSEGV); } static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) @@ -406,7 +410,8 @@ static inline void die_if_kernel(const c void die_nmi(char *str, struct pt_regs *regs) { - oops_begin(); + unsigned long flags = oops_begin(); + /* * We are in trouble anyway, lets at least try * to get a message out. @@ -416,7 +421,7 @@ void die_nmi(char *str, struct pt_regs * if (panic_on_timeout || panic_on_oops) panic("nmi watchdog"); printk("console shuts up ...\n"); - oops_end(); + oops_end(flags); do_exit(SIGSEGV); } Index: linux/arch/x86_64/mm/fault.c =================================================================== --- linux.orig/arch/x86_64/mm/fault.c +++ linux/arch/x86_64/mm/fault.c @@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, unsigned long error_code) { - oops_begin(); + unsigned long flags = oops_begin(); + printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", current->comm, address); dump_pagetable(address); __die("Bad pagetable", regs, error_code); - oops_end(); + oops_end(flags); do_exit(SIGKILL); } @@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault( unsigned long address; const struct exception_table_entry *fixup; int write; + unsigned long flags; siginfo_t info; #ifdef CONFIG_CHECKING @@ -521,7 +523,7 @@ no_context: * terminate things with extreme prejudice. */ - oops_begin(); + flags = oops_begin(); if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -534,7 +536,7 @@ no_context: __die("Oops", regs, error_code); /* Executive summary in case the body of the oops scrolled away */ printk(KERN_EMERG "CR2: %016lx\n", address); - oops_end(); + oops_end(flags); do_exit(SIGKILL); /* Index: linux/include/asm-x86_64/kdebug.h =================================================================== --- linux.orig/include/asm-x86_64/kdebug.h +++ linux/include/asm-x86_64/kdebug.h @@ -46,7 +46,7 @@ extern void die(const char *,struct pt_r extern void __die(const char *,struct pt_regs *,long); extern void show_registers(struct pt_regs *regs); extern void dump_pagetable(unsigned long); -extern void oops_begin(void); -extern void oops_end(void); +extern unsigned long oops_begin(void); +extern void oops_end(unsigned long); #endif Index: linux/include/asm-x86_64/proto.h =================================================================== --- linux.orig/include/asm-x86_64/proto.h +++ linux/include/asm-x86_64/proto.h @@ -77,9 +77,6 @@ extern void acpi_reserve_bootmem(void); extern void swap_low_mappings(void); -extern void oops_begin(void); -extern void die(const char *,struct pt_regs *,long); -extern void __die(const char * str, struct pt_regs * regs, long err); extern void __show_regs(struct pt_regs * regs); extern void show_regs(struct pt_regs * regs);