diff options
-rw-r--r-- | arch/powerpc/kernel/kprobes.c | 3 | ||||
-rw-r--r-- | arch/x86_64/kernel/kprobes.c | 4 | ||||
-rw-r--r-- | kernel/kprobes.c | 32 |
3 files changed, 20 insertions, 19 deletions
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 331e169e8629..2cd32dd6898b 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <asm/kdebug.h> | 35 | #include <asm/kdebug.h> |
36 | #include <asm/sstep.h> | 36 | #include <asm/sstep.h> |
37 | 37 | ||
38 | static DECLARE_MUTEX(kprobe_mutex); | ||
39 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | 38 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
40 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 39 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); |
41 | 40 | ||
@@ -54,9 +53,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
54 | 53 | ||
55 | /* insn must be on a special executable page on ppc64 */ | 54 | /* insn must be on a special executable page on ppc64 */ |
56 | if (!ret) { | 55 | if (!ret) { |
57 | down(&kprobe_mutex); | ||
58 | p->ainsn.insn = get_insn_slot(); | 56 | p->ainsn.insn = get_insn_slot(); |
59 | up(&kprobe_mutex); | ||
60 | if (!p->ainsn.insn) | 57 | if (!p->ainsn.insn) |
61 | ret = -ENOMEM; | 58 | ret = -ENOMEM; |
62 | } | 59 | } |
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index 8b8943bfb89e..128e18190f99 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #include <asm/kdebug.h> | 43 | #include <asm/kdebug.h> |
44 | 44 | ||
45 | void jprobe_return_end(void); | 45 | void jprobe_return_end(void); |
46 | void __kprobes arch_copy_kprobe(struct kprobe *p); | 46 | static void __kprobes arch_copy_kprobe(struct kprobe *p); |
47 | 47 | ||
48 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | 48 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
49 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 49 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); |
@@ -180,7 +180,7 @@ static inline s32 *is_riprel(u8 *insn) | |||
180 | return NULL; | 180 | return NULL; |
181 | } | 181 | } |
182 | 182 | ||
183 | void __kprobes arch_copy_kprobe(struct kprobe *p) | 183 | static void __kprobes arch_copy_kprobe(struct kprobe *p) |
184 | { | 184 | { |
185 | s32 *ripdisp; | 185 | s32 *ripdisp; |
186 | memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE); | 186 | memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE); |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index f14ccd35e9b6..f1c0e61a2cb4 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -431,7 +431,7 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p, | |||
431 | copy_kprobe(old_p, p); | 431 | copy_kprobe(old_p, p); |
432 | ret = add_new_kprobe(old_p, p); | 432 | ret = add_new_kprobe(old_p, p); |
433 | } else { | 433 | } else { |
434 | ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC); | 434 | ap = kcalloc(1, sizeof(struct kprobe), GFP_KERNEL); |
435 | if (!ap) | 435 | if (!ap) |
436 | return -ENOMEM; | 436 | return -ENOMEM; |
437 | add_aggr_kprobe(ap, old_p); | 437 | add_aggr_kprobe(ap, old_p); |
@@ -491,7 +491,8 @@ out: | |||
491 | void __kprobes unregister_kprobe(struct kprobe *p) | 491 | void __kprobes unregister_kprobe(struct kprobe *p) |
492 | { | 492 | { |
493 | struct module *mod; | 493 | struct module *mod; |
494 | struct kprobe *old_p, *cleanup_p; | 494 | struct kprobe *old_p, *list_p; |
495 | int cleanup_p; | ||
495 | 496 | ||
496 | down(&kprobe_mutex); | 497 | down(&kprobe_mutex); |
497 | old_p = get_kprobe(p->addr); | 498 | old_p = get_kprobe(p->addr); |
@@ -499,22 +500,25 @@ void __kprobes unregister_kprobe(struct kprobe *p) | |||
499 | up(&kprobe_mutex); | 500 | up(&kprobe_mutex); |
500 | return; | 501 | return; |
501 | } | 502 | } |
502 | 503 | if (p != old_p) { | |
503 | if ((old_p->pre_handler == aggr_pre_handler) && | 504 | list_for_each_entry_rcu(list_p, &old_p->list, list) |
505 | if (list_p == p) | ||
506 | /* kprobe p is a valid probe */ | ||
507 | goto valid_p; | ||
508 | up(&kprobe_mutex); | ||
509 | return; | ||
510 | } | ||
511 | valid_p: | ||
512 | if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) && | ||
504 | (p->list.next == &old_p->list) && | 513 | (p->list.next == &old_p->list) && |
505 | (p->list.prev == &old_p->list)) { | 514 | (p->list.prev == &old_p->list))) { |
506 | /* Only one element in the aggregate list */ | 515 | /* Only probe on the hash list */ |
507 | arch_disarm_kprobe(p); | 516 | arch_disarm_kprobe(p); |
508 | hlist_del_rcu(&old_p->hlist); | 517 | hlist_del_rcu(&old_p->hlist); |
509 | cleanup_p = old_p; | 518 | cleanup_p = 1; |
510 | } else if (old_p == p) { | ||
511 | /* Only one kprobe element in the hash list */ | ||
512 | arch_disarm_kprobe(p); | ||
513 | hlist_del_rcu(&p->hlist); | ||
514 | cleanup_p = p; | ||
515 | } else { | 519 | } else { |
516 | list_del_rcu(&p->list); | 520 | list_del_rcu(&p->list); |
517 | cleanup_p = NULL; | 521 | cleanup_p = 0; |
518 | } | 522 | } |
519 | 523 | ||
520 | up(&kprobe_mutex); | 524 | up(&kprobe_mutex); |
@@ -524,7 +528,7 @@ void __kprobes unregister_kprobe(struct kprobe *p) | |||
524 | module_put(mod); | 528 | module_put(mod); |
525 | 529 | ||
526 | if (cleanup_p) { | 530 | if (cleanup_p) { |
527 | if (cleanup_p->pre_handler == aggr_pre_handler) { | 531 | if (p != old_p) { |
528 | list_del_rcu(&p->list); | 532 | list_del_rcu(&p->list); |
529 | kfree(old_p); | 533 | kfree(old_p); |
530 | } | 534 | } |