aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2018-10-19 09:51:03 -0400
committerAlexei Starovoitov <ast@kernel.org>2018-10-19 16:43:08 -0400
commita64af0ef1c1dbd1e8be65a6ebbf5950305b27e48 (patch)
treedce79eaf0705b6bc3eaf0c8592fb36893427246b /tools/lib/bpf
parent09d62154f61316f7e97eae3f31ef8770c7e4b386 (diff)
bpf, libbpf: use correct barriers in perf ring buffer walk
Given libbpf is a generic library and not restricted to x86-64 only, the compiler barrier in bpf_perf_event_read_simple() after fetching the head needs to be replaced with smp_rmb() at minimum. Also, writing out the tail we should use WRITE_ONCE() to avoid store tearing. Now that we have the logic in place in ring_buffer_read_head() and ring_buffer_write_tail() helper also used by perf tool which would select the correct and best variant for a given architecture (e.g. x86-64 can avoid CPU barriers entirely), make use of these in order to fix bpf_perf_event_read_simple(). Fixes: d0cabbb021be ("tools: bpf: move the event reading loop to libbpf") Fixes: 39111695b1b8 ("samples: bpf: add bpf_perf_event_output example") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Cc: Peter Zijlstra <peterz@infradead.org> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/lib/bpf')
-rw-r--r--tools/lib/bpf/libbpf.c10
1 files changed, 4 insertions, 6 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index bd71efcc53be..0c21355f04a7 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -27,6 +27,7 @@
27#include <linux/list.h> 27#include <linux/list.h>
28#include <linux/limits.h> 28#include <linux/limits.h>
29#include <linux/perf_event.h> 29#include <linux/perf_event.h>
30#include <linux/ring_buffer.h>
30#include <sys/stat.h> 31#include <sys/stat.h>
31#include <sys/types.h> 32#include <sys/types.h>
32#include <sys/vfs.h> 33#include <sys/vfs.h>
@@ -2418,13 +2419,12 @@ bpf_perf_event_read_simple(void *mem, unsigned long size,
2418 unsigned long page_size, void **buf, size_t *buf_len, 2419 unsigned long page_size, void **buf, size_t *buf_len,
2419 bpf_perf_event_print_t fn, void *priv) 2420 bpf_perf_event_print_t fn, void *priv)
2420{ 2421{
2421 volatile struct perf_event_mmap_page *header = mem; 2422 struct perf_event_mmap_page *header = mem;
2423 __u64 data_head = ring_buffer_read_head(header);
2422 __u64 data_tail = header->data_tail; 2424 __u64 data_tail = header->data_tail;
2423 __u64 data_head = header->data_head;
2424 int ret = LIBBPF_PERF_EVENT_ERROR; 2425 int ret = LIBBPF_PERF_EVENT_ERROR;
2425 void *base, *begin, *end; 2426 void *base, *begin, *end;
2426 2427
2427 asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */
2428 if (data_head == data_tail) 2428 if (data_head == data_tail)
2429 return LIBBPF_PERF_EVENT_CONT; 2429 return LIBBPF_PERF_EVENT_CONT;
2430 2430
@@ -2467,8 +2467,6 @@ bpf_perf_event_read_simple(void *mem, unsigned long size,
2467 data_tail += ehdr->size; 2467 data_tail += ehdr->size;
2468 } 2468 }
2469 2469
2470 __sync_synchronize(); /* smp_mb() */ 2470 ring_buffer_write_tail(header, data_tail);
2471 header->data_tail = data_tail;
2472
2473 return ret; 2471 return ret;
2474} 2472}