Commit 36721656 authored by mao, bibo's avatar mao, bibo Committed by Linus Torvalds

[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: default avatarbibo, 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: default avatarSatoshi Oshima <soshima@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 585deaca
......@@ -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;
......
......@@ -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)
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,8 +389,10 @@ 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;
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);
......@@ -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);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment