Skip to content

bpf: Speed up trampoline attach #256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
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
33 changes: 33 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
sudo: required
language: bash
dist: bionic
services:
- docker

env:
global:
- PROJECT_NAME='libbpf'
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
- REPO_ROOT="$TRAVIS_BUILD_DIR"
- CI_ROOT="$REPO_ROOT/travis-ci"
- VMTEST_ROOT="$CI_ROOT/vmtest"

addons:
apt:
packages:
- qemu-kvm
- zstd
- binutils-dev
- elfutils
- libcap-dev
- libelf-dev
- libdw-dev
- python3-docutils

jobs:
include:
- stage: Builds & Tests
name: Kernel LATEST + selftests
language: bash
env: KERNEL=LATEST
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
18 changes: 15 additions & 3 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,13 @@ enum bpf_tramp_prog_type {
BPF_TRAMP_REPLACE, /* more than MAX */
};

struct bpf_trampoline_batch {
int count;
int idx;
unsigned long *ips;
unsigned long *addrs;
};

struct bpf_trampoline {
/* hlist for trampoline_table */
struct hlist_node hlist;
Expand Down Expand Up @@ -644,11 +651,15 @@ static __always_inline unsigned int bpf_dispatcher_nop_func(
return bpf_func(ctx, insnsi);
}
#ifdef CONFIG_BPF_JIT
int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr);
int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr);
int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr,
struct bpf_trampoline_batch *batch);
int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr,
struct bpf_trampoline_batch *batch);
struct bpf_trampoline *bpf_trampoline_get(u64 key,
struct bpf_attach_target_info *tgt_info);
void bpf_trampoline_put(struct bpf_trampoline *tr);
struct bpf_trampoline_batch *bpf_trampoline_batch_alloc(int count);
void bpf_trampoline_batch_free(struct bpf_trampoline_batch *batch);
#define BPF_DISPATCHER_INIT(_name) { \
.mutex = __MUTEX_INITIALIZER(_name.mutex), \
.func = &_name##_func, \
Expand Down Expand Up @@ -693,7 +704,8 @@ void bpf_ksym_add(struct bpf_ksym *ksym);
void bpf_ksym_del(struct bpf_ksym *ksym);
#else
static inline int bpf_trampoline_link_prog(struct bpf_prog *prog,
struct bpf_trampoline *tr)
struct bpf_trampoline *tr,
struct bpf_trampoline_batch *batch)
{
return -ENOTSUPP;
}
Expand Down
7 changes: 7 additions & 0 deletions include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ int ftrace_modify_direct_caller(struct ftrace_func_entry *entry,
unsigned long old_addr,
unsigned long new_addr);
unsigned long ftrace_find_rec_direct(unsigned long ip);
int register_ftrace_direct_ips(unsigned long *ips, unsigned long *addrs,
int count);
int unregister_ftrace_direct_ips(unsigned long *ips, unsigned long *addrs,
int count);
#else
# define ftrace_direct_func_count 0
static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)
Expand Down Expand Up @@ -463,6 +467,8 @@ struct dyn_ftrace {
int ftrace_force_update(void);
int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
int remove, int reset);
int ftrace_set_filter_ips(struct ftrace_ops *ops, unsigned long *ips,
int count, int remove);
int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
int len, int reset);
int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
Expand Down Expand Up @@ -738,6 +744,7 @@ static inline unsigned long ftrace_location(unsigned long ip)
#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
#define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
#define ftrace_set_filter_ip(ops, ip, remove, reset) ({ -ENODEV; })
#define ftrace_set_filter_ips(ops, ip, remove) ({ -ENODEV; })
#define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; })
#define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
#define ftrace_free_filter(ops) do { } while (0)
Expand Down
8 changes: 8 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ enum bpf_cmd {
BPF_ITER_CREATE,
BPF_LINK_DETACH,
BPF_PROG_BIND_MAP,
BPF_TRAMPOLINE_BATCH_ATTACH,
BPF_TRAMPOLINE_BATCH_DETACH,
};

enum bpf_map_type {
Expand Down Expand Up @@ -631,6 +633,12 @@ union bpf_attr {
__u32 prog_fd;
} raw_tracepoint;

struct { /* anonymous struct used by BPF_TRAMPOLINE_BATCH_* */
__aligned_u64 in;
__aligned_u64 out;
__u32 count;
} trampoline_batch;

struct { /* anonymous struct for BPF_BTF_LOAD */
__aligned_u64 btf;
__aligned_u64 btf_log_buf;
Expand Down
125 changes: 114 additions & 11 deletions kernel/bpf/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <linux/poll.h>
#include <linux/bpf-netns.h>
#include <linux/rcupdate_trace.h>
#include <linux/rcupdate_wait.h>

#define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
(map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
Expand Down Expand Up @@ -2346,12 +2347,8 @@ void bpf_link_put(struct bpf_link *link)
if (!atomic64_dec_and_test(&link->refcnt))
return;

if (in_atomic()) {
INIT_WORK(&link->work, bpf_link_put_deferred);
schedule_work(&link->work);
} else {
bpf_link_free(link);
}
INIT_WORK(&link->work, bpf_link_put_deferred);
schedule_work(&link->work);
}

static int bpf_link_release(struct inode *inode, struct file *filp)
Expand Down Expand Up @@ -2509,7 +2506,7 @@ static void bpf_tracing_link_release(struct bpf_link *link)
container_of(link, struct bpf_tracing_link, link);

WARN_ON_ONCE(bpf_trampoline_unlink_prog(link->prog,
tr_link->trampoline));
tr_link->trampoline, NULL));

