Skip to contentSkip to conversation

first zcrx updates for 7.2

PATCH Applied Pavel Begunkov 2 participants 19 messages May 19 – May 26

Subsystems (4)
lore
Share & tools
lore

Pavel Begunkov

author maintainer
#0 lore raw

cover first zcrx updates for 7.2

First batch of zcrx updates for 7.2. The main part is patches 5-8, which add notifications from zcrx to userspace via asynchronous CQE posting about events like allocation failures and copying, and statistics. It's accompanied by relevant query updates. Patches 1-4 are general cleanups.

Bertie Tryner (1):
io_uring/zcrx: reorder fd allocation in zcrx_export()

Clément Léger (2):
io_uring/zcrx: notify user on frag copy fallback io_uring/zcrx: add shared-memory notification statistics

Pavel Begunkov (5):
io_uring/zcrx: make scrubbing more reliable io_uring/zcrx: poison pointers on unregistration io_uring/zcrx: remove extra ifq close io_uring/zcrx: add ctx pointer to zcrx io_uring/zcrx: notify user when out of buffers

 include/uapi/linux/io_uring/query.h |  12 ++
 include/uapi/linux/io_uring/zcrx.h  |  36 ++++-
 io_uring/io_uring.c                 |   2 +-
 io_uring/io_uring.h                 |   1 +
 io_uring/query.c                    |  16 ++
 io_uring/zcrx.c                     | 227 ++++++++++++++++++++++++----
 io_uring/zcrx.h                     |  11 +-
 7 files changed, 274 insertions(+), 31 deletions(-)
Signature · 1 line
2.54.0
author maintainer
#1 lore raw

PATCH 1/8 io_uring/zcrx: make scrubbing more reliable

Currently, scrubbing is done once before killing all recvzc requests. It's fine as those are cancelled and don't return buffers afterwards, but it'll be more reliable not to rely that much on cancellations.

---
 io_uring/zcrx.c | 6 ++++++
 1 file changed, 6 insertions(+)
io_uring/zcrx.c +6 -0
index 7b93c87b8371..60cef10dc491 100644
@@ -986,6 +986,12 @@ void io_unregister_zcrx(struct io_ring_ctx *ctx)
 		}
 		if (!ifq)
 			break;
+		/*
+		 * io_uring can run requests and return buffers to the user
+		 * after termination, scrub it again.
+		 */
+		if (refcount_read(&ifq->user_refs) == 0)
+			io_zcrx_scrub(ifq);
 		io_put_zcrx_ifq(ifq);
 	}
 
Signature · 1 line
2.54.0
author maintainer
#2 lore raw

PATCH 2/8 io_uring/zcrx: poison pointers on unregistration

In reply to Pavel Begunkov

Nobody should be touching area and other pointers after zcrx destruction, poison them instead of zeroing.

---
 io_uring/zcrx.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)
