Pull extend-notify-die into release branch
authorTony Luck <tony.luck@intel.com>
Thu, 10 Nov 2005 18:39:09 +0000 (10:39 -0800)
committerTony Luck <tony.luck@intel.com>
Thu, 10 Nov 2005 18:39:09 +0000 (10:39 -0800)
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/process.c
arch/ia64/kernel/traps.c
include/asm-ia64/kdebug.h

index 96736a119c911e22fcbab6d6e7aabb1529a04a9a..801eeaeaf3de6c760905361ec61b9ad7eb8ebaf5 100644 (file)
@@ -347,7 +347,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
                ((struct fnptr *)kretprobe_trampoline)->ip;
 
        spin_lock_irqsave(&kretprobe_lock, flags);
-        head = kretprobe_inst_table_head(current);
+       head = kretprobe_inst_table_head(current);
 
        /*
         * It is possible to have multiple instances associated with a given
@@ -363,9 +363,9 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
         *       kretprobe_trampoline
         */
        hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
-                if (ri->task != current)
+               if (ri->task != current)
                        /* another task is sharing our hash bucket */
-                        continue;
+                       continue;
 
                if (ri->rp && ri->rp->handler)
                        ri->rp->handler(ri, regs);
@@ -394,7 +394,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
         * kprobe_handler() that we don't want the post_handler
         * to run (and have re-enabled preemption)
         */
-        return 1;
+       return 1;
 }
 
 /* Called with kretprobe_lock held */
@@ -739,12 +739,16 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
 
        switch(val) {
        case DIE_BREAK:
-               if (pre_kprobes_handler(args))
-                       ret = NOTIFY_STOP;
+               /* err is break number from ia64_bad_break() */
+               if (args->err == 0x80200 || args->err == 0x80300)
+                       if (pre_kprobes_handler(args))
+                               ret = NOTIFY_STOP;
                break;
-       case DIE_SS:
-               if (post_kprobes_handler(args->regs))
-                       ret = NOTIFY_STOP;
+       case DIE_FAULT:
+               /* err is vector number from ia64_fault() */
+               if (args->err == 36)
+                       if (post_kprobes_handler(args->regs))
+                               ret = NOTIFY_STOP;
                break;
        case DIE_PAGE_FAULT:
                /* kprobe_running() needs smp_processor_id() */
index 52c47da17246ace5033f519670ea028a7474f214..355af15287c7eb318f08382cf6d695a6bb677524 100644 (file)
@@ -51,6 +51,9 @@
  *
  * 2005-08-12 Keith Owens <kaos@sgi.com>
  *           Convert MCA/INIT handlers to use per event stacks and SAL/OS state.
+ *
+ * 2005-10-07 Keith Owens <kaos@sgi.com>
+ *           Add notify_die() hooks.
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -58,7 +61,6 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/kallsyms.h>
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
@@ -69,6 +71,7 @@
 #include <linux/workqueue.h>
 
 #include <asm/delay.h>
+#include <asm/kdebug.h>
 #include <asm/machvec.h>
 #include <asm/meminit.h>
 #include <asm/page.h>
@@ -132,6 +135,14 @@ extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe);
 
 static int mca_init;
 
+
+static void inline
+ia64_mca_spin(const char *func)
+{
+       printk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func);
+       while (1)
+               cpu_relax();
+}
 /*
  * IA64_MCA log support
  */
@@ -526,13 +537,16 @@ ia64_mca_wakeup_all(void)
  *  Outputs :   None
  */
 static irqreturn_t
-ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
 {
        unsigned long flags;
        int cpu = smp_processor_id();
 
        /* Mask all interrupts */
        local_irq_save(flags);
+       if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
 
        ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
        /* Register with the SAL monarch that the slave has
@@ -540,10 +554,18 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
         */
        ia64_sal_mc_rendez();
 
+       if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
+
        /* Wait for the monarch cpu to exit. */
        while (monarch_cpu != -1)
               cpu_relax();     /* spin until monarch leaves */
 
+       if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
+
        /* Enable all interrupts */
        local_irq_restore(flags);
        return IRQ_HANDLED;
@@ -933,6 +955,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
        oops_in_progress = 1;   /* FIXME: make printk NMI/MCA/INIT safe */
        previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA");
        monarch_cpu = cpu;
+       if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
        ia64_wait_for_slaves(cpu);
 
        /* Wakeup all the processors which are spinning in the rendezvous loop.
@@ -942,6 +967,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
         * spinning in SAL does not work.
         */
        ia64_mca_wakeup_all();
+       if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
 
        /* Get the MCA error record and log it */
        ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
@@ -960,6 +988,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
                ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA);
                sos->os_status = IA64_MCA_CORRECTED;
        }
