Skip to content

Commit f371b30

Browse files
yonghong-songAlexei Starovoitov
authored andcommitted
bpf/tracing: allow user space to query prog array on the same tp
Commit e87c6bc ("bpf: permit multiple bpf attachments for a single perf event") added support to attach multiple bpf programs to a single perf event. Although this provides flexibility, users may want to know what other bpf programs attached to the same tp interface. Besides getting visibility for the underlying bpf system, such information may also help consolidate multiple bpf programs, understand potential performance issues due to a large array, and debug (e.g., one bpf program which overwrites return code may impact subsequent program results). Commit 2541517 ("tracing, perf: Implement BPF programs attached to kprobes") utilized the existing perf ioctl interface and added the command PERF_EVENT_IOC_SET_BPF to attach a bpf program to a tracepoint. This patch adds a new ioctl command, given a perf event fd, to query the bpf program array attached to the same perf tracepoint event. The new uapi ioctl command: PERF_EVENT_IOC_QUERY_BPF The new uapi/linux/perf_event.h structure: struct perf_event_query_bpf { __u32 ids_len; __u32 prog_cnt; __u32 ids[0]; }; User space provides buffer "ids" for kernel to copy to. When returning from the kernel, the number of available programs in the array is set in "prog_cnt". The usage: struct perf_event_query_bpf *query = malloc(sizeof(*query) + sizeof(u32) * ids_len); query.ids_len = ids_len; err = ioctl(pmu_efd, PERF_EVENT_IOC_QUERY_BPF, query); if (err == 0) { /* query.prog_cnt is the number of available progs, * number of progs in ids: (ids_len == 0) ? 0 : query.prog_cnt */ } else if (errno == ENOSPC) { /* query.ids_len number of progs copied, * query.prog_cnt is the number of available progs */ } else { /* other errors */ } Signed-off-by: Yonghong Song <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 63060c3 commit f371b30

File tree

5 files changed

+73
-0
lines changed

5 files changed

+73
-0
lines changed

include/linux/bpf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ typedef unsigned long (*bpf_ctx_copy_t)(void *dst, const void *src,
254254

255255
u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
256256
void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy);
257+
int bpf_event_query_prog_array(struct perf_event *event, void __user *info);
257258

258259
int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
259260
union bpf_attr __user *uattr);
@@ -285,6 +286,9 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
285286

286287
void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs,
287288
struct bpf_prog *old_prog);
289+
int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array,
290+
__u32 __user *prog_ids, u32 request_cnt,
291+
__u32 __user *prog_cnt);
288292
int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,
289293
struct bpf_prog *exclude_prog,
290294
struct bpf_prog *include_prog,

include/uapi/linux/perf_event.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,27 @@ struct perf_event_attr {
418418
__u16 __reserved_2; /* align to __u64 */
419419
};
420420

421+
/*
422+
* Structure used by below PERF_EVENT_IOC_QUERY_BPF command
423+
* to query bpf programs attached to the same perf tracepoint
424+
* as the given perf event.
425+
*/
426+
struct perf_event_query_bpf {
427+
/*
428+
* The below ids array length
429+
*/
430+
__u32 ids_len;
431+
/*
432+
* Set by the kernel to indicate the number of
433+
* available programs
434+
*/
435+
__u32 prog_cnt;
436+
/*
437+
* User provided buffer to store program ids
438+
*/
439+
__u32 ids[0];
440+
};
441+
421442
#define perf_flags(attr) (*(&(attr)->read_format + 1))
422443

423444
/*
@@ -433,6 +454,7 @@ struct perf_event_attr {
433454
#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
434455
#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32)
435456
#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32)
457+
#define PERF_EVENT_IOC_QUERY_BPF _IOWR('$', 10, struct perf_event_query_bpf *)
436458

437459
enum perf_event_ioc_flags {
438460
PERF_IOC_FLAG_GROUP = 1U << 0,

kernel/bpf/core.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,8 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
14621462
rcu_read_lock();
14631463
prog = rcu_dereference(progs)->progs;
14641464
for (; *prog; prog++) {
1465+
if (*prog == &dummy_bpf_prog.prog)
1466+
continue;
14651467
id = (*prog)->aux->id;
14661468
if (copy_to_user(prog_ids + i, &id, sizeof(id))) {
14671469
rcu_read_unlock();
@@ -1545,6 +1547,25 @@ int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,
15451547
return 0;
15461548
}
15471549

1550+
int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array,
1551+
__u32 __user *prog_ids, u32 request_cnt,
1552+
__u32 __user *prog_cnt)
1553+
{
1554+
u32 cnt = 0;
1555+
1556+
if (array)
1557+
cnt = bpf_prog_array_length(array);
1558+
1559+
if (copy_to_user(prog_cnt, &cnt, sizeof(cnt)))
1560+
return -EFAULT;
1561+
1562+
/* return early if user requested only program count or nothing to copy */
1563+
if (!request_cnt || !cnt)
1564+
return 0;
1565+
1566+
return bpf_prog_array_copy_to_user(array, prog_ids, request_cnt);
1567+
}
1568+
15481569
static void bpf_prog_free_deferred(struct work_struct *work)
15491570
{
15501571
struct bpf_prog_aux *aux;

kernel/events/core.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4723,6 +4723,9 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon
47234723
rcu_read_unlock();
47244724
return 0;
47254725
}
4726+
4727+
case PERF_EVENT_IOC_QUERY_BPF:
4728+
return bpf_event_query_prog_array(event, (void __user *)arg);
47264729
default:
47274730
return -ENOTTY;
47284731
}

kernel/trace/bpf_trace.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,3 +820,26 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
820820
unlock:
821821
mutex_unlock(&bpf_event_mutex);
822822
}
823+
824+
int bpf_event_query_prog_array(struct perf_event *event, void __user *info)
825+
{
826+
struct perf_event_query_bpf __user *uquery = info;
827+
struct perf_event_query_bpf query = {};
828+
int ret;
829+
830+
if (!capable(CAP_SYS_ADMIN))
831+
return -EPERM;
832+
if (event->attr.type != PERF_TYPE_TRACEPOINT)
833+
return -EINVAL;
834+
if (copy_from_user(&query, uquery, sizeof(query)))
835+
return -EFAULT;
836+
837+
mutex_lock(&bpf_event_mutex);
838+
ret = bpf_prog_array_copy_info(event->tp_event->prog_array,
839+
uquery->ids,
840+
query.ids_len,
841+
&uquery->prog_cnt);
842+
mutex_unlock(&bpf_event_mutex);
843+
844+
return ret;
845+
}

0 commit comments

Comments
 (0)