diff options
Diffstat (limited to 'kernel/trace/ring_buffer.c')
| -rw-r--r-- | kernel/trace/ring_buffer.c | 33 | 
1 files changed, 33 insertions, 0 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 3046deacf7b3..c3f354cfc5ba 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2648,6 +2648,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,  		/* Mark the rest of the page with padding */  		rb_event_set_padding(event); +		/* Make sure the padding is visible before the write update */ +		smp_wmb(); +  		/* Set the write back to the previous setting */  		local_sub(length, &tail_page->write);  		return; @@ -2659,6 +2662,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,  	/* time delta must be non zero */  	event->time_delta = 1; +	/* Make sure the padding is visible before the tail_page->write update */ +	smp_wmb(); +  	/* Set write to end of buffer */  	length = (tail + length) - BUF_PAGE_SIZE;  	local_sub(length, &tail_page->write); @@ -4627,6 +4633,33 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)  	arch_spin_unlock(&cpu_buffer->lock);  	local_irq_restore(flags); +	/* +	 * The writer has preempt disable, wait for it. But not forever +	 * Although, 1 second is pretty much "forever" +	 */ +#define USECS_WAIT	1000000 +        for (nr_loops = 0; nr_loops < USECS_WAIT; nr_loops++) { +		/* If the write is past the end of page, a writer is still updating it */ +		if (likely(!reader || rb_page_write(reader) <= BUF_PAGE_SIZE)) +			break; + +		udelay(1); + +		/* Get the latest version of the reader write value */ +		smp_rmb(); +	} + +	/* The writer is not moving forward? Something is wrong */ +	if (RB_WARN_ON(cpu_buffer, nr_loops == USECS_WAIT)) +		reader = NULL; + +	/* +	 * Make sure we see any padding after the write update +	 * (see rb_reset_tail()) +	 */ +	smp_rmb(); + +  	return reader;  }  | 