io_uring/zcrx.c +5 -6
index 60cef10dc491..4bf6635c222f 100644
@@ -245,14 +245,13 @@ static void io_release_area_mem(struct io_zcrx_mem *mem)
 {
 	if (mem->is_dmabuf) {
 		io_release_dmabuf(mem);
-		return;
-	}
-	if (mem->pages) {
+	} else if (mem->pages) {
 		unpin_user_pages(mem->pages, mem->nr_folios);
 		sg_free_table(mem->sgt);
-		mem->sgt = NULL;
 		kvfree(mem->pages);
 	}
+	mem->pages = IO_URING_PTR_POISON;
+	mem->sgt = IO_URING_PTR_POISON;
 }
 
 static int io_import_area(struct io_zcrx_ifq *ifq,
@@ -403,8 +402,8 @@ static int io_allocate_rbuf_ring(struct io_ring_ctx *ctx,
 static void io_free_rbuf_ring(struct io_zcrx_ifq *ifq)
 {
 	io_free_region(ifq->user, &ifq->rq_region);
-	ifq->rq.ring = NULL;
-	ifq->rq.rqes = NULL;
+	ifq->rq.ring = IO_URING_PTR_POISON;
+	ifq->rq.rqes = IO_URING_PTR_POISON;
 }
 
 static void io_zcrx_free_area(struct io_zcrx_ifq *ifq,
Signature · 1 line
2.54.0
author maintainer
#3 lore raw

PATCH 3/8 io_uring/zcrx: remove extra ifq close

In reply to Pavel Begunkov

By the time io_zcrx_ifq_free() is called the interface queue should already be closed, so io_close_queue() will be a no-op. Remove the call and add a couple of warnings.

---
 io_uring/zcrx.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
io_uring/zcrx.c +4 -1
index 4bf6635c222f..f4440881960f 100644
@@ -575,7 +575,10 @@ static void io_close_queue(struct io_zcrx_ifq *ifq)
 
 static void io_zcrx_ifq_free(struct io_zcrx_ifq *ifq)
 {
-	io_close_queue(ifq);
+	if (WARN_ON_ONCE(ifq->if_rxq != -1))
+		return;
+	if (WARN_ON_ONCE(ifq->netdev != NULL))
+		return;
 
 	if (ifq->area)
 		io_zcrx_free_area(ifq, ifq->area);
Signature · 1 line
2.54.0
author maintainer
#4 lore raw

PATCH 4/8 io_uring/zcrx: reorder fd allocation in zcrx_export()

In reply to Pavel Begunkov

From: Bertie Tryner <[email protected]>

Currently, zcrx_export() allocates a file descriptor and copies the control structure to userspace before the backing file is created.

While the operation returns an error on failure, it is cleaner to follow the standard kernel pattern of performing the copy_to_user() and fd_install() only after all resource allocations (like the anon_inode) have succeeded. This aligns the code with other fd-publishing paths in the VFS.

---
 io_uring/zcrx.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)
io_uring/zcrx.c +14 -11
index f4440881960f..24a9ebbd9d8f 100644
@@ -699,19 +699,10 @@ static int zcrx_export(struct io_ring_ctx *ctx, struct io_zcrx_ifq *ifq,
 {
 	struct zcrx_ctrl_export *ce = &ctrl->zc_export;
 	struct file *file;
-	int fd = -1;
+	int fd;
 
 	if (!mem_is_zero(ce, sizeof(*ce)))
 		return -EINVAL;
-	fd = get_unused_fd_flags(O_CLOEXEC);
-	if (fd < 0)
-		return fd;
-
-	ce->zcrx_fd = fd;
-	if (copy_to_user(arg, ctrl, sizeof(*ctrl))) {
-		put_unused_fd(fd);
-		return -EFAULT;
-	}
 
 	refcount_inc(&ifq->refs);
 	refcount_inc(&ifq->user_refs);
@@ -719,11 +710,23 @@ static int zcrx_export(struct io_ring_ctx *ctx, struct io_zcrx_ifq *ifq,
 	file = anon_inode_create_getfile("[zcrx]", &zcrx_box_fops,
 					 ifq, O_CLOEXEC, NULL);
 	if (IS_ERR(file)) {
-		put_unused_fd(fd);
 		zcrx_unregister(ifq);
 		return PTR_ERR(file);
 	}
 
+	fd = get_unused_fd_flags(O_CLOEXEC);
+	if (fd < 0) {
+		fput(file);
+		return fd;
+	}
+
+	ce->zcrx_fd = fd;
+	if (copy_to_user(arg, ctrl, sizeof(*ctrl))) {
+		fput(file);
+		put_unused_fd(fd);
+		return -EFAULT;
+	}
+
 	fd_install(fd, file);
 	return 0;
 }
Signature · 1 line
2.54.0
author maintainer
#5 lore raw

PATCH 5/8 io_uring/zcrx: add ctx pointer to zcrx

In reply to Pavel Begunkov

zcrx will need to have a pointer to an owning ctx to communicate different events. Reference the ctx while it's attached to zcrx, and rely on zcrx termination to drop the ctx to avoid circular ref deps.

---
 io_uring/zcrx.c | 39 +++++++++++++++++++++++++++++++--------
 io_uring/zcrx.h |  3 +++
 2 files changed, 34 insertions(+), 8 deletions(-)
io_uring/zcrx.c +31 -8
index 24a9ebbd9d8f..2d8a0c453212 100644
@@ -44,6 +44,17 @@ static inline struct io_zcrx_area *io_zcrx_iov_to_area(const struct net_iov *nio
 	return container_of(owner, struct io_zcrx_area, nia);
 }
 
+static bool zcrx_set_ring_ctx(struct io_zcrx_ifq *zcrx,
+			      struct io_ring_ctx *ctx)
+{
+	guard(spinlock_bh)(&zcrx->ctx_lock);
+	if (zcrx->master_ctx)
+		return false;
+	percpu_ref_get(&ctx->refs);
+	zcrx->master_ctx = ctx;
+	return true;
+}
+
 static inline struct page *io_zcrx_iov_page(const struct net_iov *niov)
 {
 	struct io_zcrx_area *area = io_zcrx_iov_to_area(niov);
@@ -530,6 +541,7 @@ static struct io_zcrx_ifq *io_zcrx_ifq_alloc(struct io_ring_ctx *ctx)
 		return NULL;
 
 	ifq->if_rxq = -1;
+	spin_lock_init(&ifq->ctx_lock);
 	spin_lock_init(&ifq->rq.lock);
 	mutex_init(&ifq->pp_lock);
 	refcount_set(&ifq->refs, 1);
@@ -579,6 +591,8 @@ static void io_zcrx_ifq_free(struct io_zcrx_ifq *ifq)
 		return;
 	if (WARN_ON_ONCE(ifq->netdev != NULL))
 		return;
+	if (WARN_ON_ONCE(ifq->master_ctx))
+		return;
 
 	if (ifq->area)
 		io_zcrx_free_area(ifq, ifq->area);
@@ -655,17 +669,24 @@ static void io_zcrx_scrub(struct io_zcrx_ifq *ifq)
 	}
 }
 
-static void zcrx_unregister_user(struct io_zcrx_ifq *ifq)
+static void zcrx_unregister_user(struct io_zcrx_ifq *ifq, struct io_ring_ctx *ctx)
 {
+	scoped_guard(spinlock_bh, &ifq->ctx_lock) {
+		if (ctx && ifq->master_ctx == ctx) {
+			ifq->master_ctx = NULL;
+			percpu_ref_put(&ctx->refs);
+		}
+	}
+
 	if (refcount_dec_and_test(&ifq->user_refs)) {
 		io_close_queue(ifq);
 		io_zcrx_scrub(ifq);
 	}
 }
 
-static void zcrx_unregister(struct io_zcrx_ifq *ifq)
+static void zcrx_unregister(struct io_zcrx_ifq *ifq, struct io_ring_ctx *ctx)
 {
-	zcrx_unregister_user(ifq);
+	zcrx_unregister_user(ifq, ctx);
 	io_put_zcrx_ifq(ifq);
 }
 
@@ -685,7 +706,7 @@ static int zcrx_box_release(struct inode *inode, struct file *file)
 
 	if (WARN_ON_ONCE(!ifq))
 		return -EFAULT;
-	zcrx_unregister(ifq);
+	zcrx_unregister(ifq, NULL);
 	return 0;
 }
 
@@ -710,7 +731,7 @@ static int zcrx_export(struct io_ring_ctx *ctx, struct io_zcrx_ifq *ifq,
 	file = anon_inode_create_getfile("[zcrx]", &zcrx_box_fops,
 					 ifq, O_CLOEXEC, NULL);
 	if (IS_ERR(file)) {
-		zcrx_unregister(ifq);
+		zcrx_unregister(ifq, NULL);
 		return PTR_ERR(file);
 	}
 
@@ -786,7 +807,7 @@ static int import_zcrx(struct io_ring_ctx *ctx,
 	scoped_guard(mutex, &ctx->mmap_lock)
 		xa_erase(&ctx->zcrx_ctxs, id);
 err:
-	zcrx_unregister(ifq);
+	zcrx_unregister(ifq, ctx);
 	return ret;
 }
 
@@ -931,12 +952,14 @@ int io_register_zcrx(struct io_ring_ctx *ctx,
 		ret = -EFAULT;
 		goto err;
 	}
+
+	zcrx_set_ring_ctx(ifq, ctx);
 	return 0;
 err:
 	scoped_guard(mutex, &ctx->mmap_lock)
 		xa_erase(&ctx->zcrx_ctxs, id);
 ifq_free:
-	zcrx_unregister(ifq);
+	zcrx_unregister(ifq, ctx);
 	return ret;
 }
 
@@ -966,7 +989,7 @@ void io_terminate_zcrx(struct io_ring_ctx *ctx)
 			break;
 		set_zcrx_entry_mark(ctx, id);
 		id++;
-		zcrx_unregister_user(ifq);
+		zcrx_unregister_user(ifq, ctx);
 	}
 }
 
io_uring/zcrx.h +3 -0
index 75e0a4e6ef6e..76389a5dd50f 100644
@@ -72,6 +72,9 @@ struct io_zcrx_ifq {
 	 */
 	struct mutex			pp_lock;
 	struct io_mapped_region		rq_region;
+
+	spinlock_t			ctx_lock;
+	struct io_ring_ctx		*master_ctx;
 };
 
 #if defined(CONFIG_IO_URING_ZCRX)
Signature · 1 line
2.54.0
author maintainer
#6 lore raw

Re: [PATCH 5/8] io_uring/zcrx: add ctx pointer to zcrx

Quoted 5 lines · Pavel Begunkov

zcrx will need to have a pointer to an owning ctx to communicate different events. Reference the ctx while it's attached to zcrx, and rely on zcrx termination to drop the ctx to avoid circular ref deps.

Vish, can I have your sob for this and the next patches?

Quoted 1 line
Signature · 1 line
Pavel Begunkov
author maintainer
#7 lore raw

PATCH 6/8 io_uring/zcrx: notify user when out of buffers

In reply to Pavel Begunkov

There are currently no easy ways for the user to know if zcrx is out of buffers and page pool fails to allocate. Add uapi for zcrx to communicate it back.

It's implemented as a separate CQE, which for now is posted to the creator ctx. To use it, on registration the user space needs to pass an instance of struct zcrx_notification_desc, which tells the kernel the user_data for resulting CQEs and which event types are expected / allowed.

When an allowed event happens, zcrx will post a CQE containing the specified user_data, and lower bits of cqe->res will be set to the event mask. Before the kernel could post another notification of the given type, the user needs to acknowledge that it processed the previous one by issuing IORING_REGISTER_ZCRX_CTRL with ZCRX_CTRL_ARM_NOTIFICATION.

The only notification type the patch implements is ZCRX_NOTIF_NO_BUFFERS, but we'll need more of them in the future.

---
 include/uapi/linux/io_uring/zcrx.h | 24 ++++++++-
 io_uring/io_uring.c                |  2 +-
 io_uring/io_uring.h                |  1 +
 io_uring/zcrx.c                    | 86 +++++++++++++++++++++++++++++-
 io_uring/zcrx.h                    |  7 ++-
 5 files changed, 115 insertions(+), 5 deletions(-)
include/uapi/linux/io_uring/zcrx.h +23 -1
index 5ce02c7a6096..67185566ad3c 100644
@@ -65,6 +65,20 @@ enum zcrx_features {
 	 * value in struct io_uring_zcrx_ifq_reg::rx_buf_len.
 	 */
 	ZCRX_FEATURE_RX_PAGE_SIZE	= 1 << 0,
+	ZCRX_FEATURE_NOTIFICATION	= 1 << 1,
+};
+
+enum zcrx_notification_type {
+	ZCRX_NOTIF_NO_BUFFERS,
+
+	__ZCRX_NOTIF_TYPE_LAST,
+};
+
+struct zcrx_notification_desc {
+	__u64	user_data;
+	__u32	type_mask;
+	__u32	__resv1;
+	__u64	__resv2[10];
 };
 
 /*
@@ -82,12 +96,14 @@ struct io_uring_zcrx_ifq_reg {
 	struct io_uring_zcrx_offsets offsets;
 	__u32	zcrx_id;
 	__u32	rx_buf_len;
-	__u64	__resv[3];
+	__u64	notif_desc; /* see struct zcrx_notification_desc */
+	__u64	__resv[2];
 };
 
 enum zcrx_ctrl_op {
 	ZCRX_CTRL_FLUSH_RQ,
 	ZCRX_CTRL_EXPORT,
+	ZCRX_CTRL_ARM_NOTIFICATION,
 
 	__ZCRX_CTRL_LAST,
 };
