Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea317b26 authored by Kaixu Xia's avatar Kaixu Xia Committed by David S. Miller
Browse files

bpf: Add new bpf map type to store the pointer to struct perf_event



Introduce a new bpf map type 'BPF_MAP_TYPE_PERF_EVENT_ARRAY'.
This map only stores the pointer to struct perf_event. The
user space event FDs from perf_event_open() syscall are converted
to the pointer to struct perf_event and stored in map.

Signed-off-by: default avatarKaixu Xia <xiakaixu@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2a36f0b9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <uapi/linux/bpf.h>
#include <linux/workqueue.h>
#include <linux/file.h>
#include <linux/perf_event.h>

struct bpf_map;

+1 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ enum bpf_map_type {
	BPF_MAP_TYPE_HASH,
	BPF_MAP_TYPE_ARRAY,
	BPF_MAP_TYPE_PROG_ARRAY,
	BPF_MAP_TYPE_PERF_EVENT_ARRAY,
};

enum bpf_prog_type {
+57 −0
Original line number Diff line number Diff line
@@ -273,3 +273,60 @@ static int __init register_prog_array_map(void)
	return 0;
}
late_initcall(register_prog_array_map);

static void perf_event_array_map_free(struct bpf_map *map)
{
	bpf_fd_array_map_clear(map);
	fd_array_map_free(map);
}

static void *perf_event_fd_array_get_ptr(struct bpf_map *map, int fd)
{
	struct perf_event *event;
	const struct perf_event_attr *attr;

	event = perf_event_get(fd);
	if (IS_ERR(event))
		return event;

	attr = perf_event_attrs(event);
	if (IS_ERR(attr))
		return (void *)attr;

	if (attr->type != PERF_TYPE_RAW &&
	    attr->type != PERF_TYPE_HARDWARE) {
		perf_event_release_kernel(event);
		return ERR_PTR(-EINVAL);
	}
	return event;
}

static void perf_event_fd_array_put_ptr(void *ptr)
{
	struct perf_event *event = ptr;

	perf_event_release_kernel(event);
}

static const struct bpf_map_ops perf_event_array_ops = {
	.map_alloc = fd_array_map_alloc,
	.map_free = perf_event_array_map_free,
	.map_get_next_key = array_map_get_next_key,
	.map_lookup_elem = fd_array_map_lookup_elem,
	.map_update_elem = fd_array_map_update_elem,
	.map_delete_elem = fd_array_map_delete_elem,
	.map_fd_get_ptr = perf_event_fd_array_get_ptr,
	.map_fd_put_ptr = perf_event_fd_array_put_ptr,
};

static struct bpf_map_type_list perf_event_array_type __read_mostly = {
	.ops = &perf_event_array_ops,
	.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
};

static int __init register_perf_event_array_map(void)
{
	bpf_register_map_type(&perf_event_array_type);
	return 0;
}
late_initcall(register_perf_event_array_map);