diff options
-rw-r--r-- | kernel/events/ring_buffer.c | 42 |
1 files changed, 26 insertions, 16 deletions
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index e8b168af135b..146a5792b1d2 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c | |||
@@ -61,19 +61,20 @@ again: | |||
61 | * | 61 | * |
62 | * kernel user | 62 | * kernel user |
63 | * | 63 | * |
64 | * READ ->data_tail READ ->data_head | 64 | * if (LOAD ->data_tail) { LOAD ->data_head |
65 | * smp_mb() (A) smp_rmb() (C) | 65 | * (A) smp_rmb() (C) |
66 | * WRITE $data READ $data | 66 | * STORE $data LOAD $data |
67 | * smp_wmb() (B) smp_mb() (D) | 67 | * smp_wmb() (B) smp_mb() (D) |
68 | * STORE ->data_head WRITE ->data_tail | 68 | * STORE ->data_head STORE ->data_tail |
69 | * } | ||
69 | * | 70 | * |
70 | * Where A pairs with D, and B pairs with C. | 71 | * Where A pairs with D, and B pairs with C. |
71 | * | 72 | * |
72 | * I don't think A needs to be a full barrier because we won't in fact | 73 | * In our case (A) is a control dependency that separates the load of |
73 | * write data until we see the store from userspace. So we simply don't | 74 | * the ->data_tail and the stores of $data. In case ->data_tail |
74 | * issue the data WRITE until we observe it. Be conservative for now. | 75 | * indicates there is no room in the buffer to store $data we do not. |
75 | * | 76 | * |
76 | * OTOH, D needs to be a full barrier since it separates the data READ | 77 | * D needs to be a full barrier since it separates the data READ |
77 | * from the tail WRITE. | 78 | * from the tail WRITE. |
78 | * | 79 | * |
79 | * For B a WMB is sufficient since it separates two WRITEs, and for C | 80 | * For B a WMB is sufficient since it separates two WRITEs, and for C |
@@ -81,7 +82,7 @@ again: | |||
81 | * | 82 | * |
82 | * See perf_output_begin(). | 83 | * See perf_output_begin(). |
83 | */ | 84 | */ |
84 | smp_wmb(); | 85 | smp_wmb(); /* B, matches C */ |
85 | rb->user_page->data_head = head; | 86 | rb->user_page->data_head = head; |
86 | 87 | ||
87 | /* | 88 | /* |
@@ -144,17 +145,26 @@ int perf_output_begin(struct perf_output_handle *handle, | |||
144 | if (!rb->overwrite && | 145 | if (!rb->overwrite && |
145 | unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size)) | 146 | unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size)) |
146 | goto fail; | 147 | goto fail; |
148 | |||
149 | /* | ||
150 | * The above forms a control dependency barrier separating the | ||
151 | * @tail load above from the data stores below. Since the @tail | ||
152 | * load is required to compute the branch to fail below. | ||
153 | * | ||
154 | * A, matches D; the full memory barrier userspace SHOULD issue | ||
155 | * after reading the data and before storing the new tail | ||
156 | * position. | ||
157 | * | ||
158 | * See perf_output_put_handle(). | ||
159 | */ | ||
160 | |||
147 | head += size; | 161 | head += size; |
148 | } while (local_cmpxchg(&rb->head, offset, head) != offset); | 162 | } while (local_cmpxchg(&rb->head, offset, head) != offset); |
149 | 163 | ||
150 | /* | 164 | /* |
151 | * Separate the userpage->tail read from the data stores below. | 165 | * We rely on the implied barrier() by local_cmpxchg() to ensure |
152 | * Matches the MB userspace SHOULD issue after reading the data | 166 | * none of the data stores below can be lifted up by the compiler. |
153 | * and before storing the new tail position. | ||
154 | * | ||
155 | * See perf_output_put_handle(). | ||
156 | */ | 167 | */ |
157 | smp_mb(); | ||
158 | 168 | ||
159 | if (unlikely(head - local_read(&rb->wakeup) > rb->watermark)) | 169 | if (unlikely(head - local_read(&rb->wakeup) > rb->watermark)) |
160 | local_add(rb->watermark, &rb->wakeup); | 170 | local_add(rb->watermark, &rb->wakeup); |