Merge git://oss.sgi.com:8090/oss/git/xfs-2.6
[powerpc.git] / arch / x86_64 / kernel / kprobes.c
index afe11f4..14f0ced 100644 (file)
@@ -42,8 +42,8 @@
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
 
-static DECLARE_MUTEX(kprobe_mutex);
 void jprobe_return_end(void);
+static void __kprobes arch_copy_kprobe(struct kprobe *p);
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -69,12 +69,11 @@ static inline int is_IF_modifier(kprobe_opcode_t *insn)
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        /* insn: must be on special executable page on x86_64. */
-       down(&kprobe_mutex);
        p->ainsn.insn = get_insn_slot();
-       up(&kprobe_mutex);
        if (!p->ainsn.insn) {
                return -ENOMEM;
        }
+       arch_copy_kprobe(p);
        return 0;
 }
 
@@ -181,7 +180,7 @@ static inline s32 *is_riprel(u8 *insn)
        return NULL;
 }
 
-void __kprobes arch_copy_kprobe(struct kprobe *p)
+static void __kprobes arch_copy_kprobe(struct kprobe *p)
 {
        s32 *ripdisp;
        memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
@@ -223,9 +222,9 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
-       down(&kprobe_mutex);
+       mutex_lock(&kprobe_mutex);
        free_insn_slot(p->ainsn.insn);
-       up(&kprobe_mutex);
+       mutex_unlock(&kprobe_mutex);
 }
 
 static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
@@ -335,6 +334,15 @@ int __kprobes kprobe_handler(struct pt_regs *regs)
                                return 1;
                        }
                } else {
+                       if (*addr != BREAKPOINT_INSTRUCTION) {
+                       /* The breakpoint instruction was removed by
+                        * another cpu right after we hit, no further
+                        * handling of this interrupt is appropriate
+                        */
+                               regs->rip = (unsigned long)addr;
+                               ret = 1;
+                               goto no_kprobe;
+                       }
                        p = __get_cpu_var(current_kprobe);
                        if (p->break_handler && p->break_handler(p, regs)) {
                                goto ss_probe;