[PATCH] Kprobe: multi kprobe posthandler for booster

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.

[soshima@redhat.com: !CONFIG_PREEMPT fix]
Signed-off-by: bibo, mao <bibo.mao@intel.com>
Cc: Masami Hiramatsu <hiramatu@sdl.hitachi.co.jp>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: "Keshavamurthy, Anil S" <anil.s.keshavamurthy@intel.com>
Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Yumiko Sugita <sugita@sdl.hitachi.co.jp>
Cc: Hideo Aoki <haoki@redhat.com>
Signed-off-by: Satoshi Oshima <soshima@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
mao, bibo 2006-06-26 00:25:22 -07:00 committed by Linus Torvalds
parent 585deacaca
commit 3672165677
2 changed files with 29 additions and 19 deletions

View file

@ -259,7 +259,9 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
struct kprobe_ctlblk *kcb;
#ifdef CONFIG_PREEMPT
unsigned pre_preempt_count = preempt_count();
#endif /* CONFIG_PREEMPT */
#else
unsigned pre_preempt_count = 1;
#endif
addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
@ -336,22 +338,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
/* 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;

View file

@ -368,16 +368,15 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
*/
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(struct kprobe *ap, struct kprobe *p)
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 @@ void __kprobes unregister_kprobe(struct kprobe *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);
}
}