@@ -101,6 +117,11 @@ struct zcrx_ctrl_export {
 	__u32 		__resv1[11];
 };
 
+struct zcrx_ctrl_arm_notif {
+	__u32		notif_type;
+	__u32		__resv[11];
+};
+
 struct zcrx_ctrl {
 	__u32	zcrx_id;
 	__u32	op; /* see enum zcrx_ctrl_op */
@@ -109,6 +130,7 @@ struct zcrx_ctrl {
 	union {
 		struct zcrx_ctrl_export		zc_export;
 		struct zcrx_ctrl_flush_rq	zc_flush;
+		struct zcrx_ctrl_arm_notif	zc_arm_notif;
 	};
 };
 
io_uring/io_uring.c +1 -1
index 2ebb0ba37c4f..c5972274cce1 100644
@@ -160,7 +160,7 @@ static void io_poison_cached_req(struct io_kiocb *req)
 	req->apoll = IO_URING_PTR_POISON;
 }
 
-static void io_poison_req(struct io_kiocb *req)
+void io_poison_req(struct io_kiocb *req)
 {
 	io_poison_cached_req(req);
 	req->async_data = IO_URING_PTR_POISON;
io_uring/io_uring.h +1 -0
index e612a66ee80e..de0a3bed58d1 100644
@@ -213,6 +213,7 @@ bool __io_alloc_req_refill(struct io_ring_ctx *ctx);
 
 void io_activate_pollwq(struct io_ring_ctx *ctx);
 void io_restriction_clone(struct io_restriction *dst, struct io_restriction *src);
+void io_poison_req(struct io_kiocb *req);
 
 static inline void io_lockdep_assert_cq_locked(struct io_ring_ctx *ctx)
 {
io_uring/zcrx.c +84 -2

145 lines not on this page · raw message

io_uring/zcrx.h +6 -1
index 76389a5dd50f..e8b7717d6adf 100644
@@ -9,7 +9,9 @@
 #include <net/net_trackers.h>
 
 #define ZCRX_SUPPORTED_REG_FLAGS	(ZCRX_REG_IMPORT | ZCRX_REG_NODEV)
-#define ZCRX_FEATURES			(ZCRX_FEATURE_RX_PAGE_SIZE)
+#define ZCRX_FEATURES			(ZCRX_FEATURE_RX_PAGE_SIZE |\
+					 ZCRX_FEATURE_NOTIFICATION)
+#define ZCRX_NOTIF_TYPE_MASK		(1U << ZCRX_NOTIF_NO_BUFFERS)
 
 struct io_zcrx_mem {
 	unsigned long			size;
@@ -75,6 +77,9 @@ struct io_zcrx_ifq {
 
 	spinlock_t			ctx_lock;
 	struct io_ring_ctx		*master_ctx;
+	u32				allowed_notif_mask;
+	u32				fired_notifs;
+	u64				notif_data;
 };
 
 #if defined(CONFIG_IO_URING_ZCRX)
Signature · 1 line
2.54.0
maintainer
#8 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

Quoted 23 lines · Pavel Begunkov
io_uring/zcrx.c +19 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
 	return allocated;
 }
 
+static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+	struct io_kiocb *req = tw_req.req;
+	struct io_ring_ctx *ctx = req->ctx;
+
+	io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+	percpu_ref_put(&ctx->refs);
+	io_poison_req(req);
+	kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+	gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+	u32 type_mask = 1 << type;
+	struct io_kiocb *req;
+
+	if (!(type_mask & ifq->allowed_notif_mask))
+		return;

io_uring/zcrx.c static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1173

Quoted 10 lines
io_uring/zcrx.c +10 -0
+
+	guard(spinlock_bh)(&ifq->ctx_lock);
+	if (!ifq->master_ctx)
+		return;
+	if (type_mask & ifq->fired_notifs)
+		return;
+
+	req = kmem_cache_alloc(req_cachep, gfp);
+	if (unlikely(!req))
+		return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

Maybe opportunistically check ->fired_notifs early? Might also avoid the lock in the first place if we get back-to-back of these.

Signature · 1 line
Jens Axboe
author maintainer
#9 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

Quoted 30 lines · Jens Axboe
Quoted 29 lines · Pavel Begunkov
io_uring/zcrx.c +25 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
  	return allocated;
  }
 
