Commit 4a296e07c3a410c09b9155da4c2fa84a07964f38
Committed by
Linus Torvalds
1 parent
9861668f74
Exists in
master
and in
4 other branches
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>
Showing 2 changed files with 97 additions and 20 deletions Side-by-side Diff
include/linux/kprobes.h
... | ... | @@ -245,6 +245,8 @@ |
245 | 245 | |
246 | 246 | int register_kretprobe(struct kretprobe *rp); |
247 | 247 | void unregister_kretprobe(struct kretprobe *rp); |
248 | +int register_kretprobes(struct kretprobe **rps, int num); | |
249 | +void unregister_kretprobes(struct kretprobe **rps, int num); | |
248 | 250 | |
249 | 251 | void kprobe_flush_task(struct task_struct *tk); |
250 | 252 | void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); |
251 | 253 | |
... | ... | @@ -287,7 +289,14 @@ |
287 | 289 | { |
288 | 290 | return -ENOSYS; |
289 | 291 | } |
292 | +static inline int register_kretprobes(struct kretprobe **rps, int num) | |
293 | +{ | |
294 | + return -ENOSYS; | |
295 | +} | |
290 | 296 | static inline void unregister_kretprobe(struct kretprobe *rp) |
297 | +{ | |
298 | +} | |
299 | +static inline void unregister_kretprobes(struct kretprobe **rps, int num) | |
291 | 300 | { |
292 | 301 | } |
293 | 302 | static inline void kprobe_flush_task(struct task_struct *tk) |
kernel/kprobes.c
... | ... | @@ -429,6 +429,21 @@ |
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 | 448 | * Keep all fields in the kprobe consistent |
434 | 449 | */ |
... | ... | @@ -798,7 +813,8 @@ |
798 | 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 | 819 | int ret = 0; |
804 | 820 | struct kretprobe_instance *inst; |
805 | 821 | |
806 | 822 | |
807 | 823 | |
808 | 824 | |
809 | 825 | |
810 | 826 | |
811 | 827 | |
812 | 828 | |
... | ... | @@ -844,43 +860,93 @@ |
844 | 860 | |
845 | 861 | rp->nmissed = 0; |
846 | 862 | /* Establish function entry probe point */ |
847 | - if ((ret = __register_kprobe(&rp->kp, | |
848 | - (unsigned long)__builtin_return_address(0))) != 0) | |
863 | + ret = __register_kprobe(&rp->kp, called_from); | |
864 | + if (ret != 0) | |
849 | 865 | free_rp_inst(rp); |
850 | 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 | 924 | #else /* CONFIG_KRETPROBES */ |
854 | 925 | int __kprobes register_kretprobe(struct kretprobe *rp) |
855 | 926 | { |
856 | 927 | return -ENOSYS; |
857 | 928 | } |
858 | 929 | |
859 | -static int __kprobes pre_handler_kretprobe(struct kprobe *p, | |
860 | - struct pt_regs *regs) | |
930 | +int __kprobes register_kretprobes(struct kretprobe **rps, int num) | |
861 | 931 | { |
862 | - return 0; | |
932 | + return -ENOSYS; | |
863 | 933 | } |
864 | -#endif /* CONFIG_KRETPROBES */ | |
865 | - | |
866 | 934 | void __kprobes unregister_kretprobe(struct kretprobe *rp) |
867 | 935 | { |
868 | - unsigned long flags; | |
869 | - struct kretprobe_instance *ri; | |
870 | - struct hlist_node *pos, *next; | |
936 | +} | |
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 */ | |
875 | - spin_lock_irqsave(&kretprobe_lock, flags); | |
876 | - hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) { | |
877 | - ri->rp = NULL; | |
878 | - hlist_del(&ri->uflist); | |
879 | - } | |
880 | - spin_unlock_irqrestore(&kretprobe_lock, flags); | |
881 | - free_rp_inst(rp); | |
942 | +static int __kprobes pre_handler_kretprobe(struct kprobe *p, | |
943 | + struct pt_regs *regs) | |
944 | +{ | |
945 | + return 0; | |
882 | 946 | } |
883 | 947 | |
948 | +#endif /* CONFIG_KRETPROBES */ | |
949 | + | |
884 | 950 | static int __init init_kprobes(void) |
885 | 951 | { |
886 | 952 | int i, err = 0; |
... | ... | @@ -1177,5 +1243,7 @@ |
1177 | 1243 | #ifdef CONFIG_KPROBES |
1178 | 1244 | EXPORT_SYMBOL_GPL(register_kretprobe); |
1179 | 1245 | EXPORT_SYMBOL_GPL(unregister_kretprobe); |
1246 | +EXPORT_SYMBOL_GPL(register_kretprobes); | |
1247 | +EXPORT_SYMBOL_GPL(unregister_kretprobes); | |
1180 | 1248 | #endif |