]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/kprobes.c
kprobes: cleanup aggr_kprobe related code
[linux-2.6-omap-h63xx.git] / kernel / kprobes.c
index 5016bfb682b9c54393d017ee1a070515191c05c9..a55bfadfd76642b54b540adbc7bbddb25f0474f5 100644 (file)
@@ -518,20 +518,20 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
 }
 
 /*
-* Add the new probe to old_p->list. Fail if this is the
+* Add the new probe to ap->list. Fail if this is the
 * second jprobe at the address - two jprobes can't coexist
 */
-static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
+static int __kprobes add_new_kprobe(struct kprobe *ap, struct kprobe *p)
 {
        if (p->break_handler) {
-               if (old_p->break_handler)
+               if (ap->break_handler)
                        return -EEXIST;
-               list_add_tail_rcu(&p->list, &old_p->list);
-               old_p->break_handler = aggr_break_handler;
+               list_add_tail_rcu(&p->list, &ap->list);
+               ap->break_handler = aggr_break_handler;
        } else
-               list_add_rcu(&p->list, &old_p->list);
-       if (p->post_handler && !old_p->post_handler)
-               old_p->post_handler = aggr_post_handler;
+               list_add_rcu(&p->list, &ap->list);
+       if (p->post_handler && !ap->post_handler)
+               ap->post_handler = aggr_post_handler;
        return 0;
 }
 
@@ -544,6 +544,7 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
        copy_kprobe(p, ap);
        flush_insn_slot(ap);
        ap->addr = p->addr;
+       ap->flags = p->flags;
        ap->pre_handler = aggr_pre_handler;
        ap->fault_handler = aggr_fault_handler;
        /* We don't care the kprobe which has gone. */
@@ -566,44 +567,43 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p,
                                          struct kprobe *p)
 {
        int ret = 0;
-       struct kprobe *ap;
+       struct kprobe *ap = old_p;
 
-       if (kprobe_gone(old_p)) {
+       if (old_p->pre_handler != aggr_pre_handler) {
+               /* If old_p is not an aggr_probe, create new aggr_kprobe. */
+               ap = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
+               if (!ap)
+                       return -ENOMEM;
+               add_aggr_kprobe(ap, old_p);
+       }
+
+       if (kprobe_gone(ap)) {
                /*
                 * Attempting to insert new probe at the same location that
                 * had a probe in the module vaddr area which already
                 * freed. So, the instruction slot has already been
                 * released. We need a new slot for the new probe.
                 */
-               ret = arch_prepare_kprobe(old_p);
+               ret = arch_prepare_kprobe(ap);
                if (ret)
+                       /*
+                        * Even if fail to allocate new slot, don't need to
+                        * free aggr_probe. It will be used next time, or
+                        * freed by unregister_kprobe.
+                        */
                        return ret;
-       }
-       if (old_p->pre_handler == aggr_pre_handler) {
-               copy_kprobe(old_p, p);
-               ret = add_new_kprobe(old_p, p);
-               ap = old_p;
-       } else {
-               ap = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
-               if (!ap) {
-                       if (kprobe_gone(old_p))
-                               arch_remove_kprobe(old_p);
-                       return -ENOMEM;
-               }
-               add_aggr_kprobe(ap, old_p);
-               copy_kprobe(ap, p);
-               ret = add_new_kprobe(ap, p);
-       }
-       if (kprobe_gone(old_p)) {
+               /* Clear gone flag to prevent allocating new slot again. */
+               ap->flags &= ~KPROBE_FLAG_GONE;
                /*
                 * If the old_p has gone, its breakpoint has been disarmed.
                 * We have to arm it again after preparing real kprobes.
                 */
-               ap->flags &= ~KPROBE_FLAG_GONE;
                if (kprobe_enabled)
                        arch_arm_kprobe(ap);
        }
-       return ret;
+
+       copy_kprobe(ap, p);
+       return add_new_kprobe(ap, p);
 }
 
 static int __kprobes in_kprobes_functions(unsigned long addr)