diff options
author | zhangwei(Jovi) <jovi.zhangwei@huawei.com> | 2014-01-17 03:08:38 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2014-02-20 12:30:09 -0500 |
commit | 70ed91c6ec7f8bf20369634017d887d48ac979d2 (patch) | |
tree | c8b69373ee58aa2294016ddfb773a3490f5dca6d /kernel/trace/trace_uprobe.c | |
parent | dd9fa555d7bbfcc7dbc63eb744806e9f6cb62e9f (diff) |
tracing/uprobes: Support ftrace_event_file base multibuffer
Support multi-buffer on uprobe-based dynamic events by
using ftrace_event_file.
This patch is based kprobe-based dynamic events multibuffer
support work initially, commited by Masami(commit 41a7dd420c),
but revised as below:
Oleg changed the kprobe-based multibuffer design from
array-pointers of ftrace_event_file into simple list,
so this patch also change to the list design.
rcu_read_lock/unlock added into uprobe_trace_func/uretprobe_trace_func,
to synchronize with ftrace_event_file list add and delete.
Even though we allow multi-uprobes instances now,
but TP_FLAG_PROFILE/TP_FLAG_TRACE are still mutually exclusive
in probe_event_enable currently, this means we cannot allow
one user is using uprobe-tracer, and another user is using
perf-probe on same uprobe concurrently.
(Perhaps this will be fix in future, kprobe don't have this
limitation now)
Link: http://lkml.kernel.org/r/1389946120-19610-4-git-send-email-namhyung@kernel.org
Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Signed-off-by: zhangwei(Jovi) <jovi.zhangwei@huawei.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace_uprobe.c')
-rw-r--r-- | kernel/trace/trace_uprobe.c | 105 |
1 files changed, 84 insertions, 21 deletions
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index d83155e0da78..349c6df9e332 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
@@ -260,6 +260,7 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret) | |||
260 | goto error; | 260 | goto error; |
261 | 261 | ||
262 | INIT_LIST_HEAD(&tu->list); | 262 | INIT_LIST_HEAD(&tu->list); |
263 | INIT_LIST_HEAD(&tu->tp.files); | ||
263 | tu->consumer.handler = uprobe_dispatcher; | 264 | tu->consumer.handler = uprobe_dispatcher; |
264 | if (is_ret) | 265 | if (is_ret) |
265 | tu->consumer.ret_handler = uretprobe_dispatcher; | 266 | tu->consumer.ret_handler = uretprobe_dispatcher; |
@@ -760,7 +761,8 @@ static void uprobe_buffer_put(struct uprobe_cpu_buffer *ucb) | |||
760 | 761 | ||
761 | static void __uprobe_trace_func(struct trace_uprobe *tu, | 762 | static void __uprobe_trace_func(struct trace_uprobe *tu, |
762 | unsigned long func, struct pt_regs *regs, | 763 | unsigned long func, struct pt_regs *regs, |
763 | struct uprobe_cpu_buffer *ucb, int dsize) | 764 | struct uprobe_cpu_buffer *ucb, int dsize, |
765 | struct ftrace_event_file *ftrace_file) | ||
764 | { | 766 | { |
765 | struct uprobe_trace_entry_head *entry; | 767 | struct uprobe_trace_entry_head *entry; |
766 | struct ring_buffer_event *event; | 768 | struct ring_buffer_event *event; |
@@ -769,13 +771,15 @@ static void __uprobe_trace_func(struct trace_uprobe *tu, | |||
769 | int size, esize; | 771 | int size, esize; |
770 | struct ftrace_event_call *call = &tu->tp.call; | 772 | struct ftrace_event_call *call = &tu->tp.call; |
771 | 773 | ||
774 | WARN_ON(call != ftrace_file->event_call); | ||
775 | |||
772 | if (WARN_ON_ONCE(tu->tp.size + dsize > PAGE_SIZE)) | 776 | if (WARN_ON_ONCE(tu->tp.size + dsize > PAGE_SIZE)) |
773 | return; | 777 | return; |
774 | 778 | ||
775 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | 779 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); |
776 | size = esize + tu->tp.size + dsize; | 780 | size = esize + tu->tp.size + dsize; |
777 | event = trace_current_buffer_lock_reserve(&buffer, call->event.type, | 781 | event = trace_event_buffer_lock_reserve(&buffer, ftrace_file, |
778 | size, 0, 0); | 782 | call->event.type, size, 0, 0); |
779 | if (!event) | 783 | if (!event) |
780 | return; | 784 | return; |
781 | 785 | ||
@@ -799,8 +803,16 @@ static void __uprobe_trace_func(struct trace_uprobe *tu, | |||
799 | static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs, | 803 | static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs, |
800 | struct uprobe_cpu_buffer *ucb, int dsize) | 804 | struct uprobe_cpu_buffer *ucb, int dsize) |
801 | { | 805 | { |
802 | if (!is_ret_probe(tu)) | 806 | struct event_file_link *link; |
803 | __uprobe_trace_func(tu, 0, regs, ucb, dsize); | 807 | |
808 | if (is_ret_probe(tu)) | ||
809 | return 0; | ||
810 | |||
811 | rcu_read_lock(); | ||
812 | list_for_each_entry_rcu(link, &tu->tp.files, list) | ||
813 | __uprobe_trace_func(tu, 0, regs, ucb, dsize, link->file); | ||
814 | rcu_read_unlock(); | ||
815 | |||
804 | return 0; | 816 | return 0; |
805 | } | 817 | } |
806 | 818 | ||
@@ -808,7 +820,12 @@ static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func, | |||
808 | struct pt_regs *regs, | 820 | struct pt_regs *regs, |
809 | struct uprobe_cpu_buffer *ucb, int dsize) | 821 | struct uprobe_cpu_buffer *ucb, int dsize) |
810 | { | 822 | { |
811 | __uprobe_trace_func(tu, func, regs, ucb, dsize); | 823 | struct event_file_link *link; |
824 | |||
825 | rcu_read_lock(); | ||
826 | list_for_each_entry_rcu(link, &tu->tp.files, list) | ||
827 | __uprobe_trace_func(tu, func, regs, ucb, dsize, link->file); | ||
828 | rcu_read_unlock(); | ||
812 | } | 829 | } |
813 | 830 | ||
814 | /* Event entry printers */ | 831 | /* Event entry printers */ |
@@ -855,12 +872,31 @@ typedef bool (*filter_func_t)(struct uprobe_consumer *self, | |||
855 | struct mm_struct *mm); | 872 | struct mm_struct *mm); |
856 | 873 | ||
857 | static int | 874 | static int |
858 | probe_event_enable(struct trace_uprobe *tu, int flag, filter_func_t filter) | 875 | probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file, |
876 | filter_func_t filter) | ||
859 | { | 877 | { |
860 | int ret = 0; | 878 | bool enabled = trace_probe_is_enabled(&tu->tp); |
879 | struct event_file_link *link = NULL; | ||
880 | int ret; | ||
881 | |||
882 | if (file) { | ||
883 | if (tu->tp.flags & TP_FLAG_PROFILE) | ||
884 | return -EINTR; | ||
861 | 885 | ||
862 | if (trace_probe_is_enabled(&tu->tp)) | 886 | link = kmalloc(sizeof(*link), GFP_KERNEL); |
863 | return -EINTR; | 887 | if (!link) |
888 | return -ENOMEM; | ||
889 | |||
890 | link->file = file; | ||
891 | list_add_tail_rcu(&link->list, &tu->tp.files); | ||
892 | |||
893 | tu->tp.flags |= TP_FLAG_TRACE; | ||
894 | } else { | ||
895 | if (tu->tp.flags & TP_FLAG_TRACE) | ||
896 | return -EINTR; | ||
897 | |||
898 | tu->tp.flags |= TP_FLAG_PROFILE; | ||
899 | } | ||
864 | 900 | ||
865 | ret = uprobe_buffer_enable(); | 901 | ret = uprobe_buffer_enable(); |
866 | if (ret < 0) | 902 | if (ret < 0) |
@@ -868,24 +904,49 @@ probe_event_enable(struct trace_uprobe *tu, int flag, filter_func_t filter) | |||
868 | 904 | ||
869 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); | 905 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); |
870 | 906 | ||
871 | tu->tp.flags |= flag; | 907 | if (enabled) |
908 | return 0; | ||
909 | |||
872 | tu->consumer.filter = filter; | 910 | tu->consumer.filter = filter; |
873 | ret = uprobe_register(tu->inode, tu->offset, &tu->consumer); | 911 | ret = uprobe_register(tu->inode, tu->offset, &tu->consumer); |
874 | if (ret) | 912 | if (ret) { |
875 | tu->tp.flags &= ~flag; | 913 | if (file) { |
914 | list_del(&link->list); | ||
915 | kfree(link); | ||
916 | tu->tp.flags &= ~TP_FLAG_TRACE; | ||
917 | } else | ||
918 | tu->tp.flags &= ~TP_FLAG_PROFILE; | ||
919 | } | ||
876 | 920 | ||
877 | return ret; | 921 | return ret; |
878 | } | 922 | } |
879 | 923 | ||
880 | static void probe_event_disable(struct trace_uprobe *tu, int flag) | 924 | static void |
925 | probe_event_disable(struct trace_uprobe *tu, struct ftrace_event_file *file) | ||
881 | { | 926 | { |
882 | if (!trace_probe_is_enabled(&tu->tp)) | 927 | if (!trace_probe_is_enabled(&tu->tp)) |
883 | return; | 928 | return; |
884 | 929 | ||
930 | if (file) { | ||
931 | struct event_file_link *link; | ||
932 | |||
933 | link = find_event_file_link(&tu->tp, file); | ||
934 | if (!link) | ||
935 | return; | ||
936 | |||
937 | list_del_rcu(&link->list); | ||
938 | /* synchronize with u{,ret}probe_trace_func */ | ||
939 | synchronize_sched(); | ||
940 | kfree(link); | ||
941 | |||
942 | if (!list_empty(&tu->tp.files)) | ||
943 | return; | ||
944 | } | ||
945 | |||
885 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); | 946 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); |
886 | 947 | ||
887 | uprobe_unregister(tu->inode, tu->offset, &tu->consumer); | 948 | uprobe_unregister(tu->inode, tu->offset, &tu->consumer); |
888 | tu->tp.flags &= ~flag; | 949 | tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE; |
889 | 950 | ||
890 | uprobe_buffer_disable(); | 951 | uprobe_buffer_disable(); |
891 | } | 952 | } |
@@ -1077,25 +1138,27 @@ static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func, | |||
1077 | } | 1138 | } |
1078 | #endif /* CONFIG_PERF_EVENTS */ | 1139 | #endif /* CONFIG_PERF_EVENTS */ |
1079 | 1140 | ||
1080 | static | 1141 | static int |
1081 | int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, void *data) | 1142 | trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, |
1143 | void *data) | ||
1082 | { | 1144 | { |
1083 | struct trace_uprobe *tu = event->data; | 1145 | struct trace_uprobe *tu = event->data; |
1146 | struct ftrace_event_file *file = data; | ||
1084 | 1147 | ||
1085 | switch (type) { | 1148 | switch (type) { |
1086 | case TRACE_REG_REGISTER: | 1149 | case TRACE_REG_REGISTER: |
1087 | return probe_event_enable(tu, TP_FLAG_TRACE, NULL); | 1150 | return probe_event_enable(tu, file, NULL); |
1088 | 1151 | ||
1089 | case TRACE_REG_UNREGISTER: | 1152 | case TRACE_REG_UNREGISTER: |
1090 | probe_event_disable(tu, TP_FLAG_TRACE); | 1153 | probe_event_disable(tu, file); |
1091 | return 0; | 1154 | return 0; |
1092 | 1155 | ||
1093 | #ifdef CONFIG_PERF_EVENTS | 1156 | #ifdef CONFIG_PERF_EVENTS |
1094 | case TRACE_REG_PERF_REGISTER: | 1157 | case TRACE_REG_PERF_REGISTER: |
1095 | return probe_event_enable(tu, TP_FLAG_PROFILE, uprobe_perf_filter); | 1158 | return probe_event_enable(tu, NULL, uprobe_perf_filter); |
1096 | 1159 | ||
1097 | case TRACE_REG_PERF_UNREGISTER: | 1160 | case TRACE_REG_PERF_UNREGISTER: |
1098 | probe_event_disable(tu, TP_FLAG_PROFILE); | 1161 | probe_event_disable(tu, NULL); |
1099 | return 0; | 1162 | return 0; |
1100 | 1163 | ||
1101 | case TRACE_REG_PERF_OPEN: | 1164 | case TRACE_REG_PERF_OPEN: |