Add ring_fd to the struct_ops and implement [un]registration. Signed-off-by: Pavel Begunkov --- include/linux/io_uring_types.h | 2 + io_uring/bpf.c | 69 +++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h index 43432a06d177..3a71ed2d05ea 100644 --- a/include/linux/io_uring_types.h +++ b/include/linux/io_uring_types.h @@ -274,6 +274,8 @@ struct io_ring_ctx { unsigned int compat: 1; unsigned int iowq_limits_set : 1; + unsigned int bpf_installed: 1; + struct task_struct *submitter_task; struct io_rings *rings; struct percpu_ref refs; diff --git a/io_uring/bpf.c b/io_uring/bpf.c index 24dd2fe9134f..683e87f1a58b 100644 --- a/io_uring/bpf.c +++ b/io_uring/bpf.c @@ -4,6 +4,7 @@ #include "bpf.h" #include "register.h" +static DEFINE_MUTEX(io_bpf_ctrl_mutex); static const struct btf_type *loop_state_type; static int io_bpf_ops__loop(struct io_ring_ctx *ctx, struct iou_loop_state *ls) @@ -87,20 +88,86 @@ static int bpf_io_init_member(const struct btf_type *t, const struct btf_member *member, void *kdata, const void *udata) { + u32 moff = __btf_member_bit_offset(t, member) / 8; + const struct io_uring_ops *uops = udata; + struct io_uring_ops *ops = kdata; + + switch (moff) { + case offsetof(struct io_uring_ops, ring_fd): + ops->ring_fd = uops->ring_fd; + return 1; + } + return 0; +} + +static int io_install_bpf(struct io_ring_ctx *ctx, struct io_uring_ops *ops) +{ + if (ctx->bpf_ops) + return -EBUSY; + ops->priv = ctx; + ctx->bpf_ops = ops; + ctx->bpf_installed = 1; return 0; } static int bpf_io_reg(void *kdata, struct bpf_link *link) { - return -EOPNOTSUPP; + struct io_uring_ops *ops = kdata; + struct io_ring_ctx *ctx; + struct file *file; + int ret = -EBUSY; + + file = io_uring_register_get_file(ops->ring_fd, false); + if (IS_ERR(file)) + return PTR_ERR(file); + ctx = file->private_data; + + scoped_guard(mutex, &io_bpf_ctrl_mutex) { + guard(mutex)(&ctx->uring_lock); + ret = io_install_bpf(ctx, ops); + } + + fput(file); + return ret; +} + +static void io_eject_bpf(struct io_ring_ctx *ctx) +{ + struct io_uring_ops *ops = ctx->bpf_ops; + + if (!WARN_ON_ONCE(!ops)) + return; + if (WARN_ON_ONCE(ops->priv != ctx)) + return; + + ops->priv = NULL; + ctx->bpf_ops = NULL; } static void bpf_io_unreg(void *kdata, struct bpf_link *link) { + struct io_uring_ops *ops = kdata; + struct io_ring_ctx *ctx; + + guard(mutex)(&io_bpf_ctrl_mutex); + ctx = ops->priv; + if (ctx) { + guard(mutex)(&ctx->uring_lock); + if (WARN_ON_ONCE(ctx->bpf_ops != ops)) + return; + + io_eject_bpf(ctx); + } } void io_unregister_bpf(struct io_ring_ctx *ctx) { + if (!ctx->bpf_installed) + return; + guard(mutex)(&io_bpf_ctrl_mutex); + guard(mutex)(&ctx->uring_lock); + if (ctx->bpf_ops) + io_eject_bpf(ctx); } static struct bpf_struct_ops bpf_io_uring_ops = { -- 2.49.0