vserver 1.9.5.x5
[linux-2.6.git] / kernel / kprobes.c
index ca4e28b..4a331ae 100644 (file)
@@ -43,7 +43,7 @@
 static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
 
 unsigned int kprobe_cpu = NR_CPUS;
-static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(kprobe_lock);
 
 /* Locks kprobe: irqs must be disabled */
 void lock_kprobes(void)
@@ -76,30 +76,37 @@ struct kprobe *get_kprobe(void *addr)
 int register_kprobe(struct kprobe *p)
 {
        int ret = 0;
-       unsigned long flags;
+       unsigned long flags = 0;
 
+       if ((ret = arch_prepare_kprobe(p)) != 0) {
+               goto out;
+       }
        spin_lock_irqsave(&kprobe_lock, flags);
        INIT_HLIST_NODE(&p->hlist);
        if (get_kprobe(p->addr)) {
                ret = -EEXIST;
                goto out;
        }
+       arch_copy_kprobe(p);
+
        hlist_add_head(&p->hlist,
                       &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
 
-       arch_prepare_kprobe(p);
        p->opcode = *p->addr;
        *p->addr = BREAKPOINT_INSTRUCTION;
        flush_icache_range((unsigned long) p->addr,
                           (unsigned long) p->addr + sizeof(kprobe_opcode_t));
       out:
        spin_unlock_irqrestore(&kprobe_lock, flags);
+       if (ret == -EEXIST)
+               arch_remove_kprobe(p);
        return ret;
 }
 
 void unregister_kprobe(struct kprobe *p)
 {
        unsigned long flags;
+       arch_remove_kprobe(p);
        spin_lock_irqsave(&kprobe_lock, flags);
        *p->addr = p->opcode;
        hlist_del(&p->hlist);