diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2012-08-07 09:20:38 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-08-10 10:44:06 -0400 |
commit | 91d7753a45f8525dc75b6be01e427dc1c378dc16 (patch) | |
tree | 906a2c335d4403a39bd0f09ed3e338865d3df49b /kernel | |
parent | 4018994f3d8785275ef0e7391b75c3462c029e56 (diff) |
perf: Factor __output_copy to be usable with specific copy function
Adding a generic way to use __output_copy function with specific copy
function via DEFINE_PERF_OUTPUT_COPY macro.
Using this to add new __output_copy_user function, that provides output
copy from user pointers. For x86 the copy_from_user_nmi function is used
and __copy_from_user_inatomic for the rest of the architectures.
This new function will be used in user stack dump on sample, coming in
next patches.
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: "Frank Ch. Eigler" <fche@redhat.com>
Cc: Arun Sharma <asharma@fb.com>
Cc: Benjamin Redelings <benjamin.redelings@nescent.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Robert Richter <robert.richter@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Ulrich Drepper <drepper@gmail.com>
Link: http://lkml.kernel.org/r/1344345647-11536-4-git-send-email-jolsa@redhat.com
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/internal.h | 62 | ||||
-rw-r--r-- | kernel/events/ring_buffer.c | 4 |
2 files changed, 43 insertions, 23 deletions
diff --git a/kernel/events/internal.h b/kernel/events/internal.h index a096c19f2c2a..7fd5408493d2 100644 --- a/kernel/events/internal.h +++ b/kernel/events/internal.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _KERNEL_EVENTS_INTERNAL_H | 2 | #define _KERNEL_EVENTS_INTERNAL_H |
3 | 3 | ||
4 | #include <linux/hardirq.h> | 4 | #include <linux/hardirq.h> |
5 | #include <linux/uaccess.h> | ||
5 | 6 | ||
6 | /* Buffer handling */ | 7 | /* Buffer handling */ |
7 | 8 | ||
@@ -76,30 +77,49 @@ static inline unsigned long perf_data_size(struct ring_buffer *rb) | |||
76 | return rb->nr_pages << (PAGE_SHIFT + page_order(rb)); | 77 | return rb->nr_pages << (PAGE_SHIFT + page_order(rb)); |
77 | } | 78 | } |
78 | 79 | ||
79 | static inline void | 80 | #define DEFINE_OUTPUT_COPY(func_name, memcpy_func) \ |
80 | __output_copy(struct perf_output_handle *handle, | 81 | static inline unsigned int \ |
81 | const void *buf, unsigned int len) | 82 | func_name(struct perf_output_handle *handle, \ |
83 | const void *buf, unsigned int len) \ | ||
84 | { \ | ||
85 | unsigned long size, written; \ | ||
86 | \ | ||
87 | do { \ | ||
88 | size = min_t(unsigned long, handle->size, len); \ | ||
89 | \ | ||
90 | written = memcpy_func(handle->addr, buf, size); \ | ||
91 | \ | ||
92 | len -= written; \ | ||
93 | handle->addr += written; \ | ||
94 | buf += written; \ | ||
95 | handle->size -= written; \ | ||
96 | if (!handle->size) { \ | ||
97 | struct ring_buffer *rb = handle->rb; \ | ||
98 | \ | ||
99 | handle->page++; \ | ||
100 | handle->page &= rb->nr_pages - 1; \ | ||
101 | handle->addr = rb->data_pages[handle->page]; \ | ||
102 | handle->size = PAGE_SIZE << page_order(rb); \ | ||
103 | } \ | ||
104 | } while (len && written == size); \ | ||
105 | \ | ||
106 | return len; \ | ||
107 | } | ||
108 | |||
109 | static inline int memcpy_common(void *dst, const void *src, size_t n) | ||
82 | { | 110 | { |
83 | do { | 111 | memcpy(dst, src, n); |
84 | unsigned long size = min_t(unsigned long, handle->size, len); | 112 | return n; |
85 | |||
86 | memcpy(handle->addr, buf, size); | ||
87 | |||
88 | len -= size; | ||
89 | handle->addr += size; | ||
90 | buf += size; | ||
91 | handle->size -= size; | ||
92 | if (!handle->size) { | ||
93 | struct ring_buffer *rb = handle->rb; | ||
94 | |||
95 | handle->page++; | ||
96 | handle->page &= rb->nr_pages - 1; | ||
97 | handle->addr = rb->data_pages[handle->page]; | ||
98 | handle->size = PAGE_SIZE << page_order(rb); | ||
99 | } | ||
100 | } while (len); | ||
101 | } | 113 | } |
102 | 114 | ||
115 | DEFINE_OUTPUT_COPY(__output_copy, memcpy_common) | ||
116 | |||
117 | #ifndef arch_perf_out_copy_user | ||
118 | #define arch_perf_out_copy_user __copy_from_user_inatomic | ||
119 | #endif | ||
120 | |||
121 | DEFINE_OUTPUT_COPY(__output_copy_user, arch_perf_out_copy_user) | ||
122 | |||
103 | /* Callchain handling */ | 123 | /* Callchain handling */ |
104 | extern struct perf_callchain_entry * | 124 | extern struct perf_callchain_entry * |
105 | perf_callchain(struct perf_event *event, struct pt_regs *regs); | 125 | perf_callchain(struct perf_event *event, struct pt_regs *regs); |
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index 6ddaba43fb7a..b4c2ad3dee7a 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c | |||
@@ -182,10 +182,10 @@ out: | |||
182 | return -ENOSPC; | 182 | return -ENOSPC; |
183 | } | 183 | } |
184 | 184 | ||
185 | void perf_output_copy(struct perf_output_handle *handle, | 185 | unsigned int perf_output_copy(struct perf_output_handle *handle, |
186 | const void *buf, unsigned int len) | 186 | const void *buf, unsigned int len) |
187 | { | 187 | { |
188 | __output_copy(handle, buf, len); | 188 | return __output_copy(handle, buf, len); |
189 | } | 189 | } |
190 | 190 | ||
191 | void perf_output_end(struct perf_output_handle *handle) | 191 | void perf_output_end(struct perf_output_handle *handle) |