[PATCH] kprobe-booster: boosting multi-probe

From: bibo,mao
Date: Wed Apr 26 2006 - 05:33:28 EST


Andrew,
If there are multi kprobes on the same probepoint, there
will be one extra aggr_kprobe on the head of kprobe list.
The aggr_kprobe has aggr_post_handler/aggr_break_handler
whether the other kprobe post_hander/break_handler is NULL
or not. This patch modifies this, only when there is one or
more kprobe in the list whose post_handler is not NULL,
post_handler of aggr_kprobe will be set as aggr_post_handler.

Signed-off-by: bibo, mao <bibo.mao@xxxxxxxxx>

Thanks
bibo,mao
diff -Nruap 2.6.17-rc1-mm3.org/arch/i386/kernel/kprobes.c 2.6.17-rc1-mm3/arch/i386/kernel/kprobes.c
--- 2.6.17-rc1-mm3.org/arch/i386/kernel/kprobes.c 2006-04-26 15:52:24.000000000 +0800
+++ 2.6.17-rc1-mm3/arch/i386/kernel/kprobes.c 2006-04-26 16:18:50.000000000 +0800
@@ -206,9 +206,7 @@ static int __kprobes kprobe_handler(stru
int ret = 0;
kprobe_opcode_t *addr;
struct kprobe_ctlblk *kcb;
-#ifdef CONFIG_PREEMPT
unsigned pre_preempt_count = preempt_count();
-#endif /* CONFIG_PREEMPT */

addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));

@@ -294,22 +292,14 @@ static int __kprobes kprobe_handler(stru
/* handler has already set things up, so skip ss setup */
return 1;

- if (p->ainsn.boostable == 1 &&
-#ifdef CONFIG_PREEMPT
- !(pre_preempt_count) && /*
- * This enables booster when the direct
- * execution path aren't preempted.
- */
-#endif /* CONFIG_PREEMPT */
- !p->post_handler && !p->break_handler ) {
+ss_probe:
+ if (pre_preempt_count && p->ainsn.boostable == 1 && !p->post_handler){
/* Boost up -- we can execute copied instructions directly */
reset_current_kprobe();
regs->eip = (unsigned long)p->ainsn.insn;
preempt_enable_no_resched();
return 1;
}
-
-ss_probe:
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;
diff -Nruap 2.6.17-rc1-mm3.org/kernel/kprobes.c 2.6.17-rc1-mm3/kernel/kprobes.c
--- 2.6.17-rc1-mm3.org/kernel/kprobes.c 2006-04-26 15:52:24.000000000 +0800
+++ 2.6.17-rc1-mm3/kernel/kprobes.c 2006-04-26 16:09:14.000000000 +0800
@@ -368,16 +368,15 @@ static inline void copy_kprobe(struct kp
*/
static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
{
- struct kprobe *kp;
-
if (p->break_handler) {
- list_for_each_entry_rcu(kp, &old_p->list, list) {
- if (kp->break_handler)
- return -EEXIST;
- }
+ if (old_p->break_handler)
+ return -EEXIST;
list_add_tail_rcu(&p->list, &old_p->list);
+ old_p->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;
return 0;
}

@@ -390,9 +389,11 @@ static inline void add_aggr_kprobe(struc
copy_kprobe(p, ap);
ap->addr = p->addr;
ap->pre_handler = aggr_pre_handler;
- ap->post_handler = aggr_post_handler;
ap->fault_handler = aggr_fault_handler;
- ap->break_handler = aggr_break_handler;
+ if (p->post_handler)
+ ap->post_handler = aggr_post_handler;
+ if (p->break_handler)
+ ap->break_handler = aggr_break_handler;

INIT_LIST_HEAD(&ap->list);
list_add_rcu(&p->list, &ap->list);
@@ -536,6 +537,21 @@ valid_p:
kfree(old_p);
}
arch_remove_kprobe(p);
+ } else {
+ mutex_lock(&kprobe_mutex);
+ if (p->break_handler)
+ old_p->break_handler = NULL;
+ if (p->post_handler){
+ list_for_each_entry_rcu(list_p, &old_p->list, list){
+ if (list_p->post_handler){
+ cleanup_p = 2;
+ break;
+ }
+ }
+ if (cleanup_p == 0)
+ old_p->post_handler = NULL;
+ }
+ mutex_unlock(&kprobe_mutex);
}
}