+static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+	struct io_kiocb *req = tw_req.req;
+	struct io_ring_ctx *ctx = req->ctx;
+
+	io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+	percpu_ref_put(&ctx->refs);
+	io_poison_req(req);
+	kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+	gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+	u32 type_mask = 1 << type;
+	struct io_kiocb *req;
+
+	if (!(type_mask & ifq->allowed_notif_mask))
+		return;
+
+	guard(spinlock_bh)(&ifq->ctx_lock);
+	if (!ifq->master_ctx)
+		return;
+	if (type_mask & ifq->fired_notifs)
+		return;
Quoted 8 lines

io_uring/zcrx.c static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1173

Quoted 4 lines
io_uring/zcrx.c +4 -0
+
+	req = kmem_cache_alloc(req_cachep, gfp);
+	if (unlikely(!req))
+		return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

I thought about it, but it's already bh, it'd need to do pre allocations + caching to be reliable, but that's left out for now.

Quoted 2 lines

Maybe opportunistically check ->fired_notifs early? Might also avoid the lock in the first place if we get back-to-back of these.

Slow path, doesn't matter

Signature · 1 line
Pavel Begunkov
maintainer
#10 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

Quoted 39 lines · Pavel Begunkov
Quoted 29 lines · Jens Axboe
Quoted 28 lines · Pavel Begunkov
io_uring/zcrx.c +24 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
       return allocated;
   }
   +static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+    struct io_kiocb *req = tw_req.req;
+    struct io_ring_ctx *ctx = req->ctx;
+
+    io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+    percpu_ref_put(&ctx->refs);
+    io_poison_req(req);
+    kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+    gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+    u32 type_mask = 1 << type;
+    struct io_kiocb *req;
+
+    if (!(type_mask & ifq->allowed_notif_mask))
+        return;
+
+    guard(spinlock_bh)(&ifq->ctx_lock);
+    if (!ifq->master_ctx)
+        return;
+    if (type_mask & ifq->fired_notifs)
+        return;
Quoted 8 lines

io_uring/zcrx.c static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1173

