diff options
Diffstat (limited to 'kernel/trace/ring_buffer.c')
| -rw-r--r-- | kernel/trace/ring_buffer.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index afb04b9b818a..b38fb2b9e237 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
| @@ -626,8 +626,22 @@ int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu, | |||
| 626 | work = &cpu_buffer->irq_work; | 626 | work = &cpu_buffer->irq_work; |
| 627 | } | 627 | } |
| 628 | 628 | ||
| 629 | work->waiters_pending = true; | ||
| 630 | poll_wait(filp, &work->waiters, poll_table); | 629 | poll_wait(filp, &work->waiters, poll_table); |
| 630 | work->waiters_pending = true; | ||
| 631 | /* | ||
| 632 | * There's a tight race between setting the waiters_pending and | ||
| 633 | * checking if the ring buffer is empty. Once the waiters_pending bit | ||
| 634 | * is set, the next event will wake the task up, but we can get stuck | ||
| 635 | * if there's only a single event in. | ||
| 636 | * | ||
| 637 | * FIXME: Ideally, we need a memory barrier on the writer side as well, | ||
| 638 | * but adding a memory barrier to all events will cause too much of a | ||
| 639 | * performance hit in the fast path. We only need a memory barrier when | ||
| 640 | * the buffer goes from empty to having content. But as this race is | ||
| 641 | * extremely small, and it's not a problem if another event comes in, we | ||
| 642 | * will fix it later. | ||
| 643 | */ | ||
| 644 | smp_mb(); | ||
| 631 | 645 | ||
| 632 | if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) || | 646 | if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) || |
| 633 | (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu))) | 647 | (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu))) |
