Pull novell-bugzilla-156426 into release branch
[pandora-kernel.git] / arch / i386 / kernel / traps.c
index d510de7..0e49836 100644 (file)
@@ -92,22 +92,21 @@ asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
 
 static int kstack_depth_to_print = 24;
-struct notifier_block *i386die_chain;
-static DEFINE_SPINLOCK(die_notifier_lock);
+ATOMIC_NOTIFIER_HEAD(i386die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
 {
-       int err = 0;
-       unsigned long flags;
-
        vmalloc_sync_all();
-       spin_lock_irqsave(&die_notifier_lock, flags);
-       err = notifier_chain_register(&i386die_chain, nb);
-       spin_unlock_irqrestore(&die_notifier_lock, flags);
-       return err;
+       return atomic_notifier_chain_register(&i386die_chain, nb);
 }
 EXPORT_SYMBOL(register_die_notifier);
 
+int unregister_die_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&i386die_chain, nb);
+}
+EXPORT_SYMBOL(unregister_die_notifier);
+
 static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
 {
        return  p > (void *)tinfo &&
@@ -131,9 +130,8 @@ static inline int print_addr_and_symbol(unsigned long addr, char *log_lvl,
        print_symbol("%s", addr);
 
        printed = (printed + 1) % CONFIG_STACK_BACKTRACE_COLS;
-
        if (printed)
-               printk("  ");
+               printk(" ");
        else
                printk("\n");
 
@@ -213,23 +211,20 @@ static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp,
        }
 
        stack = esp;
-       printk(log_lvl);
        for(i = 0; i < kstack_depth_to_print; i++) {
                if (kstack_end(stack))
                        break;
-               if (i && ((i % 8) == 0)) {
-                       printk("\n");
-                       printk("%s       ", log_lvl);
-               }
+               if (i && ((i % 8) == 0))
+                       printk("\n%s       ", log_lvl);
                printk("%08lx ", *stack++);
        }
-       printk("\n");
-       printk("%sCall Trace:\n", log_lvl);
+       printk("\n%sCall Trace:\n", log_lvl);
        show_trace_log_lvl(task, esp, log_lvl);
 }
 
 void show_stack(struct task_struct *task, unsigned long *esp)
 {
+       printk("       ");
        show_stack_log_lvl(task, esp, "");
 }
 
@@ -254,7 +249,7 @@ void show_registers(struct pt_regs *regs)
 
        esp = (unsigned long) (&regs->esp);
        savesegment(ss, ss);
-       if (user_mode(regs)) {
+       if (user_mode_vm(regs)) {
                in_kernel = 0;
                esp = regs->esp;
                ss = regs->xss & 0xffff;
@@ -354,6 +349,8 @@ void die(const char * str, struct pt_regs * regs, long err)
        static int die_counter;
        unsigned long flags;
 
+       oops_enter();
+
        if (die.lock_owner != raw_smp_processor_id()) {
                console_verbose();
                spin_lock_irqsave(&die.lock, flags);
@@ -366,6 +363,9 @@ void die(const char * str, struct pt_regs * regs, long err)
 
        if (++die.lock_owner_depth < 3) {
                int nl = 0;
+               unsigned long esp;
+               unsigned short ss;
+
                handle_BUG(regs);
                printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
 #ifdef CONFIG_PREEMPT
@@ -386,8 +386,23 @@ void die(const char * str, struct pt_regs * regs, long err)
 #endif
                if (nl)
                        printk("\n");
-       notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
-               show_registers(regs);
+               if (notify_die(DIE_OOPS, str, regs, err,
+                                       current->thread.trap_no, SIGSEGV) !=
+                               NOTIFY_STOP) {
+                       show_registers(regs);
+                       /* Executive summary in case the oops scrolled away */
+                       esp = (unsigned long) (&regs->esp);
+                       savesegment(ss, ss);
+                       if (user_mode(regs)) {
+                               esp = regs->esp;
+                               ss = regs->xss & 0xffff;
+                       }
+                       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip);
+                       print_symbol("%s", regs->eip);
+                       printk(" SS:ESP %04x:%08lx\n", ss, esp);
+               }
+               else
+                       regs = NULL;
        } else
                printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
 
@@ -395,6 +410,9 @@ void die(const char * str, struct pt_regs * regs, long err)
        die.lock_owner = -1;
        spin_unlock_irqrestore(&die.lock, flags);
 
+       if (!regs)
+               return;
+
        if (kexec_should_crash(current))
                crash_kexec(regs);
 
@@ -406,6 +424,7 @@ void die(const char * str, struct pt_regs * regs, long err)
                ssleep(5);
                panic("Fatal exception");
        }
+       oops_exit();
        do_exit(SIGSEGV);
 }
 
@@ -622,7 +641,7 @@ static DEFINE_SPINLOCK(nmi_print_lock);
 
 void die_nmi (struct pt_regs *regs, const char *msg)
 {
-       if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 0, SIGINT) ==
+       if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) ==
            NOTIFY_STOP)
                return;
 
@@ -644,7 +663,7 @@ void die_nmi (struct pt_regs *regs, const char *msg)
        /* If we are in kernel we are probably nested up pretty bad
         * and might aswell get out now while we still can.
        */
-       if (!user_mode(regs)) {
+       if (!user_mode_vm(regs)) {
                current->thread.trap_no = 2;
                crash_kexec(regs);
        }
@@ -661,7 +680,7 @@ static void default_do_nmi(struct pt_regs * regs)
                reason = get_nmi_reason();
  
        if (!(reason & 0xc0)) {
-               if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
+               if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
                                                        == NOTIFY_STOP)
                        return;
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -677,7 +696,7 @@ static void default_do_nmi(struct pt_regs * regs)
                unknown_nmi_error(reason, regs);
                return;
        }
-       if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
+       if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
                return;
        if (reason & 0x80)
                mem_parity_error(reason, regs);
@@ -1186,6 +1205,6 @@ void __init trap_init(void)
 static int __init kstack_setup(char *s)
 {
        kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-       return 0;
+       return 1;
 }
 __setup("kstack=", kstack_setup);