Quoted 4 lines
io_uring/zcrx.c +4 -0
+
+    req = kmem_cache_alloc(req_cachep, gfp);
+    if (unlikely(!req))
+        return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

Quoted 2 lines

I thought about it, but it's already bh, it'd need to do pre allocations + caching to be reliable, but that's left out for now.

Not sure I follow - GFP_KERNEL would be more reliable than GFP_ATOMIC. What's the contract in terms of the notification? If we fail the alloc, then userspace can't rely on the notification on the refill failure.

Are we under bh save already here, before doing it ourselves? If so, then how does the guard work?

Quoted 4 lines
Quoted 2 lines

Maybe opportunistically check ->fired_notifs early? Might also avoid the lock in the first place if we get back-to-back of these.

Slow path, doesn't matter

Agree, not a huge deal as we hope to not hit the notif path.

Signature · 1 line
Jens Axboe
author maintainer
#11 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

Quoted 43 lines · Jens Axboe
Quoted 39 lines · Pavel Begunkov
Quoted 29 lines · Jens Axboe
Quoted 28 lines · Pavel Begunkov
io_uring/zcrx.c +24 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
       return allocated;
   }
   +static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+    struct io_kiocb *req = tw_req.req;
+    struct io_ring_ctx *ctx = req->ctx;
+
+    io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+    percpu_ref_put(&ctx->refs);
+    io_poison_req(req);
+    kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+    gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+    u32 type_mask = 1 << type;
+    struct io_kiocb *req;
+
+    if (!(type_mask & ifq->allowed_notif_mask))
+        return;
+
+    guard(spinlock_bh)(&ifq->ctx_lock);
+    if (!ifq->master_ctx)
+        return;
+    if (type_mask & ifq->fired_notifs)
+        return;
Quoted 8 lines

io_uring/zcrx.c static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1173

Quoted 4 lines
io_uring/zcrx.c +4 -0
+
+    req = kmem_cache_alloc(req_cachep, gfp);
+    if (unlikely(!req))
+        return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

Quoted 2 lines

I thought about it, but it's already bh, it'd need to do pre allocations + caching to be reliable, but that's left out for now.

Quoted 6 lines

Not sure I follow - GFP_KERNEL would be more reliable than GFP_ATOMIC. What's the contract in terms of the notification? If we fail the alloc, then userspace can't rely on the notification on the refill failure.

Are we under bh save already here, before doing it ourselves? If so, then how does the guard work?

In 99% of cases it's called from softirq, not sure what you mean by how it works.

Signature · 1 line
Pavel Begunkov
maintainer
#12 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

Quoted 48 lines · Pavel Begunkov
Quoted 47 lines · Jens Axboe
Quoted 39 lines · Pavel Begunkov
Quoted 29 lines · Jens Axboe
Quoted 28 lines · Pavel Begunkov
io_uring/zcrx.c +24 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
       return allocated;
   }
   +static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+    struct io_kiocb *req = tw_req.req;
+    struct io_ring_ctx *ctx = req->ctx;
+
+    io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+    percpu_ref_put(&ctx->refs);
+    io_poison_req(req);
+    kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+    gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+    u32 type_mask = 1 << type;
+    struct io_kiocb *req;
+
+    if (!(type_mask & ifq->allowed_notif_mask))
+        return;
+
+    guard(spinlock_bh)(&ifq->ctx_lock);
+    if (!ifq->master_ctx)
+        return;
+    if (type_mask & ifq->fired_notifs)
+        return;
Quoted 8 lines

io_uring/zcrx.c static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1173

Quoted 4 lines
io_uring/zcrx.c +4 -0
+
+    req = kmem_cache_alloc(req_cachep, gfp);
+    if (unlikely(!req))
+        return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

Quoted 2 lines

I thought about it, but it's already bh, it'd need to do pre allocations + caching to be reliable, but that's left out for now.

Not sure I follow - GFP_KERNEL would be more reliable than GFP_ATOMIC. What's the contract in terms of the notification? If we fail the alloc, then userspace can't rely on the notification on the refill failure.

Quoted 5 lines
Quoted 2 lines

Are we under bh save already here, before doing it ourselves? If so, then how does the guard work?

In 99% of cases it's called from softirq, not sure what you mean by how it works.

Ah ok, I thought you meant it was already called with softirqs disabled. In which case the guard would seem broken, as we'd enable softirqs when exiting. But if we're just inside softirq yeah it's fine, and there's no point shuffling the allocation either.

Question on the contract still stands, in terms of missing a notification. I guess since it's a hint basically it doesn't really matter, just something that should be documented on the userspace side. Do you have test cases for these?

Signature · 1 line
Jens Axboe
author maintainer
#13 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

Quoted 52 lines · Jens Axboe
Quoted 51 lines · Pavel Begunkov
Quoted 49 lines · Jens Axboe
Quoted 39 lines · Pavel Begunkov
Quoted 29 lines · Jens Axboe
Quoted 28 lines · Pavel Begunkov
io_uring/zcrx.c +24 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
        return allocated;
    }
    +static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+    struct io_kiocb *req = tw_req.req;
+    struct io_ring_ctx *ctx = req->ctx;
+
+    io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+    percpu_ref_put(&ctx->refs);
+    io_poison_req(req);
+    kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+    gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+    u32 type_mask = 1 << type;
+    struct io_kiocb *req;
+
+    if (!(type_mask & ifq->allowed_notif_mask))
+        return;
+
+    guard(spinlock_bh)(&ifq->ctx_lock);
+    if (!ifq->master_ctx)
+        return;
+    if (type_mask & ifq->fired_notifs)
+        return;
Quoted 8 lines

io_uring/zcrx.c static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1173

Quoted 4 lines
io_uring/zcrx.c +4 -0
+
+    req = kmem_cache_alloc(req_cachep, gfp);
+    if (unlikely(!req))
+        return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

