Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+5 −11
Original line number Diff line number Diff line
@@ -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;
+24 −8
Original line number Diff line number Diff line
@@ -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 @@ 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);
	}
}