| From: Peter Zijlstra <peterz@infradead.org> |
| Date: Fri, 17 May 2019 13:52:32 +0200 |
| Subject: perf/ring_buffer: Add ordering to rb->nest increment |
| |
| commit 3f9fbe9bd86c534eba2faf5d840fd44c6049f50e upstream. |
| |
| Similar to how decrementing rb->next too early can cause data_head to |
| (temporarily) be observed to go backward, so too can this happen when |
| we increment too late. |
| |
| This barrier() ensures the rb->head load happens after the increment, |
| both the one in the 'goto again' path, as the one from |
| perf_output_get_handle() -- albeit very unlikely to matter for the |
| latter. |
| |
| Suggested-by: Yabin Cui <yabinc@google.com> |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> |
| Cc: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Cc: Jiri Olsa <jolsa@redhat.com> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Stephane Eranian <eranian@google.com> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Cc: Vince Weaver <vincent.weaver@maine.edu> |
| Cc: acme@kernel.org |
| Cc: mark.rutland@arm.com |
| Cc: namhyung@kernel.org |
| Fixes: ef60777c9abd ("perf: Optimize the perf_output() path by removing IRQ-disables") |
| Link: http://lkml.kernel.org/r/20190517115418.309516009@infradead.org |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| kernel/events/ring_buffer.c | 9 +++++++++ |
| 1 file changed, 9 insertions(+) |
| |
| --- a/kernel/events/ring_buffer.c |
| +++ b/kernel/events/ring_buffer.c |
| @@ -47,6 +47,15 @@ static void perf_output_put_handle(struc |
| unsigned long head; |
| |
| again: |
| + /* |
| + * In order to avoid publishing a head value that goes backwards, |
| + * we must ensure the load of @rb->head happens after we've |
| + * incremented @rb->nest. |
| + * |
| + * Otherwise we can observe a @rb->head value before one published |
| + * by an IRQ/NMI happening between the load and the increment. |
| + */ |
| + barrier(); |
| head = local_read(&rb->head); |
| |
| /* |