Quoted 2 lines

I thought about it, but it's already bh, it'd need to do pre allocations + caching to be reliable, but that's left out for now.

Not sure I follow - GFP_KERNEL would be more reliable than GFP_ATOMIC. What's the contract in terms of the notification? If we fail the alloc, then userspace can't rely on the notification on the refill failure.

Are we under bh save already here, before doing it ourselves? If so, then how does the guard work?

Quoted 7 lines
Quoted 2 lines

In 99% of cases it's called from softirq, not sure what you mean by how it works.

Ah ok, I thought you meant it was already called with softirqs disabled. In which case the guard would seem broken, as we'd enable softirqs when exiting. But if we're just inside softirq yeah it's fine, and there's no point shuffling the allocation either.

Softirqs are run with bh disabled, but bh_disable()/enable() are reenterable.

Quoted 3 lines

Question on the contract still stands, in terms of missing a notification. I guess since it's a hint basically it doesn't really matter, just something that should be documented on the userspace side.

Should rather be improved than documented, I'd say, but it's still better than not getting anything at all. And it's the only place where it can in theory be dropped, e.g. CQE overflow handling, though different GFP.

Quoted 1 line

Do you have test cases for these?

Clement needs to resend them. Actually, seems I forgot to CC Vish and Clement here, my bad.

Signature · 1 line
Pavel Begunkov
author maintainer
#14 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

Quoted 56 lines · Pavel Begunkov
Quoted 55 lines · Jens Axboe
Quoted 53 lines · Pavel Begunkov
Quoted 43 lines · Jens Axboe
Quoted 39 lines · Pavel Begunkov
Quoted 29 lines · Jens Axboe
Quoted 28 lines · Pavel Begunkov
(quoted diff) +24 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
         return allocated;
     }
     +static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+    struct io_kiocb *req = tw_req.req;
+    struct io_ring_ctx *ctx = req->ctx;
+
+    io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+    percpu_ref_put(&ctx->refs);
+    io_poison_req(req);
+    kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+    gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+    u32 type_mask = 1 << type;
+    struct io_kiocb *req;
+
+    if (!(type_mask & ifq->allowed_notif_mask))
+        return;
+
+    guard(spinlock_bh)(&ifq->ctx_lock);
+    if (!ifq->master_ctx)
+        return;
+    if (type_mask & ifq->fired_notifs)
+        return;
Quoted 8 lines

Review static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1172

Quoted 4 lines
(quoted diff) +4 -0
+
+    req = kmem_cache_alloc(req_cachep, gfp);
+    if (unlikely(!req))
+        return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

Quoted 2 lines

I thought about it, but it's already bh, it'd need to do pre allocations + caching to be reliable, but that's left out for now.

Quoted 6 lines

Not sure I follow - GFP_KERNEL would be more reliable than GFP_ATOMIC. What's the contract in terms of the notification? If we fail the alloc, then userspace can't rely on the notification on the refill failure.

Are we under bh save already here, before doing it ourselves? If so, then how does the guard work?

In 99% of cases it's called from softirq, not sure what you mean by how it works.

Quoted 7 lines
Quoted 4 lines

Ah ok, I thought you meant it was already called with softirqs disabled. In which case the guard would seem broken, as we'd enable softirqs when exiting. But if we're just inside softirq yeah it's fine, and there's no point shuffling the allocation either.

Softirqs are run with bh disabled, but bh_disable()/enable() are reenterable.

Better to say they're counting nesting

Quoted 14 lines
Quoted 3 lines

Question on the contract still stands, in terms of missing a notification. I guess since it's a hint basically it doesn't really matter, just something that should be documented on the userspace side.

Should rather be improved than documented, I'd say, but it's still better than not getting anything at all. And it's the only place where it can in theory be dropped, e.g. CQE overflow handling, though different GFP.

Quoted 1 line

Do you have test cases for these?

Clement needs to resend them. Actually, seems I forgot to CC Vish and Clement here, my bad.

Signature · 1 line
Pavel Begunkov
maintainer
#15 lore raw

Re: [PATCH 6/8] io_uring/zcrx: notify user when out of buffers

In reply to Pavel Begunkov
Quoted 56 lines · Pavel Begunkov
Quoted 55 lines · Jens Axboe
Quoted 53 lines · Pavel Begunkov
Quoted 43 lines · Jens Axboe
Quoted 39 lines · Pavel Begunkov
Quoted 29 lines · Jens Axboe
Quoted 28 lines · Pavel Begunkov
(quoted diff) +24 -0
@@ -1126,6 +1142,48 @@ static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if
        return allocated;
    }
    +static void zcrx_notif_tw(struct io_tw_req tw_req, io_tw_token_t tw)
