aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kprobes.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 507f26e7ae7c..64aab081153b 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -47,11 +47,17 @@
47 47
48static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; 48static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
49static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; 49static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
50static atomic_t kprobe_count;
50 51
51DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */ 52DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
52DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ 53DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
53static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; 54static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
54 55
56static struct notifier_block kprobe_page_fault_nb = {
57 .notifier_call = kprobe_exceptions_notify,
58 .priority = 0x7fffffff /* we need to notified first */
59};
60
55#ifdef __ARCH_WANT_KPROBES_INSN_SLOT 61#ifdef __ARCH_WANT_KPROBES_INSN_SLOT
56/* 62/*
57 * kprobe->ainsn.insn points to the copy of the instruction to be 63 * kprobe->ainsn.insn points to the copy of the instruction to be
@@ -465,6 +471,8 @@ static int __kprobes __register_kprobe(struct kprobe *p,
465 old_p = get_kprobe(p->addr); 471 old_p = get_kprobe(p->addr);
466 if (old_p) { 472 if (old_p) {
467 ret = register_aggr_kprobe(old_p, p); 473 ret = register_aggr_kprobe(old_p, p);
474 if (!ret)
475 atomic_inc(&kprobe_count);
468 goto out; 476 goto out;
469 } 477 }
470 478
@@ -475,6 +483,10 @@ static int __kprobes __register_kprobe(struct kprobe *p,
475 hlist_add_head_rcu(&p->hlist, 483 hlist_add_head_rcu(&p->hlist,
476 &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); 484 &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
477 485
486 if (atomic_add_return(1, &kprobe_count) == \
487 (ARCH_INACTIVE_KPROBE_COUNT + 1))
488 register_page_fault_notifier(&kprobe_page_fault_nb);
489
478 arch_arm_kprobe(p); 490 arch_arm_kprobe(p);
479 491
480out: 492out:
@@ -553,6 +565,16 @@ valid_p:
553 } 565 }
554 mutex_unlock(&kprobe_mutex); 566 mutex_unlock(&kprobe_mutex);
555 } 567 }
568
569 /* Call unregister_page_fault_notifier()
570 * if no probes are active
571 */
572 mutex_lock(&kprobe_mutex);
573 if (atomic_add_return(-1, &kprobe_count) == \
574 ARCH_INACTIVE_KPROBE_COUNT)
575 unregister_page_fault_notifier(&kprobe_page_fault_nb);
576 mutex_unlock(&kprobe_mutex);
577 return;
556} 578}
557 579
558static struct notifier_block kprobe_exceptions_nb = { 580static struct notifier_block kprobe_exceptions_nb = {
@@ -560,10 +582,6 @@ static struct notifier_block kprobe_exceptions_nb = {
560 .priority = 0x7fffffff /* we need to be notified first */ 582 .priority = 0x7fffffff /* we need to be notified first */
561}; 583};
562 584
563static struct notifier_block kprobe_page_fault_nb = {
564 .notifier_call = kprobe_exceptions_notify,
565 .priority = 0x7fffffff /* we need to notified first */
566};
567 585
568int __kprobes register_jprobe(struct jprobe *jp) 586int __kprobes register_jprobe(struct jprobe *jp)
569{ 587{
@@ -673,14 +691,12 @@ static int __init init_kprobes(void)
673 INIT_HLIST_HEAD(&kprobe_table[i]); 691 INIT_HLIST_HEAD(&kprobe_table[i]);
674 INIT_HLIST_HEAD(&kretprobe_inst_table[i]); 692 INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
675 } 693 }
694 atomic_set(&kprobe_count, 0);
676 695
677 err = arch_init_kprobes(); 696 err = arch_init_kprobes();
678 if (!err) 697 if (!err)
679 err = register_die_notifier(&kprobe_exceptions_nb); 698 err = register_die_notifier(&kprobe_exceptions_nb);
680 699
681 if (!err)
682 err = register_page_fault_notifier(&kprobe_page_fault_nb);
683
684 return err; 700 return err;
685} 701}
686 702