Skip to content

Commit d0e437b

Browse files
isilenceaxboe
authored andcommitted
io_uring/bpf-ops: implement loop_step with BPF struct_ops
Introduce io_uring BPF struct ops implementing the loop_step callback, which will allow BPF to overwrite the default io_uring event loop logic. The callback takes an io_uring context, the main role of which is to be passed to io_uring kfuncs. The other argument is a struct iou_loop_params, which BPF can use to request CQ waiting and communicate other parameters. See the event loop description in the previous patch for more details. Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> Link: https://patch.msgid.link/98db437651ce64e9cbeb611c60bf5887259db09f.1772109579.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 033af2b commit d0e437b

5 files changed

Lines changed: 148 additions & 0 deletions

File tree

io_uring/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ config IO_URING_BPF
1414
def_bool y
1515
depends on BPF
1616
depends on NET
17+
18+
config IO_URING_BPF_OPS
19+
def_bool y
20+
depends on IO_URING
21+
depends on BPF_SYSCALL && BPF_JIT && DEBUG_INFO_BTF

io_uring/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ obj-$(CONFIG_NET) += net.o cmd_net.o
2525
obj-$(CONFIG_PROC_FS) += fdinfo.o
2626
obj-$(CONFIG_IO_URING_MOCK_FILE) += mock_file.o
2727
obj-$(CONFIG_IO_URING_BPF) += bpf_filter.o
28+
obj-$(CONFIG_IO_URING_BPF_OPS) += bpf-ops.o

io_uring/bpf-ops.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#include <linux/mutex.h>
3+
#include <linux/bpf.h>
4+
#include <linux/bpf_verifier.h>
5+
6+
#include "io_uring.h"
7+
#include "register.h"
8+
#include "bpf-ops.h"
9+
#include "loop.h"
10+
11+
static const struct btf_type *loop_params_type;
12+
13+
static int io_bpf_ops__loop_step(struct io_ring_ctx *ctx,
14+
struct iou_loop_params *lp)
15+
{
16+
return IOU_LOOP_STOP;
17+
}
18+
19+
static struct io_uring_bpf_ops io_bpf_ops_stubs = {
20+
.loop_step = io_bpf_ops__loop_step,
21+
};
22+
23+
static bool bpf_io_is_valid_access(int off, int size,
24+
enum bpf_access_type type,
25+
const struct bpf_prog *prog,
26+
struct bpf_insn_access_aux *info)
27+
{
28+
if (type != BPF_READ)
29+
return false;
30+
if (off < 0 || off >= sizeof(__u64) * MAX_BPF_FUNC_ARGS)
31+
return false;
32+
if (off % size != 0)
33+
return false;
34+
35+
return btf_ctx_access(off, size, type, prog, info);
36+
}
37+
38+
static int bpf_io_btf_struct_access(struct bpf_verifier_log *log,
39+
const struct bpf_reg_state *reg, int off,
40+
int size)
41+
{
42+
const struct btf_type *t = btf_type_by_id(reg->btf, reg->btf_id);
43+
44+
if (t == loop_params_type) {
45+
if (off + size <= offsetofend(struct iou_loop_params, cq_wait_idx))
46+
return SCALAR_VALUE;
47+
}
48+
49+
return -EACCES;
50+
}
51+
52+
static const struct bpf_verifier_ops bpf_io_verifier_ops = {
53+
.get_func_proto = bpf_base_func_proto,
54+
.is_valid_access = bpf_io_is_valid_access,
55+
.btf_struct_access = bpf_io_btf_struct_access,
56+
};
57+
58+
static const struct btf_type *
59+
io_lookup_struct_type(struct btf *btf, const char *name)
60+
{
61+
s32 type_id;
62+
63+
type_id = btf_find_by_name_kind(btf, name, BTF_KIND_STRUCT);
64+
if (type_id < 0)
65+
return NULL;
66+
return btf_type_by_id(btf, type_id);
67+
}
68+
69+
static int bpf_io_init(struct btf *btf)
70+
{
71+
loop_params_type = io_lookup_struct_type(btf, "iou_loop_params");
72+
if (!loop_params_type) {
73+
pr_err("io_uring: Failed to locate iou_loop_params\n");
74+
return -EINVAL;
75+
}
76+
77+
return 0;
78+
}
79+
80+
static int bpf_io_check_member(const struct btf_type *t,
81+
const struct btf_member *member,
82+
const struct bpf_prog *prog)
83+
{
84+
return 0;
85+
}
86+
87+
static int bpf_io_init_member(const struct btf_type *t,
88+
const struct btf_member *member,
89+
void *kdata, const void *udata)
90+
{
91+
return 0;
92+
}
93+
94+
static int bpf_io_reg(void *kdata, struct bpf_link *link)
95+
{
96+
return -EOPNOTSUPP;
97+
}
98+
99+
static void bpf_io_unreg(void *kdata, struct bpf_link *link)
100+
{
101+
}
102+
103+
static struct bpf_struct_ops bpf_ring_ops = {
104+
.verifier_ops = &bpf_io_verifier_ops,
105+
.reg = bpf_io_reg,
106+
.unreg = bpf_io_unreg,
107+
.check_member = bpf_io_check_member,
108+
.init_member = bpf_io_init_member,
109+
.init = bpf_io_init,
110+
.cfi_stubs = &io_bpf_ops_stubs,
111+
.name = "io_uring_bpf_ops",
112+
.owner = THIS_MODULE,
113+
};
114+
115+
static int __init io_uring_bpf_init(void)
116+
{
117+
int ret;
118+
119+
ret = register_bpf_struct_ops(&bpf_ring_ops, io_uring_bpf_ops);
120+
if (ret) {
121+
pr_err("io_uring: Failed to register struct_ops (%d)\n", ret);
122+
return ret;
123+
}
124+
125+
return 0;
126+
}
127+
__initcall(io_uring_bpf_init);

io_uring/bpf-ops.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#ifndef IOU_BPF_OPS_H
3+
#define IOU_BPF_OPS_H
4+
5+
#include <linux/io_uring_types.h>
6+
7+
struct io_uring_bpf_ops {
8+
int (*loop_step)(struct io_ring_ctx *ctx, struct iou_loop_params *lp);
9+
10+
__u32 ring_fd;
11+
void *priv;
12+
};
13+
14+
#endif /* IOU_BPF_OPS_H */

io_uring/io_uring.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
#include "msg_ring.h"
8888
#include "memmap.h"
8989
#include "zcrx.h"
90+
#include "bpf-ops.h"
9091

9192
#include "timeout.h"
9293
#include "poll.h"

0 commit comments

Comments
 (0)