[PATCH] Kprobes: Use RCU for (un)register synchronization - arch changes
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / ppc64 / kernel / kprobes.c
index 3f89f3e..e0a25b3 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/config.h>
 #include <linux/kprobes.h>
 #include <linux/ptrace.h>
-#include <linux/spinlock.h>
 #include <linux/preempt.h>
 #include <asm/cacheflush.h>
 #include <asm/kdebug.h>
@@ -125,6 +124,7 @@ static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
        kcb->kprobe_saved_msr = regs->msr;
 }
 
+/* Called with kretprobe_lock held */
 void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
                                      struct pt_regs *regs)
 {
@@ -152,8 +152,6 @@ static inline int kprobe_handler(struct pt_regs *regs)
 
        /* Check we're not actually recursing */
        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) {
                        kprobe_opcode_t insn = *p->ainsn.insn;
@@ -161,7 +159,6 @@ static inline int kprobe_handler(struct pt_regs *regs)
                                        is_trap(insn)) {
                                regs->msr &= ~MSR_SE;
                                regs->msr |= kcb->kprobe_saved_msr;
-                               unlock_kprobes();
                                goto no_kprobe;
                        }
                        /* We have reentered the kprobe_handler(), since
@@ -183,14 +180,11 @@ static inline int kprobe_handler(struct pt_regs *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 (*addr != BREAKPOINT_INSTRUCTION) {
                        /*
                         * PowerPC has multiple variants of the "trap"
@@ -254,9 +248,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
         struct kretprobe_instance *ri = NULL;
         struct hlist_head *head;
         struct hlist_node *node, *tmp;
-       unsigned long orig_ret_address = 0;
+       unsigned long flags, orig_ret_address = 0;
        unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 
+       spin_lock_irqsave(&kretprobe_lock, flags);
         head = kretprobe_inst_table_head(current);
 
        /*
@@ -296,7 +291,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
        regs->nip = orig_ret_address;
 
        reset_current_kprobe();
-       unlock_kprobes();
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
        preempt_enable_no_resched();
 
         /*
@@ -348,7 +343,6 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
                goto out;
        }
        reset_current_kprobe();
-       unlock_kprobes();
 out:
        preempt_enable_no_resched();
 
@@ -363,7 +357,6 @@ out:
        return 1;
 }
 
-/* Interrupts disabled, kprobe_lock held. */
 static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
        struct kprobe *cur = kprobe_running();
@@ -378,7 +371,6 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
                regs->msr |= kcb->kprobe_saved_msr;
 
                reset_current_kprobe();
-               unlock_kprobes();
                preempt_enable_no_resched();
        }
        return 0;
@@ -393,11 +385,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
        struct die_args *args = (struct die_args *)data;
        int ret = NOTIFY_DONE;
 
-       /*
-        * Interrupts are not disabled here.  We need to disable
-        * preemption, because kprobe_running() uses smp_processor_id().
-        */
-       preempt_disable();
+       rcu_read_lock();
        switch (val) {
        case DIE_BPT:
                if (kprobe_handler(args->regs))
@@ -415,7 +403,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
        default:
                break;
        }
-       preempt_enable_no_resched();
+       rcu_read_unlock();
        return ret;
 }