|
@@ -5694,9 +5694,13 @@ void perf_prepare_sample(struct perf_event_header *header,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void perf_event_output(struct perf_event *event,
|
|
|
- struct perf_sample_data *data,
|
|
|
- struct pt_regs *regs)
|
|
|
+static void __always_inline
|
|
|
+__perf_event_output(struct perf_event *event,
|
|
|
+ struct perf_sample_data *data,
|
|
|
+ struct pt_regs *regs,
|
|
|
+ int (*output_begin)(struct perf_output_handle *,
|
|
|
+ struct perf_event *,
|
|
|
+ unsigned int))
|
|
|
{
|
|
|
struct perf_output_handle handle;
|
|
|
struct perf_event_header header;
|
|
@@ -5706,7 +5710,7 @@ void perf_event_output(struct perf_event *event,
|
|
|
|
|
|
perf_prepare_sample(&header, data, event, regs);
|
|
|
|
|
|
- if (perf_output_begin(&handle, event, header.size))
|
|
|
+ if (output_begin(&handle, event, header.size))
|
|
|
goto exit;
|
|
|
|
|
|
perf_output_sample(&handle, &header, data, event);
|
|
@@ -5717,6 +5721,30 @@ exit:
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
+void
|
|
|
+perf_event_output_forward(struct perf_event *event,
|
|
|
+ struct perf_sample_data *data,
|
|
|
+ struct pt_regs *regs)
|
|
|
+{
|
|
|
+ __perf_event_output(event, data, regs, perf_output_begin_forward);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+perf_event_output_backward(struct perf_event *event,
|
|
|
+ struct perf_sample_data *data,
|
|
|
+ struct pt_regs *regs)
|
|
|
+{
|
|
|
+ __perf_event_output(event, data, regs, perf_output_begin_backward);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+perf_event_output(struct perf_event *event,
|
|
|
+ struct perf_sample_data *data,
|
|
|
+ struct pt_regs *regs)
|
|
|
+{
|
|
|
+ __perf_event_output(event, data, regs, perf_output_begin);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* read event_id
|
|
|
*/
|
|
@@ -8153,8 +8181,11 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
|
|
|
if (overflow_handler) {
|
|
|
event->overflow_handler = overflow_handler;
|
|
|
event->overflow_handler_context = context;
|
|
|
+ } else if (is_write_backward(event)){
|
|
|
+ event->overflow_handler = perf_event_output_backward;
|
|
|
+ event->overflow_handler_context = NULL;
|
|
|
} else {
|
|
|
- event->overflow_handler = perf_event_output;
|
|
|
+ event->overflow_handler = perf_event_output_forward;
|
|
|
event->overflow_handler_context = NULL;
|
|
|
}
|
|
|
|
|
@@ -8388,6 +8419,13 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
|
|
|
if (output_event->clock != event->clock)
|
|
|
goto out;
|
|
|
|
|
|
+ /*
|
|
|
+ * Either writing ring buffer from beginning or from end.
|
|
|
+ * Mixing is not allowed.
|
|
|
+ */
|
|
|
+ if (is_write_backward(output_event) != is_write_backward(event))
|
|
|
+ goto out;
|
|
|
+
|
|
|
/*
|
|
|
* If both events generate aux data, they must be on the same PMU
|
|
|
*/
|