Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions kernel/trace/bpf_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include <asm/tlb.h>

#include <trace/events/bpf_test_run.h>

#include "trace_probe.h"
#include "trace.h"

Expand Down Expand Up @@ -1160,7 +1162,112 @@ const struct bpf_verifier_ops perf_event_verifier_ops = {
.convert_ctx_access = pe_prog_convert_ctx_access,
};

static int pe_prog_test_run(struct bpf_prog *prog,
const union bpf_attr *kattr,
union bpf_attr __user *uattr)
{
void __user *ctx_in = u64_to_user_ptr(kattr->test.ctx_in);
void __user *data_in = u64_to_user_ptr(kattr->test.data_in);
u32 data_size_in = kattr->test.data_size_in;
u32 ctx_size_in = kattr->test.ctx_size_in;
u32 repeat = kattr->test.repeat;
u32 retval = 0, duration = 0;
int err = -EINVAL;
u64 time_start, time_spent = 0;
int i;
struct perf_sample_data sample_data = {0, };
struct perf_event event = {0, };
struct bpf_perf_event_data_kern real_ctx = {0, };
struct bpf_perf_event_data fake_ctx = {0, };
struct bpf_perf_event_value value = {0, };

if (ctx_size_in != sizeof(fake_ctx))
goto out;
if (data_size_in != sizeof(value))
goto out;

if (copy_from_user(&fake_ctx, ctx_in, ctx_size_in)) {
err = -EFAULT;
goto out;
}
if (copy_from_user(&value, data_in, data_size_in)) {
err = -EFAULT;
goto out;
}

real_ctx.regs = &fake_ctx.regs;
real_ctx.data = &sample_data;
real_ctx.event = &event;
perf_sample_data_init(&sample_data, fake_ctx.addr,
fake_ctx.sample_period);
event.cpu = smp_processor_id();
event.oncpu = -1;
event.state = PERF_EVENT_STATE_OFF;
local64_set(&event.count, value.counter);
event.total_time_enabled = value.enabled;
event.total_time_running = value.running;
/* make self as a leader - it is used only for checking the
* state field
*/
event.group_leader = &event;

/* slightly changed copy pasta from bpf_test_run() in
* net/bpf/test_run.c
*/
if (!repeat)
repeat = 1;

rcu_read_lock();
preempt_disable();
time_start = ktime_get_ns();
for (i = 0; i < repeat; i++) {
retval = BPF_PROG_RUN(prog, &real_ctx);

if (signal_pending(current)) {
err = -EINTR;
preempt_enable();
rcu_read_unlock();
goto out;
}

if (need_resched()) {
time_spent += ktime_get_ns() - time_start;
preempt_enable();
rcu_read_unlock();

cond_resched();

rcu_read_lock();
preempt_disable();
time_start = ktime_get_ns();
}
}
time_spent += ktime_get_ns() - time_start;
preempt_enable();
rcu_read_unlock();

do_div(time_spent, repeat);
duration = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;
/* end of slightly changed copy pasta from bpf_test_run() in
* net/bpf/test_run.c
*/

if (copy_to_user(&uattr->test.retval, &retval, sizeof(retval))) {
err = -EFAULT;
goto out;
}
if (copy_to_user(&uattr->test.duration, &duration, sizeof(duration))) {
err = -EFAULT;
goto out;
}
err = 0;
out:
trace_bpf_test_finish(&err);
return err;
}

const struct bpf_prog_ops perf_event_prog_ops = {
.test_run = pe_prog_test_run,
};

static DEFINE_MUTEX(bpf_event_mutex);
Expand Down
28 changes: 28 additions & 0 deletions tools/include/linux/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,32 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
# define __fallthrough
#endif


#ifdef __OPTIMIZE__
# define __compiletime_assert(condition, msg, prefix, suffix) \
do { \
extern void prefix ## suffix(void) __compiletime_error(msg); \
if (!(condition)) \
prefix ## suffix(); \
} while (0)
#else
# define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0)
#endif

#define _compiletime_assert(condition, msg, prefix, suffix) \
__compiletime_assert(condition, msg, prefix, suffix)

/**
* compiletime_assert - break build and emit msg if condition is false
* @condition: a compile-time constant condition to check
* @msg: a message to emit if condition is false
*
* In tradition of POSIX assert, this macro will break the build if the
* supplied condition is *false*, emitting the supplied error message if the
* compiler has support to do so.
*/
#define compiletime_assert(condition, msg) \
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)


#endif /* _TOOLS_LINUX_COMPILER_H */
1 change: 1 addition & 0 deletions tools/include/uapi/linux/bpf_perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
struct bpf_perf_event_data {
bpf_user_pt_regs_t regs;
__u64 sample_period;
__u64 addr;
};

#endif /* _UAPI__LINUX_BPF_PERF_EVENT_H__ */
Loading