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) ...@@ -259,7 +259,9 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
struct kprobe_ctlblk *kcb; struct kprobe_ctlblk *kcb;
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
unsigned pre_preempt_count = preempt_count(); 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)); addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
...@@ -336,22 +338,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ...@@ -336,22 +338,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
/* handler has already set things up, so skip ss setup */ /* handler has already set things up, so skip ss setup */
return 1; return 1;
if (p->ainsn.boostable == 1 && ss_probe:
#ifdef CONFIG_PREEMPT if (pre_preempt_count && p->ainsn.boostable == 1 && !p->post_handler){
!(pre_preempt_count) && /*
* This enables booster when the direct
* execution path aren't preempted.
*/
#endif /* CONFIG_PREEMPT */
!p->post_handler && !p->break_handler ) {
/* Boost up -- we can execute copied instructions directly */ /* Boost up -- we can execute copied instructions directly */
reset_current_kprobe(); reset_current_kprobe();
regs->eip = (unsigned long)p->ainsn.insn; regs->eip = (unsigned long)p->ainsn.insn;
preempt_enable_no_resched(); preempt_enable_no_resched();
return 1; return 1;
} }
ss_probe:
prepare_singlestep(p, regs); prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS; kcb->kprobe_status = KPROBE_HIT_SS;
return 1; return 1;
......
...@@ -368,16 +368,15 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p) ...@@ -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) static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
{ {
struct kprobe *kp;
if (p->break_handler) { if (p->break_handler) {
list_for_each_entry_rcu(kp, &old_p->list, list) { if (old_p->break_handler)
if (kp->break_handler) return -EEXIST;
return -EEXIST;
}
list_add_tail_rcu(&p->list, &old_p->list); list_add_tail_rcu(&p->list, &old_p->list);
old_p->break_handler = aggr_break_handler;
} else } else
list_add_rcu(&p->list, &old_p->list); 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; return 0;
} }
...@@ -390,9 +389,11 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p) ...@@ -390,9 +389,11 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
copy_kprobe(p, ap); copy_kprobe(p, ap);
ap->addr = p->addr; ap->addr = p->addr;
ap->pre_handler = aggr_pre_handler; ap->pre_handler = aggr_pre_handler;
ap->post_handler = aggr_post_handler;
ap->fault_handler = aggr_fault_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); INIT_LIST_HEAD(&ap->list);
list_add_rcu(&p->list, &ap->list); list_add_rcu(&p->list, &ap->list);
...@@ -536,6 +537,21 @@ void __kprobes unregister_kprobe(struct kprobe *p) ...@@ -536,6 +537,21 @@ void __kprobes unregister_kprobe(struct kprobe *p)
kfree(old_p); kfree(old_p);
} }
arch_remove_kprobe(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