Commit 4a296e07c3a410c09b9155da4c2fa84a07964f38

Authored by Masami Hiramatsu
Committed by Linus Torvalds
1 parent 9861668f74

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)
... ... @@ -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