Skip to content

Commit e7c3067

Browse files
committed
io_uring/bpf_filter: cache lookup table in ctx->bpf_filters
Currently a few pointer dereferences need to be made to both check if BPF filters are installed, and then also to retrieve the actual filter for the opcode. Cache the table in ctx->bpf_filters to avoid that. Add a bit of debug info on ring exit to show if we ever got this wrong. Small risk of that given that the table is currently only updated in one spot, but once task forking is enabled, that will add one more spot. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 8768770 commit e7c3067

5 files changed

Lines changed: 23 additions & 10 deletions

File tree

include/linux/io_uring_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ struct io_ring_ctx {
287287

288288
struct task_struct *submitter_task;
289289
struct io_rings *rings;
290+
/* cache of ->restrictions.bpf_filters->filters */
291+
struct io_bpf_filter __rcu **bpf_filters;
290292
struct percpu_ref refs;
291293

292294
clockid_t clockid;

io_uring/bpf_filter.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,23 @@ static void io_uring_populate_bpf_ctx(struct io_uring_bpf_ctx *bctx,
5858
* __io_uring_run_bpf_filters() returns 0 on success, allow running the
5959
* request, and -EACCES when a request is denied.
6060
*/
61-
int __io_uring_run_bpf_filters(struct io_restriction *res, struct io_kiocb *req)
61+
int __io_uring_run_bpf_filters(struct io_bpf_filter __rcu **filters,
62+
struct io_kiocb *req)
6263
{
6364
struct io_bpf_filter *filter;
6465
struct io_uring_bpf_ctx bpf_ctx;
6566
int ret;
6667

6768
/* Fast check for existence of filters outside of RCU */
68-
if (!rcu_access_pointer(res->bpf_filters->filters[req->opcode]))
69+
if (!rcu_access_pointer(filters[req->opcode]))
6970
return 0;
7071

7172
/*
7273
* req->opcode has already been validated to be within the range
7374
* of what we expect, io_init_req() does this.
7475
*/
7576
guard(rcu)();
76-
filter = rcu_dereference(res->bpf_filters->filters[req->opcode]);
77+
filter = rcu_dereference(filters[req->opcode]);
7778
if (!filter)
7879
return 0;
7980
else if (filter == &dummy_filter)

io_uring/bpf_filter.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@
66

77
#ifdef CONFIG_IO_URING_BPF
88

9-
int __io_uring_run_bpf_filters(struct io_restriction *res, struct io_kiocb *req);
9+
int __io_uring_run_bpf_filters(struct io_bpf_filter __rcu **filters, struct io_kiocb *req);
1010

1111
int io_register_bpf_filter(struct io_restriction *res,
1212
struct io_uring_bpf __user *arg);
1313

1414
void io_put_bpf_filters(struct io_restriction *res);
1515

16-
static inline int io_uring_run_bpf_filters(struct io_restriction *res,
16+
static inline int io_uring_run_bpf_filters(struct io_bpf_filter __rcu **filters,
1717
struct io_kiocb *req)
1818
{
19-
if (res->bpf_filters)
20-
return __io_uring_run_bpf_filters(res, req);
19+
if (filters)
20+
return __io_uring_run_bpf_filters(filters, req);
2121

2222
return 0;
2323
}
@@ -29,7 +29,7 @@ static inline int io_register_bpf_filter(struct io_restriction *res,
2929
{
3030
return -EINVAL;
3131
}
32-
static inline int io_uring_run_bpf_filters(struct io_restriction *res,
32+
static inline int io_uring_run_bpf_filters(struct io_bpf_filter __rcu **filters,
3333
struct io_kiocb *req)
3434
{
3535
return 0;

io_uring/io_uring.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,8 +1875,8 @@ static inline int io_submit_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
18751875
if (unlikely(ret))
18761876
return io_submit_fail_init(sqe, req, ret);
18771877

1878-
if (unlikely(ctx->restrictions.bpf_filters)) {
1879-
ret = io_uring_run_bpf_filters(&ctx->restrictions, req);
1878+
if (unlikely(ctx->bpf_filters)) {
1879+
ret = io_uring_run_bpf_filters(ctx->bpf_filters, req);
18801880
if (ret)
18811881
return io_submit_fail_init(sqe, req, ret);
18821882
}
@@ -2168,6 +2168,13 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
21682168
percpu_ref_exit(&ctx->refs);
21692169
free_uid(ctx->user);
21702170
io_req_caches_free(ctx);
2171+
2172+
if (ctx->restrictions.bpf_filters) {
2173+
WARN_ON_ONCE(ctx->bpf_filters !=
2174+
ctx->restrictions.bpf_filters->filters);
2175+
} else {
2176+
WARN_ON_ONCE(ctx->bpf_filters);
2177+
}
21712178
io_put_bpf_filters(&ctx->restrictions);
21722179

21732180
WARN_ON_ONCE(ctx->nr_req_allocated);

io_uring/register.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,9 @@ static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,
837837
if (nr_args != 1)
838838
break;
839839
ret = io_register_bpf_filter(&ctx->restrictions, arg);
840+
if (!ret)
841+
WRITE_ONCE(ctx->bpf_filters,
842+
ctx->restrictions.bpf_filters->filters);
840843
break;
841844
default:
842845
ret = -EINVAL;

0 commit comments

Comments
 (0)