+{
+    struct io_kiocb *req = tw_req.req;
+    struct io_ring_ctx *ctx = req->ctx;
+
+    io_post_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, 0);
+    percpu_ref_put(&ctx->refs);
+    io_poison_req(req);
+    kmem_cache_free(req_cachep, req);
+}
+
+static void zcrx_send_notif(struct io_zcrx_ifq *ifq, unsigned type)
+{
+    gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
+    u32 type_mask = 1 << type;
+    struct io_kiocb *req;
+
+    if (!(type_mask & ifq->allowed_notif_mask))
+        return;
+
+    guard(spinlock_bh)(&ifq->ctx_lock);
+    if (!ifq->master_ctx)
+        return;
+    if (type_mask & ifq->fired_notifs)
+        return;
Quoted 8 lines

Review static unsigned io_zcrx_refill_slow(struct page_pool *pp, struct io_zcrx_ifq *if · line 1172

Quoted 4 lines
(quoted diff) +4 -0
+
+    req = kmem_cache_alloc(req_cachep, gfp);
+    if (unlikely(!req))
+        return;

It'd be nice to avoid an allocation here inside ctx_lock and with bh's disabled, which looks like is also the only reason why GFP_ATOMIC is being used here.

Quoted 2 lines

I thought about it, but it's already bh, it'd need to do pre allocations + caching to be reliable, but that's left out for now.

Quoted 6 lines

Not sure I follow - GFP_KERNEL would be more reliable than GFP_ATOMIC. What's the contract in terms of the notification? If we fail the alloc, then userspace can't rely on the notification on the refill failure.

Are we under bh save already here, before doing it ourselves? If so, then how does the guard work?

In 99% of cases it's called from softirq, not sure what you mean by how it works.

Quoted 7 lines
Quoted 4 lines

Ah ok, I thought you meant it was already called with softirqs disabled. In which case the guard would seem broken, as we'd enable softirqs when exiting. But if we're just inside softirq yeah it's fine, and there's no point shuffling the allocation either.

Softirqs are run with bh disabled, but bh_disable()/enable() are reenterable.

No worries on that then.

Quoted 5 lines
Quoted 3 lines

Question on the contract still stands, in terms of missing a notification. I guess since it's a hint basically it doesn't really matter, just something that should be documented on the userspace side.

Should rather be improved than documented, I'd say, but it's still

Of course, that's why I was originally asking about what the contract is here - is it a hint, or is it more than that? In either case, should be documented what the application can rely on. And might not be too bad to harden, since it also really doesn't make sense to have more than one of these inflight at the time anyway.

Quoted 8 lines

better than not getting anything at all. And it's the only place where it can in theory be dropped, e.g. CQE overflow handling, though different GFP.

Quoted 1 line

Do you have test cases for these?

Clement needs to resend them. Actually, seems I forgot to CC Vish and Clement here, my bad.

Sounds good.

Signature · 1 line
Jens Axboe
author maintainer
#16 lore raw

PATCH 7/8 io_uring/zcrx: notify user on frag copy fallback

In reply to Pavel Begunkov

From: Clément Léger <[email protected]>

Add a ZCRX_NOTIF_COPY notification type to signal userspace when a received fragment could not be delivered using zero-copy and was instead copied into a buffer.

---
 include/uapi/linux/io_uring/zcrx.h | 1 +
 io_uring/zcrx.c                    | 7 ++++++-
 io_uring/zcrx.h                    | 2 +-
 3 files changed, 8 insertions(+), 2 deletions(-)
include/uapi/linux/io_uring/zcrx.h +1 -0
index 67185566ad3c..3f7b72b09878 100644
@@ -70,6 +70,7 @@ enum zcrx_features {
 
 enum zcrx_notification_type {
 	ZCRX_NOTIF_NO_BUFFERS,
+	ZCRX_NOTIF_COPY,
 
 	__ZCRX_NOTIF_TYPE_LAST,
 };
io_uring/zcrx.c +6 -1
index 455226790553..1e7c305da0d0 100644
@@ -1533,8 +1533,13 @@ static int io_zcrx_copy_frag(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
 			     const skb_frag_t *frag, int off, int len)
 {
 	struct page *page = skb_frag_page(frag);
+	int ret;
+
+	ret = io_zcrx_copy_chunk(req, ifq, page, off + skb_frag_off(frag), len);
+	if (ret > 0)
+		zcrx_send_notif(ifq, ZCRX_NOTIF_COPY);
 
-	return io_zcrx_copy_chunk(req, ifq, page, off + skb_frag_off(frag), len);
+	return ret;
 }
 
 static int io_zcrx_recv_frag(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
io_uring/zcrx.h +1 -1
index e8b7717d6adf..54d91b580eaf 100644
@@ -11,7 +11,7 @@
 #define ZCRX_SUPPORTED_REG_FLAGS	(ZCRX_REG_IMPORT | ZCRX_REG_NODEV)
 #define ZCRX_FEATURES			(ZCRX_FEATURE_RX_PAGE_SIZE |\
 					 ZCRX_FEATURE_NOTIFICATION)
-#define ZCRX_NOTIF_TYPE_MASK		(1U << ZCRX_NOTIF_NO_BUFFERS)
+#define ZCRX_NOTIF_TYPE_MASK		((1U << ZCRX_NOTIF_NO_BUFFERS) | (1U << ZCRX_NOTIF_COPY))
 
 struct io_zcrx_mem {
 	unsigned long			size;
Signature · 1 line
2.54.0
author maintainer
#17 lore raw

PATCH 8/8 io_uring/zcrx: add shared-memory notification statistics

In reply to Pavel Begunkov

From: Clément Léger <[email protected]>

Add support for an optional stats struct embedded in the refill queue region, allowing userspace to monitor copy-fallback in real-time.

Userspace queries the stats struct size and alignment via IO_URING_QUERY_ZCRX_NOTIF (notif_stats_size / notif_stats_alignment), then provides a stats_offset in zcrx_notification_desc pointing to a location within the refill queue region.

The kernel updates the stats counters in-place on every copy-fallback event.

[pavel: rename io_uring_zcrx_notif_stats]
---
 include/uapi/linux/io_uring/query.h | 12 +++++++
 include/uapi/linux/io_uring/zcrx.h  | 15 ++++++--
 io_uring/query.c                    | 16 +++++++++
 io_uring/zcrx.c                     | 54 +++++++++++++++++++++++++++--
 io_uring/zcrx.h                     |  1 +
 5 files changed, 94 insertions(+), 4 deletions(-)
include/uapi/linux/io_uring/query.h +12 -0
index 95500759cc13..1a68eca7c6b4 100644
@@ -23,6 +23,7 @@ enum {
 	IO_URING_QUERY_OPCODES			= 0,
 	IO_URING_QUERY_ZCRX			= 1,
 	IO_URING_QUERY_SCQ			= 2,
+	IO_URING_QUERY_ZCRX_NOTIF		= 3,
 
 	__IO_URING_QUERY_MAX,
 };
@@ -62,6 +63,17 @@ struct io_uring_query_zcrx {
 	__u64 __resv2;
 };
 
+struct io_uring_query_zcrx_notif {
+	/* Bitmask of supported ZCRX_NOTIF_* flags */
+	__u32 notif_flags;
+	/* Size of io_uring_zcrx_notif_stats */
+	__u32 notif_stats_size;
+	/* Required alignment for the stats struct within the region (ie stats_offset) */
+	__u32 notif_stats_off_alignment;
+	__u32 __resv1;
+	__u64 __resv2[4];
+};
+
 struct io_uring_query_scq {
 	/* The SQ/CQ rings header size */
 	__u64 hdr_size;
include/uapi/linux/io_uring/zcrx.h +13 -2
index 3f7b72b09878..15c05c45ce36 100644
@@ -75,11 +75,22 @@ enum zcrx_notification_type {
 	__ZCRX_NOTIF_TYPE_LAST,
 };
 
+enum zcrx_notification_desc_flags {
+	/* If set, stats_offset holds a valid offset to a notif_stats struct */
+	ZCRX_NOTIF_DESC_FLAG_STATS = 1 << 0,
+};
+
+struct zcrx_notif_stats {
+	__u64	copy_count;	/* cumulative copy-fallback CQEs */
+	__u64	copy_bytes;	/* cumulative bytes copied */
+};
+
 struct zcrx_notification_desc {
 	__u64	user_data;
 	__u32	type_mask;
-	__u32	__resv1;
-	__u64	__resv2[10];
+	__u32	flags; /* see enum zcrx_notification_desc_flags */
+	__u64	stats_offset; /* offset from the beginning of refill ring region for stats */
+	__u64	__resv2[9];
 };
 
 /*
io_uring/query.c +16 -0
index c1704d088374..d529d94aa8f4 100644
@@ -9,6 +9,7 @@
 union io_query_data {
 	struct io_uring_query_opcode opcodes;
 	struct io_uring_query_zcrx zcrx;
+	struct io_uring_query_zcrx_notif zcrx_notif;
 	struct io_uring_query_scq scq;
 };
 
@@ -44,6 +45,18 @@ static ssize_t io_query_zcrx(union io_query_data *data)
 	return sizeof(*e);
 }
 
+static ssize_t io_query_zcrx_notif(union io_query_data *data)
+{
+	struct io_uring_query_zcrx_notif *e = &data->zcrx_notif;
+
+	e->notif_flags = ZCRX_NOTIF_TYPE_MASK;
+	e->notif_stats_size = sizeof(struct zcrx_notif_stats);
+	e->notif_stats_off_alignment = __alignof__(struct zcrx_notif_stats);
+	e->__resv1 = 0;
+	memset(&e->__resv2, 0, sizeof(e->__resv2));
+	return sizeof(*e);
+}
+
 static ssize_t io_query_scq(union io_query_data *data)
 {
 	struct io_uring_query_scq *e = &data->scq;
@@ -83,6 +96,9 @@ static int io_handle_query_entry(union io_query_data *data, void __user *uhdr,
 	case IO_URING_QUERY_ZCRX:
 		ret = io_query_zcrx(data);
 		break;
+	case IO_URING_QUERY_ZCRX_NOTIF:
+		ret = io_query_zcrx_notif(data);
+		break;
 	case IO_URING_QUERY_SCQ:
 		ret = io_query_scq(data);
 		break;
io_uring/zcrx.c +52 -2

91 lines not on this page · raw message

io_uring/zcrx.h +1 -0
index 54d91b580eaf..fa00900e479e 100644
@@ -80,6 +80,7 @@ struct io_zcrx_ifq {
 	u32				allowed_notif_mask;
 	u32				fired_notifs;
 	u64				notif_data;
+	struct zcrx_notif_stats		*notif_stats;
 };
 
 #if defined(CONFIG_IO_URING_ZCRX)
Signature · 1 line
2.54.0
maintainer Applied
#18 lore raw
In reply to Pavel Begunkov
Quoted 10 lines · Pavel Begunkov

First batch of zcrx updates for 7.2. The main part is patches 5-8, which add notifications from zcrx to userspace via asynchronous CQE posting about events like allocation failures and copying, and statistics. It's accompanied by relevant query updates. Patches 1-4 are general cleanups.

Bertie Tryner (1):
io_uring/zcrx: reorder fd allocation in zcrx_export()

[...]

Applied, thanks!

[1/8] io_uring/zcrx: make scrubbing more reliable

      commit: 74fc9a9b50d43ed473ea2449682000da43e17175
[2/8] io_uring/zcrx: poison pointers on unregistration
      commit: e57b44039bc54bbdf3d1511021458356858a4a12
[3/8] io_uring/zcrx: remove extra ifq close
      commit: 98f07b0f74b65284ebe0d021505b461d4be6bf07
[4/8] io_uring/zcrx: reorder fd allocation in zcrx_export()
      commit: 84f7d0931c42cb0690615a431738cf6913d265f2
[5/8] io_uring/zcrx: add ctx pointer to zcrx
      commit: 8503f2de11f7fe78a7fdb87746255c8d02897279
[6/8] io_uring/zcrx: notify user when out of buffers
      commit: 0719e10d826aa0ba4840917d0261986eaead9a51
[7/8] io_uring/zcrx: notify user on frag copy fallback
      commit: 255180f7034f48aa5b0c8df70228307394bddbb9
[8/8] io_uring/zcrx: add shared-memory notification statistics
      commit: 6935f631465f5f60205978a59228a26db4723d51

Best regards,

Signature · 1 line
Jens Axboe