+       if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, 0, 0, recover)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
 
        set_curr_task(cpu, previous_current);
        monarch_cpu = -1;
@@ -1188,6 +1219,37 @@ ia64_mca_cpe_poll (unsigned long dummy)
 
 #endif /* CONFIG_ACPI */
 
+static int
+default_monarch_init_process(struct notifier_block *self, unsigned long val, void *data)
+{
+       int c;
+       struct task_struct *g, *t;
+       if (val != DIE_INIT_MONARCH_PROCESS)
+               return NOTIFY_DONE;
+       printk(KERN_ERR "Processes interrupted by INIT -");
+       for_each_online_cpu(c) {
+               struct ia64_sal_os_state *s;
+               t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET);
+               s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET);
+               g = s->prev_task;
+               if (g) {
+                       if (g->pid)
+                               printk(" %d", g->pid);
+                       else
+                               printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g);
+               }
+       }
+       printk("\n\n");
+       if (read_trylock(&tasklist_lock)) {
+               do_each_thread (g, t) {
+                       printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm);
+                       show_stack(t, NULL);
+               } while_each_thread (g, t);
+               read_unlock(&tasklist_lock);
+       }
+       return NOTIFY_DONE;
+}
+
 /*
  * C portion of the OS INIT handler
  *
@@ -1212,8 +1274,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
        static atomic_t slaves;
        static atomic_t monarchs;
        task_t *previous_current;
-       int cpu = smp_processor_id(), c;
-       struct task_struct *g, *t;
+       int cpu = smp_processor_id();
 
        oops_in_progress = 1;   /* FIXME: make printk NMI/MCA/INIT safe */
        console_loglevel = 15;  /* make sure printks make it to console */
@@ -1253,8 +1314,17 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
                ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT;
                while (monarch_cpu == -1)
                       cpu_relax();     /* spin until monarch enters */
+               if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, 0, 0, 0)
+                               == NOTIFY_STOP)
+                       ia64_mca_spin(__FUNCTION__);
+               if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, 0, 0, 0)
+                               == NOTIFY_STOP)
+                       ia64_mca_spin(__FUNCTION__);
                while (monarch_cpu != -1)
                       cpu_relax();     /* spin until monarch leaves */
+               if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, 0, 0, 0)
+                               == NOTIFY_STOP)
+                       ia64_mca_spin(__FUNCTION__);
                printk("Slave on cpu %d returning to normal service.\n", cpu);
                set_curr_task(cpu, previous_current);
                ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
@@ -1263,6 +1333,9 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
        }
 
        monarch_cpu = cpu;
+       if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
 
        /*
         * Wait for a bit.  On some machines (e.g., HP's zx2000 and zx6000, INIT can be
@@ -1273,27 +1346,16 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
        printk("Delaying for 5 seconds...\n");
        udelay(5*1000000);
        ia64_wait_for_slaves(cpu);
-       printk(KERN_ERR "Processes interrupted by INIT -");
-       for_each_online_cpu(c) {
-               struct ia64_sal_os_state *s;
-               t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET);
-               s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET);
-               g = s->prev_task;
-               if (g) {
-                       if (g->pid)
-                               printk(" %d", g->pid);
-                       else
-                               printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g);
-               }
-       }
-       printk("\n\n");
-       if (read_trylock(&tasklist_lock)) {
-               do_each_thread (g, t) {
-                       printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm);
-                       show_stack(t, NULL);
-               } while_each_thread (g, t);
-               read_unlock(&tasklist_lock);
-       }
+       /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through
+        * to default_monarch_init_process() above and just print all the
+        * tasks.
+        */
+       if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
+       if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, 0, 0, 0)
+                       == NOTIFY_STOP)
+               ia64_mca_spin(__FUNCTION__);
        printk("\nINIT dump complete.  Monarch on cpu %d returning to normal service.\n", cpu);
        atomic_dec(&monarchs);
        set_curr_task(cpu, previous_current);
