Skip to content

Commit 3dbb5b5

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf_enable_stats'
Song Liu says: ==================== run_time_ns is a useful stats for BPF programs. However, it is gated by sysctl kernel.bpf_stats_enabled. When multiple user space tools are toggling kernl.bpf_stats_enabled at the same time, they may confuse each other. Solve this problem with a new BPF command BPF_ENABLE_STATS. Changes v8 => v9: 1. Clean up in selftest (Andrii). 2. Not using static variable in test program (Andrii). Changes v7 => v8: 1. Change name BPF_STATS_RUNTIME_CNT => BPF_STATS_RUN_TIME (Alexei). 2. Add CHECK_ATTR to bpf_enable_stats() (Alexei). 3. Rebase (Andrii). 4. Simplfy the selftest (Alexei). Changes v6 => v7: 1. Add test to verify run_cnt matches count measured by the program. Changes v5 => v6: 1. Simplify test program (Yonghong). 2. Rebase (with some conflicts). Changes v4 => v5: 1. Use memset to zero bpf_attr in bpf_enable_stats() (Andrii). Changes v3 => v4: 1. Add libbpf support and selftest; 2. Avoid cleaning trailing space. Changes v2 => v3: 1. Rename the command to BPF_ENABLE_STATS, and make it extendible. 2. fix commit log; 3. remove unnecessary headers. ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents c321022 + 31a9f7f commit 3dbb5b5

File tree

10 files changed

+190
-1
lines changed

10 files changed

+190
-1
lines changed

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,7 @@ _out: \
987987

988988
#ifdef CONFIG_BPF_SYSCALL
989989
DECLARE_PER_CPU(int, bpf_prog_active);
990+
extern struct mutex bpf_stats_enabled_mutex;
990991

991992
/*
992993
* Block execution of BPF programs attached to instrumentation (perf,

include/uapi/linux/bpf.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ enum bpf_cmd {
115115
BPF_LINK_UPDATE,
116116
BPF_LINK_GET_FD_BY_ID,
117117
BPF_LINK_GET_NEXT_ID,
118+
BPF_ENABLE_STATS,
118119
};
119120

120121
enum bpf_map_type {
@@ -390,6 +391,12 @@ enum {
390391
*/
391392
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
392393

394+
/* type for BPF_ENABLE_STATS */
395+
enum bpf_stats_type {
396+
/* enabled run_time_ns and run_cnt */
397+
BPF_STATS_RUN_TIME = 0,
398+
};
399+
393400
enum bpf_stack_build_id_status {
394401
/* user space need an empty entry to identify end of a trace */
395402
BPF_STACK_BUILD_ID_EMPTY = 0,
@@ -601,6 +608,10 @@ union bpf_attr {
601608
__u32 old_prog_fd;
602609
} link_update;
603610

611+
struct { /* struct used by BPF_ENABLE_STATS command */
612+
__u32 type;
613+
} enable_stats;
614+
604615
} __attribute__((aligned(8)));
605616

