Re: [RFC v2 3/5] io_uring/bpf: implement struct_ops registration

From: Pavel Begunkov
Date: Fri Jun 06 2025 - 15:59:33 EST


On 6/6/25 15:57, Jens Axboe wrote:
...>> @@ -50,20 +52,83 @@ 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;

Possible to pass in here whether the ring fd is registered or not? Such
that it can be used in bpf_io_reg() as well.

That requires registration to be done off the syscall path (e.g. no
workers), which is low risk and I'm pretty sure that's how it's done,
but in either case that's not up to io_uring and should be vetted by
bpf. It's not important to performance, and leaking that to other
syscalls is a bad idea as well, so in the meantime it's just left
unsupported.

+static int io_register_bpf_ops(struct io_ring_ctx *ctx, struct io_uring_ops *ops)
+{
+ if (ctx->bpf_ops)
+ return -EBUSY;
+ if (!(ctx->flags & IORING_SETUP_DEFER_TASKRUN))
+ return -EOPNOTSUPP;
+
+ percpu_ref_get(&ctx->refs);
+ ops->ctx = ctx;
+ ctx->bpf_ops = ops;
return 0;
}

Haven't looked too deeply yet, but what's the dependency with
DEFER_TASKRUN?
Unregistration needs to be sync'ed with waiters, and that can easily
become a problem. Taking the lock like in this set in not necessarily
the right solution. I plan to wait and see where it goes rather
than shooting myself in the leg right away.

--
Pavel Begunkov