@@ -1462,6 +1524,10 @@ ia64_mca_init(void)
        s64 rc;
        struct ia64_sal_retval isrv;
        u64 timeout = IA64_MCA_RENDEZ_TIMEOUT;  /* platform specific */
+       static struct notifier_block default_init_monarch_nb = {
+               .notifier_call = default_monarch_init_process,
+               .priority = 0/* we need to notified last */
+       };
 
        IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__);
 
@@ -1555,6 +1621,10 @@ ia64_mca_init(void)
                       "(status %ld)\n", rc);
                return;
        }
+       if (register_die_notifier(&default_init_monarch_nb)) {
+               printk(KERN_ERR "Failed to register default monarch INIT process\n");
+               return;
+       }
 
        IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__);
 
index 640d6908f8ec9727525f798fd306af5f981617eb..e92ea64d8040a807bc59800f266259859384683c 100644 (file)
@@ -4,6 +4,9 @@
  * Copyright (C) 1998-2003 Hewlett-Packard Co
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  * 04/11/17 Ashok Raj  <ashok.raj@intel.com> Added CPU Hotplug Support
+ *
+ * 2005-10-07 Keith Owens <kaos@sgi.com>
+ *           Add notify_die() hooks.
  */
 #define __KERNEL_SYSCALLS__    /* see <asm/unistd.h> */
 #include <linux/config.h>
@@ -34,6 +37,7 @@
 #include <asm/elf.h>
 #include <asm/ia32.h>
 #include <asm/irq.h>
+#include <asm/kdebug.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
@@ -808,12 +812,14 @@ cpu_halt (void)
 void
 machine_restart (char *restart_cmd)
 {
+       (void) notify_die(DIE_MACHINE_RESTART, restart_cmd, NULL, 0, 0, 0);
        (*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL);
 }
 
 void
 machine_halt (void)
 {
+       (void) notify_die(DIE_MACHINE_HALT, "", NULL, 0, 0, 0);
        cpu_halt();
 }
 
index f970359e7edf2fbb67117695c2f7b1a25f86b4d0..fba5fdd1f9689351dda3adf028e864ff8c05c0bf 100644 (file)
@@ -30,17 +30,20 @@ fpswa_interface_t *fpswa_interface;
 EXPORT_SYMBOL(fpswa_interface);
 
 struct notifier_block *ia64die_chain;
-static DEFINE_SPINLOCK(die_notifier_lock);
 
-int register_die_notifier(struct notifier_block *nb)
+int
+register_die_notifier(struct notifier_block *nb)
 {
-       int err = 0;
-       unsigned long flags;
-       spin_lock_irqsave(&die_notifier_lock, flags);
-       err = notifier_chain_register(&ia64die_chain, nb);
-       spin_unlock_irqrestore(&die_notifier_lock, flags);
-       return err;
+       return notifier_chain_register(&ia64die_chain, nb);
 }
+EXPORT_SYMBOL_GPL(register_die_notifier);
+
+int
+unregister_die_notifier(struct notifier_block *nb)
+{
+       return notifier_chain_unregister(&ia64die_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_die_notifier);
 
 void __init
 trap_init (void)
@@ -105,6 +108,7 @@ die (const char *str, struct pt_regs *regs, long err)
        if (++die.lock_owner_depth < 3) {
                printk("%s[%d]: %s %ld [%d]\n",
                        current->comm, current->pid, str, err, ++die_counter);
+               (void) notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
                show_regs(regs);
        } else
                printk(KERN_ERR "Recursive die() failure, output suppressed\n");
@@ -155,9 +159,8 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
        switch (break_num) {
              case 0: /* unknown error (used by GCC for __builtin_abort()) */
                if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP)
-                               == NOTIFY_STOP) {
+                               == NOTIFY_STOP)
                        return;
