diff options
| author | Masami Hiramatsu <mhiramat@redhat.com> | 2008-04-28 05:14:29 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 11:58:32 -0400 |
| commit | 4a296e07c3a410c09b9155da4c2fa84a07964f38 (patch) | |
| tree | d6070555a2ddf026a7c8534689b425c0e931dcfe /kernel | |
| parent | 9861668f747895608cea425f8457989d8dd2edf2 (diff) | |
kprobes: add (un)register_kretprobes for batch registration
Introduce unregister_/register_kretprobes() for kretprobe batch registration.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Cc: Shaohua Li <shaohua.li@intel.com>
Cc: David Miller <davem@davemloft.net>
Cc: "Frank Ch. Eigler" <fche@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kprobes.c | 108 |
1 files changed, 88 insertions, 20 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 76275fc025a5..5e3144ad9b64 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -429,6 +429,21 @@ static inline void free_rp_inst(struct kretprobe *rp) | |||
| 429 | } | 429 | } |
| 430 | } | 430 | } |
| 431 | 431 | ||
| 432 | static void __kprobes cleanup_rp_inst(struct kretprobe *rp) | ||
| 433 | { | ||
| 434 | unsigned long flags; | ||
| 435 | struct kretprobe_instance *ri; | ||
| 436 | struct hlist_node *pos, *next; | ||
| 437 | /* No race here */ | ||
| 438 | spin_lock_irqsave(&kretprobe_lock, flags); | ||
| 439 | hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) { | ||
| 440 | ri->rp = NULL; | ||
| 441 | hlist_del(&ri->uflist); | ||
| 442 | } | ||
| 443 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
| 444 | free_rp_inst(rp); | ||
| 445 | } | ||
| 446 | |||
| 432 | /* | 447 | /* |
| 433 | * Keep all fields in the kprobe consistent | 448 | * Keep all fields in the kprobe consistent |
| 434 | */ | 449 | */ |
| @@ -798,7 +813,8 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, | |||
| 798 | return 0; | 813 | return 0; |
| 799 | } | 814 | } |
| 800 | 815 | ||
| 801 | int __kprobes register_kretprobe(struct kretprobe *rp) | 816 | static int __kprobes __register_kretprobe(struct kretprobe *rp, |
| 817 | unsigned long called_from) | ||
| 802 | { | 818 | { |
| 803 | int ret = 0; | 819 | int ret = 0; |
| 804 | struct kretprobe_instance *inst; | 820 | struct kretprobe_instance *inst; |
| @@ -844,43 +860,93 @@ int __kprobes register_kretprobe(struct kretprobe *rp) | |||
| 844 | 860 | ||
| 845 | rp->nmissed = 0; | 861 | rp->nmissed = 0; |
| 846 | /* Establish function entry probe point */ | 862 | /* Establish function entry probe point */ |
| 847 | if ((ret = __register_kprobe(&rp->kp, | 863 | ret = __register_kprobe(&rp->kp, called_from); |
| 848 | (unsigned long)__builtin_return_address(0))) != 0) | 864 | if (ret != 0) |
| 849 | free_rp_inst(rp); | 865 | free_rp_inst(rp); |
| 850 | return ret; | 866 | return ret; |
| 851 | } | 867 | } |
| 852 | 868 | ||
| 869 | static int __register_kretprobes(struct kretprobe **rps, int num, | ||
| 870 | unsigned long called_from) | ||
| 871 | { | ||
| 872 | int ret = 0, i; | ||
| 873 | |||
| 874 | if (num <= 0) | ||
| 875 | return -EINVAL; | ||
| 876 | for (i = 0; i < num; i++) { | ||
| 877 | ret = __register_kretprobe(rps[i], called_from); | ||
| 878 | if (ret < 0 && i > 0) { | ||
| 879 | unregister_kretprobes(rps, i); | ||
| 880 | break; | ||
| 881 | } | ||
| 882 | } | ||
| 883 | return ret; | ||
| 884 | } | ||
| 885 | |||
| 886 | int __kprobes register_kretprobe(struct kretprobe *rp) | ||
| 887 | { | ||
| 888 | return __register_kretprobes(&rp, 1, | ||
| 889 | (unsigned long)__builtin_return_address(0)); | ||
| 890 | } | ||
| 891 | |||
| 892 | void __kprobes unregister_kretprobe(struct kretprobe *rp) | ||
| 893 | { | ||
| 894 | unregister_kretprobes(&rp, 1); | ||
| 895 | } | ||
| 896 | |||
| 897 | int __kprobes register_kretprobes(struct kretprobe **rps, int num) | ||
| 898 | { | ||
| 899 | return __register_kretprobes(rps, num, | ||
| 900 | (unsigned long)__builtin_return_address(0)); | ||
| 901 | } | ||
| 902 | |||
| 903 | void __kprobes unregister_kretprobes(struct kretprobe **rps, int num) | ||
| 904 | { | ||
| 905 | int i; | ||
| 906 | |||
| 907 | if (num <= 0) | ||
| 908 | return; | ||
| 909 | mutex_lock(&kprobe_mutex); | ||
| 910 | for (i = 0; i < num; i++) | ||
| 911 | if (__unregister_kprobe_top(&rps[i]->kp) < 0) | ||
| 912 | rps[i]->kp.addr = NULL; | ||
| 913 | mutex_unlock(&kprobe_mutex); | ||
| 914 | |||
| 915 | synchronize_sched(); | ||
| 916 | for (i = 0; i < num; i++) { | ||
| 917 | if (rps[i]->kp.addr) { | ||
| 918 | __unregister_kprobe_bottom(&rps[i]->kp); | ||
| 919 | cleanup_rp_inst(rps[i]); | ||
| 920 | } | ||
| 921 | } | ||
| 922 | } | ||
| 923 | |||
| 853 | #else /* CONFIG_KRETPROBES */ | 924 | #else /* CONFIG_KRETPROBES */ |
| 854 | int __kprobes register_kretprobe(struct kretprobe *rp) | 925 | int __kprobes register_kretprobe(struct kretprobe *rp) |
| 855 | { | 926 | { |
| 856 | return -ENOSYS; | 927 | return -ENOSYS; |
| 857 | } | 928 | } |
| 858 | 929 | ||
| 859 | static int __kprobes pre_handler_kretprobe(struct kprobe *p, | 930 | int __kprobes register_kretprobes(struct kretprobe **rps, int num) |
| 860 | struct pt_regs *regs) | ||
| 861 | { | 931 | { |
| 862 | return 0; | 932 | return -ENOSYS; |
| 863 | } | 933 | } |
| 864 | #endif /* CONFIG_KRETPROBES */ | ||
| 865 | |||
| 866 | void __kprobes unregister_kretprobe(struct kretprobe *rp) | 934 | void __kprobes unregister_kretprobe(struct kretprobe *rp) |
| 867 | { | 935 | { |
| 868 | unsigned long flags; | 936 | } |
| 869 | struct kretprobe_instance *ri; | ||
| 870 | struct hlist_node *pos, *next; | ||
| 871 | 937 | ||
| 872 | unregister_kprobe(&rp->kp); | 938 | void __kprobes unregister_kretprobes(struct kretprobe **rps, int num) |
| 939 | { | ||
| 940 | } | ||
| 873 | 941 | ||
| 874 | /* No race here */ | 942 | static int __kprobes pre_handler_kretprobe(struct kprobe *p, |
| 875 | spin_lock_irqsave(&kretprobe_lock, flags); | 943 | struct pt_regs *regs) |
| 876 | hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) { | 944 | { |
| 877 | ri->rp = NULL; | 945 | return 0; |
| 878 | hlist_del(&ri->uflist); | ||
| 879 | } | ||
| 880 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
| 881 | free_rp_inst(rp); | ||
| 882 | } | 946 | } |
| 883 | 947 | ||
| 948 | #endif /* CONFIG_KRETPROBES */ | ||
| 949 | |||
| 884 | static int __init init_kprobes(void) | 950 | static int __init init_kprobes(void) |
| 885 | { | 951 | { |
| 886 | int i, err = 0; | 952 | int i, err = 0; |
| @@ -1177,4 +1243,6 @@ EXPORT_SYMBOL_GPL(jprobe_return); | |||
| 1177 | #ifdef CONFIG_KPROBES | 1243 | #ifdef CONFIG_KPROBES |
| 1178 | EXPORT_SYMBOL_GPL(register_kretprobe); | 1244 | EXPORT_SYMBOL_GPL(register_kretprobe); |
| 1179 | EXPORT_SYMBOL_GPL(unregister_kretprobe); | 1245 | EXPORT_SYMBOL_GPL(unregister_kretprobe); |
| 1246 | EXPORT_SYMBOL_GPL(register_kretprobes); | ||
| 1247 | EXPORT_SYMBOL_GPL(unregister_kretprobes); | ||
| 1180 | #endif | 1248 | #endif |
