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,  		work = &cpu_buffer->irq_work;  	} -	work->waiters_pending = true;  	poll_wait(filp, &work->waiters, poll_table); +	work->waiters_pending = true; +	/* +	 * There's a tight race between setting the waiters_pending and +	 * checking if the ring buffer is empty.  Once the waiters_pending bit +	 * is set, the next event will wake the task up, but we can get stuck +	 * if there's only a single event in. +	 * +	 * FIXME: Ideally, we need a memory barrier on the writer side as well, +	 * but adding a memory barrier to all events will cause too much of a +	 * performance hit in the fast path.  We only need a memory barrier when +	 * the buffer goes from empty to having content.  But as this race is +	 * extremely small, and it's not a problem if another event comes in, we +	 * will fix it later. +	 */ +	smp_mb();  	if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) ||  	    (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu)))  | 