606617
/* The description below is an attempt at providing documentation to eBPF

kernel/bpf/syscall.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3872,6 +3872,60 @@ static int bpf_link_get_fd_by_id(const union bpf_attr *attr)
38723872
return fd;
38733873
}
38743874

3875+
DEFINE_MUTEX(bpf_stats_enabled_mutex);
3876+
3877+
static int bpf_stats_release(struct inode *inode, struct file *file)
3878+
{
3879+
mutex_lock(&bpf_stats_enabled_mutex);
3880+
static_key_slow_dec(&bpf_stats_enabled_key.key);
3881+
mutex_unlock(&bpf_stats_enabled_mutex);
3882+
return 0;
3883+
}
3884+
3885+
static const struct file_operations bpf_stats_fops = {
3886+
.release = bpf_stats_release,
3887+
};
3888+
3889+
static int bpf_enable_runtime_stats(void)
3890+
{
3891+
int fd;
3892+
3893+
mutex_lock(&bpf_stats_enabled_mutex);
3894+
3895+
/* Set a very high limit to avoid overflow */
3896+
if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 2) {
3897+
mutex_unlock(&bpf_stats_enabled_mutex);
3898+
return -EBUSY;
3899+
}
3900+
3901+
fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC);
3902+
if (fd >= 0)
3903+
static_key_slow_inc(&bpf_stats_enabled_key.key);
3904+
3905+
mutex_unlock(&bpf_stats_enabled_mutex);
3906+
return fd;
3907+
}
3908+
3909+
#define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type
3910+
3911+
static int bpf_enable_stats(union bpf_attr *attr)
3912+
{
3913+
3914+
if (CHECK_ATTR(BPF_ENABLE_STATS))
3915+
return -EINVAL;
3916+
3917+
if (!capable(CAP_SYS_ADMIN))
3918+
return -EPERM;
3919+
3920+
switch (attr->enable_stats.type) {
3921+
case BPF_STATS_RUN_TIME:
3922+
return bpf_enable_runtime_stats();
3923+
default:
3924+
break;
3925+
}
3926+
return -EINVAL;
3927+
}
3928+
38753929
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
38763930
{
38773931
union bpf_attr attr;
@@ -3996,6 +4050,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
39964050
err = bpf_obj_get_next_id(&attr, uattr,
39974051
&link_idr, &link_idr_lock);
39984052
break;
4053+
case BPF_ENABLE_STATS:
4054+
err = bpf_enable_stats(&attr);
4055+
break;
39994056
default:
40004057
err = -EINVAL;
40014058
break;

kernel/sysctl.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,40 @@ static int max_extfrag_threshold = 1000;
201201

202202
#endif /* CONFIG_SYSCTL */
203203

204+
#ifdef CONFIG_BPF_SYSCALL
205+
static int bpf_stats_handler(struct ctl_table *table, int write,
206+
void __user *buffer, size_t *lenp,
207+
loff_t *ppos)
208+
{
209+
struct static_key *key = (struct static_key *)table->data;
210+
static int saved_val;
211+
int val, ret;
212+
struct ctl_table tmp = {
213+
.data = &val,
214+
.maxlen = sizeof(val),
215+
.mode = table->mode,
216+
.extra1 = SYSCTL_ZERO,
217+
.extra2 = SYSCTL_ONE,
218+
};
219+
220+
if (write && !capable(CAP_SYS_ADMIN))
221+
return -EPERM;
222+
223+
mutex_lock(&bpf_stats_enabled_mutex);
224+
val = saved_val;
225+
ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
226+
if (write && !ret && val != saved_val) {
227+
if (val)
228+
static_key_slow_inc(key);
229+
else
230+
static_key_slow_dec(key);
231+
saved_val = val;
232+
}
233+
mutex_unlock(&bpf_stats_enabled_mutex);
234+
return ret;
235+
}
236+
#endif
237+
204238
/*
205239
* /proc/sys support
206240
*/
@@ -2549,7 +2583,7 @@ static struct ctl_table kern_table[] = {
25492583
.data = &bpf_stats_enabled_key.key,
25502584
.maxlen = sizeof(bpf_stats_enabled_key),
25512585
.mode = 0644,
2552-
.proc_handler = proc_do_static_key,
2586+
.proc_handler = bpf_stats_handler,
25532587
},
25542588
#endif
25552589
#if defined(CONFIG_TREE_RCU)

tools/include/uapi/linux/bpf.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ enum bpf_cmd {
115115
BPF_LINK_UPDATE,
116116
BPF_LINK_GET_FD_BY_ID,
117117
BPF_LINK_GET_NEXT_ID,
118+
BPF_ENABLE_STATS,
118119
};
119120

120121
enum bpf_map_type {
@@ -390,6 +391,12 @@ enum {
390391
*/
391392
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
392393

394+
/* type for BPF_ENABLE_STATS */
395+
enum bpf_stats_type {
396+
/* enabled run_time_ns and run_cnt */
397+
BPF_STATS_RUN_TIME = 0,
398+
};
399+
393400
enum bpf_stack_build_id_status {
394401
/* user space need an empty entry to identify end of a trace */
395402
BPF_STACK_BUILD_ID_EMPTY = 0,
@@ -601,6 +608,10 @@ union bpf_attr {
601608
__u32 old_prog_fd;
602609
} link_update;
603610

611+
struct { /* struct used by BPF_ENABLE_STATS command */
612+
__u32 type;
613+
} enable_stats;
614+
604615
} __attribute__((aligned(8)));
605616

606617
/* The description below is an attempt at providing documentation to eBPF

tools/lib/bpf/bpf.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,3 +841,13 @@ int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len,
841841

842842
return err;
843843
}
844+
845+
int bpf_enable_stats(enum bpf_stats_type type)
846+
{
847+
union bpf_attr attr;
848+
849+
memset(&attr, 0, sizeof(attr));
850+
attr.enable_stats.type = type;
851+
852+
return sys_bpf(BPF_ENABLE_STATS, &attr, sizeof(attr));
853+
}

tools/lib/bpf/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ LIBBPF_API int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf,
231231
LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
232232
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
233233
__u64 *probe_offset, __u64 *probe_addr);
234+
LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type);
234235

235236
#ifdef __cplusplus
236237
} /* extern "C" */

tools/lib/bpf/libbpf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ LIBBPF_0.0.8 {
257257

258258
LIBBPF_0.0.9 {
259259
global:
260+
bpf_enable_stats;
260261
bpf_link_get_fd_by_id;
261262
bpf_link_get_next_id;
262263
} LIBBPF_0.0.8;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <test_progs.h>
3+
#include "test_enable_stats.skel.h"
4+
5+
void test_enable_stats(void)
6+
{
7+
struct test_enable_stats *skel;
8+
int stats_fd, err, prog_fd;
9+
struct bpf_prog_info info;
10+
__u32 info_len = sizeof(info);
11+
int duration = 0;
12+
13+
skel = test_enable_stats__open_and_load();
14+
if (CHECK(!skel, "skel_open_and_load", "skeleton open/load failed\n"))
15+
return;
16+
17+
stats_fd = bpf_enable_stats(BPF_STATS_RUN_TIME);
18+
if (CHECK(stats_fd < 0, "get_stats_fd", "failed %d\n", errno)) {
19+
test_enable_stats__destroy(skel);
20+
return;
21+
}
22+
23+
err = test_enable_stats__attach(skel);
24+
if (CHECK(err, "attach_raw_tp", "err %d\n", err))
25+
goto cleanup;
26+
27+
test_enable_stats__detach(skel);
28+
29+
prog_fd = bpf_program__fd(skel->progs.test_enable_stats);
30+
memset(&info, 0, info_len);
31+
err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
32+
if (CHECK(err, "get_prog_info",
33+
"failed to get bpf_prog_info for fd %d\n", prog_fd))
34+
goto cleanup;
35+
if (CHECK(info.run_time_ns == 0, "check_stats_enabled",
36+
"failed to enable run_time_ns stats\n"))
37+
goto cleanup;
38+
39+
CHECK(info.run_cnt != skel->bss->count, "check_run_cnt_valid",
40+
"invalid run_cnt stats\n");
41+
42+
cleanup:
43+
test_enable_stats__destroy(skel);
44+
close(stats_fd);
45+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (c) 2020 Facebook
3+
4+
#include <linux/bpf.h>
5+
#include <stdint.h>
6+
#include <linux/types.h>
7+
#include <bpf/bpf_helpers.h>
8+
9+
char _license[] SEC("license") = "GPL";
10+
11+
__u64 count = 0;
12+
13+
SEC("raw_tracepoint/sys_enter")
14+
int test_enable_stats(void *ctx)
15+
{
16+
count += 1;
17+
return 0;
18+
}

0 commit comments

Comments
 (0)