(Note: Patch also attached because the inline version is certain to get line wrapped.) 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 <[email protected]> diff -Npru 2.6.13/arch/x86_64/kernel/traps.c 2.6.13-x86_64-oops-irq/arch/x86_64/kernel/traps.c --- 2.6.13/arch/x86_64/kernel/traps.c 2005-08-29 01:41:01.000000000 +0200 +++ 2.6.13-x86_64-oops-irq/arch/x86_64/kernel/traps.c 2005-09-07 15:37:52.000000000 +0200 @@ -342,30 +342,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) { @@ -391,10 +394,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) @@ -405,7 +409,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. @@ -415,7 +420,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); } diff -Npru 2.6.13/arch/x86_64/mm/fault.c 2.6.13-x86_64-oops-irq/arch/x86_64/mm/fault.c --- 2.6.13/arch/x86_64/mm/fault.c 2005-08-29 01:41:01.000000000 +0200 +++ 2.6.13-x86_64-oops-irq/arch/x86_64/mm/fault.c 2005-09-07 16:15:13.000000000 +0200 @@ -220,12 +220,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); } @@ -302,6 +303,7 @@ asmlinkage void do_page_fault(struct pt_ unsigned long address; const struct exception_table_entry *fixup; int write; + unsigned long flags; siginfo_t info; #ifdef CONFIG_CHECKING @@ -519,7 +521,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"); @@ -532,7 +534,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); /* diff -Npru 2.6.13/include/asm-x86_64/kdebug.h 2.6.13-x86_64-oops-irq/include/asm-x86_64/kdebug.h --- 2.6.13/include/asm-x86_64/kdebug.h 2005-08-29 01:41:01.000000000 +0200 +++ 2.6.13-x86_64-oops-irq/include/asm-x86_64/kdebug.h 2005-09-01 11:32:12.000000000 +0200 @@ -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 diff -Npru 2.6.13/include/asm-x86_64/proto.h 2.6.13-x86_64-oops-irq/include/asm-x86_64/proto.h --- 2.6.13/include/asm-x86_64/proto.h 2005-08-29 01:41:01.000000000 +0200 +++ 2.6.13-x86_64-oops-irq/include/asm-x86_64/proto.h 2005-09-01 11:32:12.000000000 +0200 @@ -75,9 +75,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);
Attachment:
linux-2.6.13-x86_64-oops-irq.patch
Description: Binary data
- Follow-Ups:
- Prev by Date: [PATCH] add and handle NMI_VECTOR
- Next by Date: [PATCH] fix x86-64 condition to call nmi_watchdog_tick
- Previous by thread: [PATCH] add and handle NMI_VECTOR
- Next by thread: Re: [discuss] [PATCH] fix x86-64 interrupt re-enabling in oops_end()
- Index(es):