-               }
                die_if_kernel("bugcheck!", regs, break_num);
                sig = SIGILL; code = ILL_ILLOPC;
                break;
@@ -210,15 +213,6 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
                sig = SIGILL; code = __ILL_BNDMOD;
                break;
 
-             case 0x80200:
-             case 0x80300:
-               if (notify_die(DIE_BREAK, "kprobe", regs, break_num, TRAP_BRKPT, SIGTRAP)
-                               == NOTIFY_STOP) {
-                       return;
-               }
-               sig = SIGTRAP; code = TRAP_BRKPT;
-               break;
-
              default:
                if (break_num < 0x40000 || break_num > 0x100000)
                        die_if_kernel("Bad break", regs, break_num);
@@ -226,6 +220,9 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
                if (break_num < 0x80000) {
                        sig = SIGILL; code = __ILL_BREAK;
                } else {
+                       if (notify_die(DIE_BREAK, "bad break", regs, break_num, TRAP_BRKPT, SIGTRAP)
+                                       == NOTIFY_STOP)
+                               return;
                        sig = SIGTRAP; code = TRAP_BRKPT;
                }
        }
@@ -578,12 +575,11 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
 #endif
                        break;
                      case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
-                     case 36:
-                             if (notify_die(DIE_SS, "ss", &regs, vector,
-                                            vector, SIGTRAP) == NOTIFY_STOP)
-                                     return;
-                             siginfo.si_code = TRAP_TRACE; ifa = 0; break;
+                     case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
                }
+               if (notify_die(DIE_FAULT, "ia64_fault", &regs, vector, siginfo.si_code, SIGTRAP)
+                               == NOTIFY_STOP)
+                       return;
                siginfo.si_signo = SIGTRAP;
                siginfo.si_errno = 0;
                siginfo.si_addr  = (void __user *) ifa;
index 4d376e1663f7abec6f3a72310fbf7ede35be948f..8b01a083dde6f94dd391e042ccc641212fcf06a4 100644 (file)
@@ -22,6 +22,9 @@
  * 2005-Apr     Rusty Lynch <rusty.lynch@intel.com> and Anil S Keshavamurthy
  *              <anil.s.keshavamurthy@intel.com> adopted from
  *              include/asm-x86_64/kdebug.h
+ *
+ * 2005-Oct    Keith Owens <kaos@sgi.com>.  Expand notify_die to cover more
+ *             events.
  */
 #include <linux/notifier.h>
 
@@ -35,13 +38,36 @@ struct die_args {
        int signr;
 };
 
-int register_die_notifier(struct notifier_block *nb);
+extern int register_die_notifier(struct notifier_block *);
+extern int unregister_die_notifier(struct notifier_block *);
 extern struct notifier_block *ia64die_chain;
 
 enum die_val {
        DIE_BREAK = 1,
-       DIE_SS,
+       DIE_FAULT,
+       DIE_OOPS,
        DIE_PAGE_FAULT,
+       DIE_MACHINE_HALT,
+       DIE_MACHINE_RESTART,
+       DIE_MCA_MONARCH_ENTER,
+       DIE_MCA_MONARCH_PROCESS,
+       DIE_MCA_MONARCH_LEAVE,
+       DIE_MCA_SLAVE_ENTER,
+       DIE_MCA_SLAVE_PROCESS,
+       DIE_MCA_SLAVE_LEAVE,
+       DIE_MCA_RENDZVOUS_ENTER,
+       DIE_MCA_RENDZVOUS_PROCESS,
+       DIE_MCA_RENDZVOUS_LEAVE,
+       DIE_INIT_MONARCH_ENTER,
+       DIE_INIT_MONARCH_PROCESS,
+       DIE_INIT_MONARCH_LEAVE,
+       DIE_INIT_SLAVE_ENTER,
+       DIE_INIT_SLAVE_PROCESS,
+       DIE_INIT_SLAVE_LEAVE,
+       DIE_KDEBUG_ENTER,
+       DIE_KDEBUG_LEAVE,
+       DIE_KDUMP_ENTER,
+       DIE_KDUMP_LEAVE,
 };
 
 static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs,