Pull altix-ce1.0-asic into release branch
[pandora-kernel.git] / arch / sparc64 / kernel / kprobes.c
index b959841..b9a9ce7 100644 (file)
@@ -42,15 +42,11 @@ DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
-{
-       return 0;
-}
-
-void __kprobes arch_copy_kprobe(struct kprobe *p)
 {
        p->ainsn.insn[0] = *p->addr;
        p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
        p->opcode = *p->addr;
+       return 0;
 }
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
@@ -65,10 +61,6 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
        flushi(p->addr);
 }
 
-void __kprobes arch_remove_kprobe(struct kprobe *p)
-{
-}
-
 static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
 {
        kcb->prev_kprobe.kp = kprobe_running();
@@ -113,18 +105,21 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
        struct kprobe *p;
        void *addr = (void *) regs->tpc;
        int ret = 0;
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       struct kprobe_ctlblk *kcb;
+
+       /*
+        * We don't want to be preempted for the entire
+        * duration of kprobe processing
+        */
+       preempt_disable();
+       kcb = get_kprobe_ctlblk();
 
        if (kprobe_running()) {
-               /* We *are* holding lock here, so this is safe.
-                * Disarm the probe we just hit, and ignore it.
-                */
                p = get_kprobe(addr);
                if (p) {
                        if (kcb->kprobe_status == KPROBE_HIT_SS) {
                                regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
                                        kcb->kprobe_orig_tstate_pil);
-                               unlock_kprobes();
                                goto no_kprobe;
                        }
                        /* We have reentered the kprobe_handler(), since
@@ -135,23 +130,28 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
                         */
                        save_previous_kprobe(kcb);
                        set_current_kprobe(p, regs, kcb);
-                       p->nmissed++;
+                       kprobes_inc_nmissed_count(p);
                        kcb->kprobe_status = KPROBE_REENTER;
                        prepare_singlestep(p, regs, kcb);
                        return 1;
                } else {
+                       if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) {
+                       /* The breakpoint instruction was removed by
+                        * another cpu right after we hit, no further
+                        * handling of this interrupt is appropriate
+                        */
+                               ret = 1;
+                               goto no_kprobe;
+                       }
                        p = __get_cpu_var(current_kprobe);
                        if (p->break_handler && p->break_handler(p, regs))
                                goto ss_probe;
                }
-               /* If it's not ours, can't be delete race, (we hold lock). */
                goto no_kprobe;
        }
 
-       lock_kprobes();
        p = get_kprobe(addr);
        if (!p) {
-               unlock_kprobes();
                if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) {
                        /*
                         * The breakpoint instruction was removed right
@@ -166,11 +166,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
                goto no_kprobe;
        }
 
-       /*
-        * This preempt_disable() matches the preempt_enable_no_resched()
-        * in post_kprobes_handler()
-        */
-       preempt_disable();
        set_current_kprobe(p, regs, kcb);
        kcb->kprobe_status = KPROBE_HIT_ACTIVE;
        if (p->pre_handler && p->pre_handler(p, regs))
@@ -182,6 +177,7 @@ ss_probe:
        return 1;
 
 no_kprobe:
+       preempt_enable_no_resched();
        return ret;
 }
 
@@ -296,14 +292,12 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
                goto out;
        }
        reset_current_kprobe();
-       unlock_kprobes();
 out:
        preempt_enable_no_resched();
 
        return 1;
 }
 
-/* Interrupts disabled, kprobe_lock held. */
 static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
        struct kprobe *cur = kprobe_running();
@@ -316,7 +310,6 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
                resume_execution(cur, regs, kcb);
 
                reset_current_kprobe();
-               unlock_kprobes();
                preempt_enable_no_resched();
        }
        return 0;
@@ -331,7 +324,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
        struct die_args *args = (struct die_args *)data;
        int ret = NOTIFY_DONE;
 
-       preempt_disable();
        switch (val) {
        case DIE_DEBUG:
                if (kprobe_handler(args->regs))
@@ -343,14 +335,16 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
                break;
        case DIE_GPF:
        case DIE_PAGE_FAULT:
+               /* kprobe_running() needs smp_processor_id() */
+               preempt_disable();
                if (kprobe_running() &&
                    kprobe_fault_handler(args->regs, args->trapnr))
                        ret = NOTIFY_STOP;
+               preempt_enable();
                break;
        default:
                break;
        }
-       preempt_enable();
        return ret;
 }
 
@@ -436,6 +430,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
                       &(kcb->jprobe_saved_stack),
                       sizeof(kcb->jprobe_saved_stack));
 
+               preempt_enable_no_resched();
                return 1;
        }
        return 0;