diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2018-10-19 09:51:03 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-10-19 16:43:08 -0400 |
commit | a64af0ef1c1dbd1e8be65a6ebbf5950305b27e48 (patch) | |
tree | dce79eaf0705b6bc3eaf0c8592fb36893427246b /tools/lib/bpf | |
parent | 09d62154f61316f7e97eae3f31ef8770c7e4b386 (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.c | 10 |
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 | } |