aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/events/ring_buffer.c37
1 files changed, 4 insertions, 33 deletions
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 9c2ddfbf4525..6929c5848d4f 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -12,40 +12,10 @@
12#include <linux/perf_event.h> 12#include <linux/perf_event.h>
13#include <linux/vmalloc.h> 13#include <linux/vmalloc.h>
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/circ_buf.h>
15 16
16#include "internal.h" 17#include "internal.h"
17 18
18static bool perf_output_space(struct ring_buffer *rb, unsigned long tail,
19 unsigned long offset, unsigned long head)
20{
21 unsigned long sz = perf_data_size(rb);
22 unsigned long mask = sz - 1;
23
24 /*
25 * check if user-writable
26 * overwrite : over-write its own tail
27 * !overwrite: buffer possibly drops events.
28 */
29 if (rb->overwrite)
30 return true;
31
32 /*
33 * verify that payload is not bigger than buffer
34 * otherwise masking logic may fail to detect
35 * the "not enough space" condition
36 */
37 if ((head - offset) > sz)
38 return false;
39
40 offset = (offset - tail) & mask;
41 head = (head - tail) & mask;
42
43 if ((int)(head - offset) < 0)
44 return false;
45
46 return true;
47}
48
49static void perf_output_wakeup(struct perf_output_handle *handle) 19static void perf_output_wakeup(struct perf_output_handle *handle)
50{ 20{
51 atomic_set(&handle->rb->poll, POLL_IN); 21 atomic_set(&handle->rb->poll, POLL_IN);
@@ -181,9 +151,10 @@ int perf_output_begin(struct perf_output_handle *handle,
181 tail = ACCESS_ONCE(rb->user_page->data_tail); 151 tail = ACCESS_ONCE(rb->user_page->data_tail);
182 smp_mb(); 152 smp_mb();
183 offset = head = local_read(&rb->head); 153 offset = head = local_read(&rb->head);
184 head += size; 154 if (!rb->overwrite &&
185 if (unlikely(!perf_output_space(rb, tail, offset, head))) 155 unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size))
186 goto fail; 156 goto fail;
157 head += size;
187 } while (local_cmpxchg(&rb->head, offset, head) != offset); 158 } while (local_cmpxchg(&rb->head, offset, head) != offset);
188 159
189 if (head - local_read(&rb->wakeup) > rb->watermark) 160 if (head - local_read(&rb->wakeup) > rb->watermark)