]> err.no Git - linux-2.6/commitdiff
[PATCH] x86-64: Safe interrupts in oops_begin/end
authorJan Beulich <jbeulich@novell.com>
Mon, 12 Sep 2005 16:49:24 +0000 (18:49 +0200)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 12 Sep 2005 17:50:57 +0000 (10:50 -0700)
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 <jbeulich@novell.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/x86_64/kernel/traps.c
arch/x86_64/mm/fault.c
include/asm-x86_64/kdebug.h
include/asm-x86_64/proto.h

index f238d6078a5a921fcf94c935903b9aaa3aac5bf0..64a59cb49411af85d222db21ac54d64584779af4 100644 (file)
@@ -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_regs * regs, long err)
 
 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 char * str, struct pt_regs * regs, long e
 
 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 *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 816732d8858c3195c7b6d78419b2b0b537de3f10..b75b872ec154f8e004fc04a29375eb97f7f468bb 100644 (file)
@@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct *tsk, int sig)
 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(struct pt_regs *regs,
        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 b90341994d80f6e78d18f685cca99e15baea8e37..f604e84c53039e784e10605b3b3e428af9d91deb 100644 (file)
@@ -46,7 +46,7 @@ extern void die(const char *,struct pt_regs *,long);
 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 764b5f822ce28ab5ae2bb62f35633eb1cf5d553f..dbb37b0adb43df3f2ea20d62bc4e398c9bd469be 100644 (file)
@@ -74,9 +74,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);