[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251025191504.3024224-4-dw@davidwei.uk>
Date: Sat, 25 Oct 2025 12:15:02 -0700
From: David Wei <dw@...idwei.uk>
To: io-uring@...r.kernel.org,
netdev@...r.kernel.org
Cc: Jens Axboe <axboe@...nel.dk>,
Pavel Begunkov <asml.silence@...il.com>
Subject: [PATCH v2 3/5] io_uring/zcrx: share an ifq between rings
Add a way to share an ifq from a src ring that is real i.e. bound to a
HW RX queue with other rings. This is done by passing a new flag
IORING_ZCRX_IFQ_REG_PROXY in the registration struct
io_uring_zcrx_ifq_reg, alongside the fd of the src ring and the ifq id
to be proxied.
It is not permitted to proxy another proxy ifq; it must be a real ifq.
The proxy ifq has most fields zero initialised. The exception is
ifq->if_rxq, which is set to the same value as the src ifq. This is
because if_rxq will be used by the cleanup code to denote an ifq that
has been cleaned up but not yet freed.
To prevent the src ring or ifq from being cleaned up or freed while the
proxy exists, take the appropriate refs on the src ring (ctx->refs) and
src ifq (ifq->refs). The subsequent patch that adds cleaning up proxy
ifqs will discuss lifetimes in more detail.
Signed-off-by: David Wei <dw@...idwei.uk>
---
include/uapi/linux/io_uring.h | 4 ++
io_uring/zcrx.c | 72 ++++++++++++++++++++++++++++++++++-
io_uring/zcrx.h | 1 +
3 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 263bed13473e..10f6347b1725 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -1055,6 +1055,10 @@ struct io_uring_zcrx_area_reg {
__u64 __resv2[2];
};
+enum io_uring_zcrx_ifq_reg_flags {
+ IORING_ZCRX_IFQ_REG_PROXY = 1,
+};
+
/*
* Argument for IORING_REGISTER_ZCRX_IFQ
*/
diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
index 22d759307c16..6b9066333fcf 100644
--- a/io_uring/zcrx.c
+++ b/io_uring/zcrx.c
@@ -22,10 +22,10 @@
#include <uapi/linux/io_uring.h>
#include "io_uring.h"
-#include "kbuf.h"
#include "memmap.h"
#include "zcrx.h"
#include "rsrc.h"
+#include "register.h"
#define IO_ZCRX_AREA_SUPPORTED_FLAGS (IORING_ZCRX_AREA_DMABUF)
@@ -541,6 +541,74 @@ struct io_mapped_region *io_zcrx_get_region(struct io_ring_ctx *ctx,
return ifq ? &ifq->region : NULL;
}
+static int io_proxy_zcrx_ifq(struct io_ring_ctx *ctx,
+ struct io_uring_zcrx_ifq_reg __user *arg,
+ struct io_uring_zcrx_ifq_reg *reg)
+{
+ struct io_zcrx_ifq *ifq, *src_ifq;
+ struct io_ring_ctx *src_ctx;
+ struct file *file;
+ int src_fd, ret;
+ u32 src_id, id;
+
+ src_fd = reg->if_idx;
+ src_id = reg->if_rxq;
+
+ file = io_uring_register_get_file(src_fd, false);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ src_ctx = file->private_data;
+ if (src_ctx == ctx)
+ return -EBADFD;
+
+ mutex_unlock(&ctx->uring_lock);
+ io_lock_two_rings(ctx, src_ctx);
+
+ ret = -EINVAL;
+ src_ifq = xa_load(&src_ctx->zcrx_ctxs, src_id);
+ if (!src_ifq || src_ifq->proxy)
+ goto err_unlock;
+
+ percpu_ref_get(&src_ctx->refs);
+ refcount_inc(&src_ifq->refs);
+
+ ifq = kzalloc(sizeof(*ifq), GFP_KERNEL);
+ ifq->proxy = src_ifq;
+ ifq->ctx = ctx;
+ ifq->if_rxq = src_ifq->if_rxq;
+
+ scoped_guard(mutex, &ctx->mmap_lock) {
+ ret = xa_alloc(&ctx->zcrx_ctxs, &id, NULL, xa_limit_31b, GFP_KERNEL);
+ if (ret)
+ goto err_free;
+
+ ret = -ENOMEM;
+ if (xa_store(&ctx->zcrx_ctxs, id, ifq, GFP_KERNEL)) {
+ xa_erase(&ctx->zcrx_ctxs, id);
+ goto err_free;
+ }
+ }
+
+ reg->zcrx_id = id;
+ if (copy_to_user(arg, reg, sizeof(*reg))) {
+ ret = -EFAULT;
+ goto err;
+ }
+ mutex_unlock(&src_ctx->uring_lock);
+ fput(file);
+ return 0;
+err:
+ scoped_guard(mutex, &ctx->mmap_lock)
+ xa_erase(&ctx->zcrx_ctxs, id);
+err_free:
+ kfree(ifq);
+err_unlock:
+ mutex_unlock(&src_ctx->uring_lock);
+ fput(file);
+ return ret;
+}
+
int io_register_zcrx_ifq(struct io_ring_ctx *ctx,
struct io_uring_zcrx_ifq_reg __user *arg)
{
@@ -566,6 +634,8 @@ int io_register_zcrx_ifq(struct io_ring_ctx *ctx,
return -EINVAL;
if (copy_from_user(®, arg, sizeof(reg)))
return -EFAULT;
+ if (reg.flags & IORING_ZCRX_IFQ_REG_PROXY)
+ return io_proxy_zcrx_ifq(ctx, arg, ®);
if (copy_from_user(&rd, u64_to_user_ptr(reg.region_ptr), sizeof(rd)))
return -EFAULT;
if (!mem_is_zero(®.__resv, sizeof(reg.__resv)) ||
diff --git a/io_uring/zcrx.h b/io_uring/zcrx.h
index 566d519cbaf6..0df956cb9592 100644
--- a/io_uring/zcrx.h
+++ b/io_uring/zcrx.h
@@ -62,6 +62,7 @@ struct io_zcrx_ifq {
struct io_mapped_region region;
refcount_t refs;
+ struct io_zcrx_ifq *proxy;
};
#if defined(CONFIG_IO_URING_ZCRX)
--
2.47.3
Powered by blists - more mailing lists