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))) |