Thread (12 messages) 12 messages, 2 authors, 2025-10-28

Re: [PATCH v3 3/3] io_uring/zcrx: share an ifq between rings

From: Pavel Begunkov <asml.silence@gmail.com>
Date: 2025-10-28 15:22:17
Also in: io-uring

On 10/28/25 14:55, David Wei wrote:
On 2025-10-27 03:20, Pavel Begunkov wrote:
quoted
On 10/26/25 17:34, David Wei wrote:
quoted
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_SHARE in the registration struct
io_uring_zcrx_ifq_reg, alongside the fd of the src ring and the ifq id
to be shared.

To prevent the src ring or ifq from being cleaned up or freed while
there are still shared ifqs, take the appropriate refs on the src ring
(ctx->refs) and src ifq (ifq->refs).

Signed-off-by: David Wei <redacted>
---
  include/uapi/linux/io_uring.h |  4 ++
  io_uring/zcrx.c               | 74 ++++++++++++++++++++++++++++++++++-
  2 files changed, 76 insertions(+), 2 deletions(-)
diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
index 569cc0338acb..7418c959390a 100644
--- a/io_uring/zcrx.c
+++ b/io_uring/zcrx.c
[...]
quoted
quoted
@@ -541,6 +541,67 @@ struct io_mapped_region *io_zcrx_get_region(struct io_ring_ctx *ctx,
      return ifq ? &ifq->region : NULL;
  }
+static int io_share_zcrx_ifq(struct io_ring_ctx *ctx,
+                 struct io_uring_zcrx_ifq_reg __user *arg,
+                 struct io_uring_zcrx_ifq_reg *reg)
+{
+    struct io_ring_ctx *src_ctx;
+    struct io_zcrx_ifq *src_ifq;
+    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)
+        goto err_unlock;
+
+    percpu_ref_get(&src_ctx->refs);
+    refcount_inc(&src_ifq->refs);
+
+    scoped_guard(mutex, &ctx->mmap_lock) {
+        ret = xa_alloc(&ctx->zcrx_ctxs, &id, NULL, xa_limit_31b, GFP_KERNEL);
+        if (ret)
+            goto err_unlock;
+
+        ret = -ENOMEM;
+        if (xa_store(&ctx->zcrx_ctxs, id, src_ifq, GFP_KERNEL)) {
+            xa_erase(&ctx->zcrx_ctxs, id);
+            goto err_unlock;
+        }
It's just xa_alloc(..., src_ifq, ...);
quoted
+    }
+
+    reg->zcrx_id = id;
+    if (copy_to_user(arg, reg, sizeof(*reg))) {
+        ret = -EFAULT;
+        goto err;
+    }
Better to do that before publishing zcrx into ctx->zcrx_ctxs
I can only do one of the two suggestions above. No valid id until
xa_alloc() returns, so I either split xa_alloc()/xa_store() with
copy_to_user() in between, or I do a single xa_alloc() and
copy_to_user() after.
Makes sense, I'd do splitting then, at least this way it's
not exposing it to the user space for a brief moment.

-- 
Pavel Begunkov
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help