bpf_trampoline_put(tr_link->trampoline);

Expand Down Expand Up @@ -2557,7 +2554,8 @@ static const struct bpf_link_ops bpf_tracing_link_lops = {

static int bpf_tracing_prog_attach(struct bpf_prog *prog,
int tgt_prog_fd,
u32 btf_id)
u32 btf_id,
struct bpf_trampoline_batch *batch)
{
struct bpf_link_primer link_primer;
struct bpf_prog *tgt_prog = NULL;
Expand Down Expand Up @@ -2682,7 +2680,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
if (err)
goto out_unlock;

err = bpf_trampoline_link_prog(prog, tr);
err = bpf_trampoline_link_prog(prog, tr, batch);
if (err) {
bpf_link_cleanup(&link_primer);
link = NULL;
Expand Down Expand Up @@ -2830,7 +2828,7 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
tp_name = prog->aux->attach_func_name;
break;
}
return bpf_tracing_prog_attach(prog, 0, 0);
return bpf_tracing_prog_attach(prog, 0, 0, NULL);
case BPF_PROG_TYPE_RAW_TRACEPOINT:
case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
if (strncpy_from_user(buf,
Expand Down Expand Up @@ -2883,6 +2881,106 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
return err;
}

#define BPF_RAW_TRACEPOINT_OPEN_BATCH_LAST_FIELD trampoline_batch.count

static int bpf_trampoline_batch(const union bpf_attr *attr, int cmd)
{
void __user *uout = u64_to_user_ptr(attr->trampoline_batch.out);
void __user *uin = u64_to_user_ptr(attr->trampoline_batch.in);
struct bpf_trampoline_batch *batch = NULL;
struct bpf_prog *prog;
int count, ret, i, fd;
u32 *in, *out;

if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN_BATCH))
return -EINVAL;

if (!uin || !uout)
return -EINVAL;

count = attr->trampoline_batch.count;

in = kcalloc(count, sizeof(u32), GFP_KERNEL);
out = kcalloc(count, sizeof(u32), GFP_KERNEL);
if (!in || !out) {
kfree(in);
kfree(out);
return -ENOMEM;
}

ret = copy_from_user(in, uin, count * sizeof(u32));
if (ret)
goto out_clean;

/* test read out array */
ret = copy_to_user(uout, out, count * sizeof(u32));
if (ret)
goto out_clean;

batch = bpf_trampoline_batch_alloc(count);
if (!batch)
goto out_clean;

synchronize_rcu_mult(call_rcu_tasks, call_rcu_tasks_trace);

for (i = 0; i < count; i++) {
if (cmd == BPF_TRAMPOLINE_BATCH_ATTACH) {
prog = bpf_prog_get(in[i]);
if (IS_ERR(prog)) {
ret = PTR_ERR(prog);
goto out_clean;
}

ret = -EINVAL;
if (prog->type != BPF_PROG_TYPE_TRACING)
goto out_clean;
if (prog->type == BPF_PROG_TYPE_TRACING &&
prog->expected_attach_type == BPF_TRACE_RAW_TP)
goto out_clean;

fd = bpf_tracing_prog_attach(prog, 0, 0, batch);
if (fd < 0)
goto out_clean;

out[i] = fd;
} else {
struct bpf_tracing_link *tr_link;
struct bpf_link *link;

link = bpf_link_get_from_fd(in[i]);
if (IS_ERR(link)) {
ret = PTR_ERR(link);
goto out_clean;
}

if (link->type != BPF_LINK_TYPE_TRACING) {
ret = -EINVAL;
bpf_link_put(link);
goto out_clean;
}

tr_link = container_of(link, struct bpf_tracing_link, link);
bpf_trampoline_unlink_prog(link->prog, tr_link->trampoline, batch);
bpf_link_put(link);
}
}

if (cmd == BPF_TRAMPOLINE_BATCH_ATTACH)
ret = register_ftrace_direct_ips(batch->ips, batch->addrs, batch->idx);
else
ret = unregister_ftrace_direct_ips(batch->ips, batch->addrs, batch->idx);

if (!ret)
WARN_ON_ONCE(copy_to_user(uout, out, count * sizeof(u32)));

out_clean:
/* XXX cleanup partialy attached array */
bpf_trampoline_batch_free(batch);
kfree(in);
kfree(out);
return ret;
}

static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
enum bpf_attach_type attach_type)
{
Expand Down Expand Up @@ -4022,7 +4120,8 @@ static int tracing_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *
else if (prog->type == BPF_PROG_TYPE_EXT)
return bpf_tracing_prog_attach(prog,
attr->link_create.target_fd,
attr->link_create.target_btf_id);
attr->link_create.target_btf_id,
NULL);
return -EINVAL;
}

Expand Down Expand Up @@ -4441,6 +4540,10 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
case BPF_RAW_TRACEPOINT_OPEN:
err = bpf_raw_tracepoint_open(&attr);
break;
case BPF_TRAMPOLINE_BATCH_ATTACH:
case BPF_TRAMPOLINE_BATCH_DETACH:
err = bpf_trampoline_batch(&attr, cmd);
break;
case BPF_BTF_LOAD:
err = bpf_btf_load(&attr);
break;
Expand Down
Loading