Commit 3dca2115 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Alexei Starovoitov

bpf, libbpf: simplify and cleanup perf ring buffer walk

Simplify bpf_perf_event_read_simple() a bit and fix up some minor
things along the way: the return code in the header is not of type
int but enum bpf_perf_event_ret instead. Once callback indicated
to break the loop walking event data, it also needs to be consumed
in data_tail since it has been processed already.

Moreover, bpf_perf_event_print_t callback should avoid void * as
we actually get a pointer to struct perf_event_header and thus
applications can make use of container_of() to have type checks.
The walk also doesn't have to use modulo op since the ring size is
required to be power of two.
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 84430d42
...@@ -50,15 +50,17 @@ static void int_exit(int signo) ...@@ -50,15 +50,17 @@ static void int_exit(int signo)
stop = true; stop = true;
} }
static enum bpf_perf_event_ret print_bpf_output(void *event, void *priv) static enum bpf_perf_event_ret
print_bpf_output(struct perf_event_header *event, void *private_data)
{ {
struct event_ring_info *ring = priv; struct perf_event_sample *e = container_of(event, struct perf_event_sample,
struct perf_event_sample *e = event; header);
struct event_ring_info *ring = private_data;
struct { struct {
struct perf_event_header header; struct perf_event_header header;
__u64 id; __u64 id;
__u64 lost; __u64 lost;
} *lost = event; } *lost = (typeof(lost))event;
if (json_output) { if (json_output) {
jsonw_start_object(json_wtr); jsonw_start_object(json_wtr);
......
...@@ -2415,56 +2415,47 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, ...@@ -2415,56 +2415,47 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
} }
enum bpf_perf_event_ret enum bpf_perf_event_ret
bpf_perf_event_read_simple(void *mem, unsigned long size, bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
unsigned long page_size, void **buf, size_t *buf_len, void **copy_mem, size_t *copy_size,
bpf_perf_event_print_t fn, void *priv) bpf_perf_event_print_t fn, void *private_data)
{ {
struct perf_event_mmap_page *header = mem; struct perf_event_mmap_page *header = mmap_mem;
__u64 data_head = ring_buffer_read_head(header); __u64 data_head = ring_buffer_read_head(header);
__u64 data_tail = header->data_tail; __u64 data_tail = header->data_tail;
int ret = LIBBPF_PERF_EVENT_ERROR; void *base = ((__u8 *)header) + page_size;
void *base, *begin, *end; int ret = LIBBPF_PERF_EVENT_CONT;
struct perf_event_header *ehdr;
if (data_head == data_tail) size_t ehdr_size;
return LIBBPF_PERF_EVENT_CONT;
while (data_head != data_tail) {
base = ((char *)header) + page_size; ehdr = base + (data_tail & (mmap_size - 1));
ehdr_size = ehdr->size;
begin = base + data_tail % size;
end = base + data_head % size; if (((void *)ehdr) + ehdr_size > base + mmap_size) {
void *copy_start = ehdr;
while (begin != end) { size_t len_first = base + mmap_size - copy_start;
struct perf_event_header *ehdr; size_t len_secnd = ehdr_size - len_first;
ehdr = begin; if (*copy_size < ehdr_size) {
if (begin + ehdr->size > base + size) { free(*copy_mem);
long len = base + size - begin; *copy_mem = malloc(ehdr_size);
if (!*copy_mem) {
if (*buf_len < ehdr->size) { *copy_size = 0;
free(*buf);
*buf = malloc(ehdr->size);
if (!*buf) {
ret = LIBBPF_PERF_EVENT_ERROR; ret = LIBBPF_PERF_EVENT_ERROR;
break; break;
} }
*buf_len = ehdr->size; *copy_size = ehdr_size;
} }
memcpy(*buf, begin, len); memcpy(*copy_mem, copy_start, len_first);
memcpy(*buf + len, base, ehdr->size - len); memcpy(*copy_mem + len_first, base, len_secnd);
ehdr = (void *)*buf; ehdr = *copy_mem;
begin = base + ehdr->size - len;
} else if (begin + ehdr->size == base + size) {
begin = base;
} else {
begin += ehdr->size;
} }
ret = fn(ehdr, priv); ret = fn(ehdr, private_data);
data_tail += ehdr_size;
if (ret != LIBBPF_PERF_EVENT_CONT) if (ret != LIBBPF_PERF_EVENT_CONT)
break; break;
data_tail += ehdr->size;
} }
ring_buffer_write_tail(header, data_tail); ring_buffer_write_tail(header, data_tail);
......
...@@ -297,13 +297,14 @@ enum bpf_perf_event_ret { ...@@ -297,13 +297,14 @@ enum bpf_perf_event_ret {
LIBBPF_PERF_EVENT_CONT = -2, LIBBPF_PERF_EVENT_CONT = -2,
}; };
typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(void *event, struct perf_event_header;
void *priv); typedef enum bpf_perf_event_ret
LIBBPF_API int bpf_perf_event_read_simple(void *mem, unsigned long size, (*bpf_perf_event_print_t)(struct perf_event_header *hdr,
unsigned long page_size, void *private_data);
void **buf, size_t *buf_len, LIBBPF_API enum bpf_perf_event_ret
bpf_perf_event_print_t fn, bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
void *priv); void **copy_mem, size_t *copy_size,
bpf_perf_event_print_t fn, void *private_data);
struct nlattr; struct nlattr;
typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
......
...@@ -125,10 +125,11 @@ struct perf_event_sample { ...@@ -125,10 +125,11 @@ struct perf_event_sample {
char data[]; char data[];
}; };
static enum bpf_perf_event_ret bpf_perf_event_print(void *event, void *priv) static enum bpf_perf_event_ret
bpf_perf_event_print(struct perf_event_header *hdr, void *private_data)
{ {
struct perf_event_sample *e = event; struct perf_event_sample *e = (struct perf_event_sample *)hdr;
perf_event_print_fn fn = priv; perf_event_print_fn fn = private_data;
int ret; int ret;
if (e->header.type == PERF_RECORD_SAMPLE) { if (e->header.type == PERF_RECORD_SAMPLE) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment