io_uring for-6.19 zcrx updates
Subsystems (4)
Pavel Begunkov
maintainercover io_uring for-6.19 zcrx updates
Note: it depends on the 6.18-rc5 patch that removed sync refilling.
Zcrx updates for 6.19. It includes a bunch of small patches, IORING_REGISTER_ZCRX_CTRL and RQ flushing (Patches 4-5) and David's work on sharing zcrx b/w multiple io_uring instances.
David Wei (3):
io_uring/zcrx: move io_zcrx_scrub() and dependencies up io_uring/zcrx: add io_fill_zcrx_offsets() io_uring/zcrx: share an ifq between rings
Pavel Begunkov (6):
io_uring/zcrx: convert to use netmem_desc io_uring/zcrx: elide passing msg flags io_uring/zcrx: introduce IORING_REGISTER_ZCRX_CTRL io_uring/zcrx: add sync refill queue flushing io_uring/zcrx: count zcrx users io_uring/zcrx: export zcrx via a file
Pedro Demarchi Gomes (1):
io_uring/zcrx: use folio_nr_pages() instead of shift operation
include/uapi/linux/io_uring.h | 34 ++++ io_uring/net.c | 7 +- io_uring/register.c | 3 + io_uring/zcrx.c | 326 ++++++++++++++++++++++++++++------ io_uring/zcrx.h | 8 + 5 files changed, 317 insertions(+), 61 deletions(-)
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 1/10 io_uring/zcrx: convert to use netmem_desc
Convert zcrx to struct netmem_desc, and use struct net_iov::desc to access its fields instead of struct net_iov inner union alises. zcrx only directly reads niov->pp, so with this patch it doesn't depend on the union anymore.
--- io_uring/zcrx.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
io_uring/zcrx.c +7 -5
@@ -696,12 +696,12 @@ static void io_zcrx_return_niov(struct net_iov *niov) {netmem_ref netmem =net_iov_to_netmem (niov); -if (!niov->pp) { +if (!niov->desc.pp) {/* copy fallback allocated niovs */ io_zcrx_return_niov_freelist (niov);return ; } -page_pool_put_unrefed_netmem (niov->pp, netmem,-1 , false); +page_pool_put_unrefed_netmem (niov->desc.pp, netmem,-1 , false); }static void io_zcrx_scrub (struct io_zcrx_ifq *ifq)
@@ -815,7 +815,7 @@ static void io_zcrx_ring_refill(struct page_pool *pp,if (!page_pool_unref_and_test (netmem))continue ; -if (unlikely (niov->pp != pp)) { +if (unlikely (niov->desc.pp != pp)) {io_zcrx_return_niov (niov);continue ; }
@@ -1082,13 +1082,15 @@ static int io_zcrx_recv_frag(struct io_kiocb *req, struct io_zcrx_ifq *ifq, const skb_frag_t *frag, int off, int len) { struct net_iov *niov; +struct page_pool *pp;if (unlikely (!skb_frag_is_net_iov (frag)))return io_zcrx_copy_frag (req, ifq, frag, off, len); niov =netmem_to_net_iov (frag->netmem); -if (!niov->pp || niov->pp->mp_ops != &io_uring_pp_zc_ops || -io_pp_to_ifq (niov->pp) != ifq) + pp = niov->desc.pp; + +if (!pp || pp->mp_ops != &io_uring_pp_zc_ops ||io_pp_to_ifq (pp) != ifq)return -EFAULT ;if (!io_zcrx_queue_cqe (req, niov, ifq, off +skb_frag_off (frag), len))
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 2/10 io_uring/zcrx: use folio_nr_pages() instead of shift operation
In reply to Pavel BegunkovFrom: Pedro Demarchi Gomes <[email protected]>
folio_nr_pages() is a faster helper function to get the number of pages when NR_PAGES_IN_LARGE_FOLIO is enabled.
--- io_uring/zcrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
io_uring/zcrx.c +1 -1
@@ -170,7 +170,7 @@ static unsigned long io_count_account_pages(struct page **pages, unsigned nr_pagif (folio == last_folio)continue ; last_folio = folio; - res +=1UL <<folio_order (folio); + res +=folio_nr_pages (folio); }return res; }
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 3/10 io_uring/zcrx: elide passing msg flags
In reply to Pavel Begunkovzcrx sqe->msg_flags has never been defined and checked to be zero. It doesn't need to be a MSG_* bitmask. Keep them undefined, don't mix with MSG_DONTWAIT, and don't pass into io_zcrx_recv() as it's ignored anyway.
--- io_uring/net.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
io_uring/net.c +2 -5
@@ -110,7 +110,6 @@ enum sr_retry_flags {struct io_recvzc {struct file *file; -unsigned msg_flags;u16 flags;u32 len;struct io_zcrx_ifq *ifq;
@@ -1262,8 +1261,7 @@ int io_recvzc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) zc->len =READ_ONCE (sqe->len); zc->flags =READ_ONCE (sqe->ioprio); - zc->msg_flags =READ_ONCE (sqe->msg_flags); -if (zc->msg_flags) +if (READ_ONCE (sqe->msg_flags))return -EINVAL ;if (zc->flags & ~(IORING_RECVSEND_POLL_FIRST |IORING_RECV_MULTISHOT ))return -EINVAL ;
@@ -1292,8 +1290,7 @@ int io_recvzc(struct io_kiocb *req, unsigned int issue_flags)return -ENOTSOCK ; len = zc->len; - ret =io_zcrx_recv (req, zc->ifq, sock, zc->msg_flags |MSG_DONTWAIT , - issue_flags, &zc->len); + ret =io_zcrx_recv (req, zc->ifq, sock,0 , issue_flags, &zc->len);if (len && zc->len ==0 ) {io_req_set_res (req,0 ,0 );
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 4/10 io_uring/zcrx: introduce IORING_REGISTER_ZCRX_CTRL
In reply to Pavel BegunkovIt'll be annoying and take enough of boilerplate code to implement new zcrx features as separate io_uring register opcode. Introduce IORING_REGISTER_ZCRX_CTRL that will multiplex such calls to zcrx. Note, there are no real users of the opcode in this patch.
--- include/uapi/linux/io_uring.h | 13 +++++++++++++ io_uring/register.c | 3 +++ io_uring/zcrx.c | 21 +++++++++++++++++++++ io_uring/zcrx.h | 6 ++++++ 4 files changed, 43 insertions(+)
include/uapi/linux/io_uring.h +13 -0
@@ -701,6 +701,9 @@ enum io_uring_register_op {/* query various aspects of io_uring, see linux/io_uring/query.h */ IORING_REGISTER_QUERY =35 , +/* auxiliary zcrx configuration, see enum zcrx_ctrl_op */ +IORING_REGISTER_ZCRX_CTRL =36 , +/* this goes last */ IORING_REGISTER_LAST,
@@ -1082,6 +1085,16 @@ struct io_uring_zcrx_ifq_reg {__u64 __resv[3 ]; }; +enum zcrx_ctrl_op { + __ZCRX_CTRL_LAST, +}; + +struct zcrx_ctrl { +__u32 zcrx_id; +__u32 op;/* see enum zcrx_ctrl_op */ +__u64 __resv[8 ]; +}; + #ifdef __cplusplus }#endif
io_uring/register.c +3 -0
@@ -826,6 +826,9 @@ static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,case IORING_REGISTER_QUERY : ret =io_query (ctx, arg, nr_args);break ; +case IORING_REGISTER_ZCRX_CTRL : + ret =io_zcrx_ctrl (ctx, arg, nr_args); +break ;default : ret = -EINVAL ;break ;
io_uring/zcrx.c +21 -0
@@ -941,6 +941,27 @@ static const struct memory_provider_ops io_uring_pp_zc_ops = { .uninstall = io_pp_uninstall, }; +int io_zcrx_ctrl (struct io_ring_ctx *ctx,void __user *arg,unsigned nr_args) +{ +struct zcrx_ctrl ctrl; +struct io_zcrx_ifq *zcrx; + +if (nr_args) +return -EINVAL ; +if (copy_from_user (&ctrl, arg,sizeof (ctrl))) +return -EFAULT ; +if (!mem_is_zero (&ctrl.__resv,sizeof (ctrl.__resv))) +return -EFAULT ; + + zcrx =xa_load (&ctx->zcrx_ctxs, ctrl.zcrx_id); +if (!zcrx) +return -ENXIO ; +if (ctrl.op >= __ZCRX_CTRL_LAST) +return -EOPNOTSUPP ; + +return -EINVAL ; +} +static bool io_zcrx_queue_cqe (struct io_kiocb *req,struct net_iov *niov,struct io_zcrx_ifq *ifq,int off,int len) {
io_uring/zcrx.h +6 -0
@@ -65,6 +65,7 @@ struct io_zcrx_ifq { };#if defined(CONFIG_IO_URING_ZCRX ) +int io_zcrx_ctrl (struct io_ring_ctx *ctx,void __user *arg,unsigned nr_arg);int io_register_zcrx_ifq (struct io_ring_ctx *ctx,struct io_uring_zcrx_ifq_reg __user *arg);void io_unregister_zcrx_ifqs (struct io_ring_ctx *ctx);
@@ -93,6 +94,11 @@ static inline struct io_mapped_region *io_zcrx_get_region(struct io_ring_ctx *ct {return NULL ; } +static inline int io_zcrx_ctrl (struct io_ring_ctx *ctx, +void __user *arg,unsigned nr_arg) +{ +return -EOPNOTSUPP ; +}#endif int io_recvzc (struct io_kiocb *req,unsigned int issue_flags);
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 5/10 io_uring/zcrx: add sync refill queue flushing
In reply to Pavel BegunkovAdd an zcrx interface via IORING_REGISTER_ZCRX_CTRL that forces the kernel to flush / consume entries from the refill queue. Just as with the IORING_REGISTER_ZCRX_REFILL attempt, the motivation is to address cases where the refill queue becomes full, and the user can't return buffers and needs to stash them. It's still a slow path, and the user should size refill queue appropriately, but it should be helpful for handling temporary traffic spikes and other unpredictable conditions.
The interface is simpler comparing to ZCRX_REFILL as it doesn't need temporary refill entry arrays and gives natural batching, whereas ZCRX_REFILL requires even more user logic to be somewhat efficient.
Also, add a structure for the operation. It's not currently used but can serve for future improvements like limiting the number of buffers to process, etc.
--- include/uapi/linux/io_uring.h | 10 ++++- io_uring/zcrx.c | 74 +++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 4 deletions(-)
include/uapi/linux/io_uring.h +9 -1
@@ -1086,13 +1086,21 @@ struct io_uring_zcrx_ifq_reg { };enum zcrx_ctrl_op { +ZCRX_CTRL_FLUSH_RQ , + __ZCRX_CTRL_LAST, }; +struct zcrx_ctrl_flush_rq { +__u64 __resv[6 ]; +}; +struct zcrx_ctrl {__u32 zcrx_id;__u32 op;/* see enum zcrx_ctrl_op */ -__u64 __resv[8 ]; +__u64 __resv[2 ]; + +struct zcrx_ctrl_flush_rq zc_flush; };#ifdef __cplusplus
io_uring/zcrx.c +71 -3
87 lines not on this page · raw message
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 6/10 io_uring/zcrx: count zcrx users
In reply to Pavel Begunkovzcrx tries to detach ifq / terminate page pools when the io_uring ctx owning it is being destroyed. There will be multiple io_uring instances attached to it in the future, so add a separate counter to track the users. Note, refs can't be reused for this purpose as it only used to prevent zcrx and rings destruction, and also used by page pools to keep it alive.
--- io_uring/zcrx.c | 7 +++++-- io_uring/zcrx.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-)
io_uring/zcrx.c +5 -2
@@ -482,6 +482,7 @@ static struct io_zcrx_ifq *io_zcrx_ifq_alloc(struct io_ring_ctx *ctx)spin_lock_init (&ifq->rq_lock);mutex_init (&ifq->pp_lock);refcount_set (&ifq->refs,1 ); +refcount_set (&ifq->user_refs,1 );return ifq; }
@@ -742,8 +743,10 @@ void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx)if (!ifq)break ; -io_close_queue (ifq); -io_zcrx_scrub (ifq); +if (refcount_dec_and_test (&ifq->user_refs)) { +io_close_queue (ifq); +io_zcrx_scrub (ifq); + }io_put_zcrx_ifq (ifq); }
io_uring/zcrx.h +2 -0
@@ -55,6 +55,8 @@ struct io_zcrx_ifq {struct net_device *netdev;netdevice_tracker netdev_tracker;refcount_t refs; +/* counts userspace facing users like io_uring */ +refcount_t user_refs;/* * Page pool and net configuration lock, can be taken deeper in the
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 7/10 io_uring/zcrx: move io_zcrx_scrub() and dependencies up
In reply to Pavel BegunkovFrom: David Wei <[email protected]>
In preparation for adding zcrx ifq exporting and importing, move io_zcrx_scrub() and its dependencies up the file to be closer to io_close_queue().
--- io_uring/zcrx.c | 84 ++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-)
io_uring/zcrx.c +42 -42
@@ -544,6 +544,48 @@ static void io_put_zcrx_ifq(struct io_zcrx_ifq *ifq)io_zcrx_ifq_free (ifq); } +static void io_zcrx_return_niov_freelist (struct net_iov *niov) +{ +struct io_zcrx_area *area =io_zcrx_iov_to_area (niov); + +spin_lock_bh (&area->freelist_lock); + area->freelist[area->free_count++] =net_iov_idx (niov); +spin_unlock_bh (&area->freelist_lock); +} + +static void io_zcrx_return_niov (struct net_iov *niov) +{ +netmem_ref netmem =net_iov_to_netmem (niov); + +if (!niov->desc.pp) { +/* copy fallback allocated niovs */ +io_zcrx_return_niov_freelist (niov); +return ; + } +page_pool_put_unrefed_netmem (niov->desc.pp, netmem,-1 , false); +} + +static void io_zcrx_scrub (struct io_zcrx_ifq *ifq) +{ +struct io_zcrx_area *area = ifq->area; +int i; + +if (!area) +return ; + +/* Reclaim back all buffers given to the user space. */ +for (i =0 ; i < area->nia.num_niovs; i++) { +struct net_iov *niov = &area->nia.niovs[i]; +int nr; + +if (!atomic_read (io_get_user_counter (niov))) +continue ; + nr =atomic_xchg (io_get_user_counter (niov),0 ); +if (nr && !page_pool_unref_netmem (net_iov_to_netmem (niov), nr)) +io_zcrx_return_niov (niov); + } +} +struct io_mapped_region *io_zcrx_get_region (struct io_ring_ctx *ctx,unsigned int id) {
@@ -684,48 +726,6 @@ static struct net_iov *__io_zcrx_get_free_niov(struct io_zcrx_area *area)return &area->nia.niovs[niov_idx]; } -static void io_zcrx_return_niov_freelist (struct net_iov *niov) -{ -struct io_zcrx_area *area =io_zcrx_iov_to_area (niov); - -spin_lock_bh (&area->freelist_lock); - area->freelist[area->free_count++] =net_iov_idx (niov); -spin_unlock_bh (&area->freelist_lock); -} - -static void io_zcrx_return_niov (struct net_iov *niov) -{ -netmem_ref netmem =net_iov_to_netmem (niov); - -if (!niov->desc.pp) { -/* copy fallback allocated niovs */ -io_zcrx_return_niov_freelist (niov); -return ; - } -page_pool_put_unrefed_netmem (niov->desc.pp, netmem,-1 , false); -} - -static void io_zcrx_scrub (struct io_zcrx_ifq *ifq) -{ -struct io_zcrx_area *area = ifq->area; -int i; - -if (!area) -return ; - -/* Reclaim back all buffers given to the user space. */ -for (i =0 ; i < area->nia.num_niovs; i++) { -struct net_iov *niov = &area->nia.niovs[i]; -int nr; - -if (!atomic_read (io_get_user_counter (niov))) -continue ; - nr =atomic_xchg (io_get_user_counter (niov),0 ); -if (nr && !page_pool_unref_netmem (net_iov_to_netmem (niov), nr)) -io_zcrx_return_niov (niov); - } -} -void io_unregister_zcrx_ifqs (struct io_ring_ctx *ctx) {struct io_zcrx_ifq *ifq;
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 8/10 io_uring/zcrx: export zcrx via a file
In reply to Pavel BegunkovAdd an option to wrap a zcrx instance into a file and expose it to the user space. Currently, users can't do anything meaningful with the file, but it'll be used in a next patch to import it into another io_uring instance. It's implemented as a new op called ZCRX_CTRL_EXPORT for the IORING_REGISTER_ZCRX_CTRL registration opcode.
--- include/uapi/linux/io_uring.h | 11 +++++- io_uring/zcrx.c | 68 +++++++++++++++++++++++++++++++---- 2 files changed, 72 insertions(+), 7 deletions(-)
include/uapi/linux/io_uring.h +10 -1
@@ -1087,6 +1087,7 @@ struct io_uring_zcrx_ifq_reg {enum zcrx_ctrl_op {ZCRX_CTRL_FLUSH_RQ , +ZCRX_CTRL_EXPORT , __ZCRX_CTRL_LAST, };
@@ -1095,12 +1096,20 @@ struct zcrx_ctrl_flush_rq {__u64 __resv[6 ]; }; +struct zcrx_ctrl_export { +__u32 zcrx_fd; +__u32 __resv1[11 ]; +}; +struct zcrx_ctrl {__u32 zcrx_id;__u32 op;/* see enum zcrx_ctrl_op */ __u64 __resv[2 ]; -struct zcrx_ctrl_flush_rq zc_flush; +union { +struct zcrx_ctrl_export zc_export; +struct zcrx_ctrl_flush_rq zc_flush; + }; };#ifdef __cplusplus
io_uring/zcrx.c +62 -6
98 lines not on this page · raw message
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 9/10 io_uring/zcrx: add io_fill_zcrx_offsets()
In reply to Pavel BegunkovFrom: David Wei <[email protected]>
Add a helper io_fill_zcrx_offsets() that sets the constant offsets in struct io_uring_zcrx_offsets returned to userspace.
--- io_uring/zcrx.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
io_uring/zcrx.c +9 -4
@@ -345,6 +345,13 @@ static void io_zcrx_get_niov_uref(struct net_iov *niov)atomic_inc (io_get_user_counter (niov)); } +static void io_fill_zcrx_offsets (struct io_uring_zcrx_offsets *offsets) +{ + offsets->head = offsetof(struct io_uring , head); + offsets->tail = offsetof(struct io_uring , tail); + offsets->rqes =ALIGN (sizeof (struct io_uring ),L1_CACHE_BYTES ); +} + static int io_allocate_rbuf_ring(struct io_ring_ctx *ctx, struct io_zcrx_ifq *ifq, struct io_uring_zcrx_ifq_reg *reg,
@@ -356,7 +363,8 @@ static int io_allocate_rbuf_ring(struct io_ring_ctx *ctx,void *ptr;int ret; - off =ALIGN (sizeof (struct io_uring ),L1_CACHE_BYTES ); +io_fill_zcrx_offsets (®->offsets); + off = reg->offsets.rqes; size = off +sizeof (struct io_uring_zcrx_rqe ) * reg->rq_entries;if (size > rd->size)return -EINVAL ;
@@ -372,9 +380,6 @@ static int io_allocate_rbuf_ring(struct io_ring_ctx *ctx, ifq->rq_ring = (struct io_uring *)ptr; ifq->rqes = (struct io_uring_zcrx_rqe *)(ptr + off); - reg->offsets.head = offsetof(struct io_uring , head); - reg->offsets.tail = offsetof(struct io_uring , tail); - reg->offsets.rqes = off;return 0 ; }
Signature · 1 line
2.49.0
Pavel Begunkov
maintainerPATCH 10/10 io_uring/zcrx: share an ifq between rings
In reply to Pavel BegunkovFrom: David Wei <[email protected]>
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_IMPORT in the registration struct io_uring_zcrx_ifq_reg, alongside the fd of an exported zcrx ifq.
--- include/uapi/linux/io_uring.h | 4 +++ io_uring/zcrx.c | 63 +++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-)
include/uapi/linux/io_uring.h +4 -0
@@ -1067,6 +1067,10 @@ struct io_uring_zcrx_area_reg {__u64 __resv2[2 ]; }; +enum zcrx_reg_flags { +ZCRX_REG_IMPORT =1 , +}; +/* * Argument for IORING_REGISTER_ZCRX_IFQ */
io_uring/zcrx.c +61 -2
78 lines not on this page · raw message
Signature · 1 line
2.49.0
Quoted 6 lines · Pavel Begunkov
Note: it depends on the 6.18-rc5 patch that removed sync refilling.
Zcrx updates for 6.19. It includes a bunch of small patches,
IORING_REGISTER_ZCRX_CTRLand RQ flushing (Patches 4-5) and David's work on sharing zcrx b/w multipleio_uringinstances.
Quoted 6 lines
David Wei (3):
io_uring/zcrx: moveio_zcrx_scrub()and dependencies upio_uring/zcrx: addio_fill_zcrx_offsets()io_uring/zcrx: share an ifq between rings[...]
Applied, thanks!
[01/10] io_uring/zcrx: convert to use netmem_desc
commit: f0243d2b86b97a575a7a013370e934f70ee77dd3
[02/10] io_uring/zcrx: use folio_nr_pages() instead of shift operation
commit: a0169c3a62875d1bafa0caffa42e1d1cf6aa40e6
[03/10] io_uring/zcrx: elide passing msg flags
commit: 1b8b5d0316da7468ae4d40f6c2102d559d9e3ca2
[04/10] io_uring/zcrx: introduce IORING_REGISTER_ZCRX_CTRL
commit: d663976dad68de9b2e3df59cc31f0a24ee4c4511
[05/10] io_uring/zcrx: add sync refill queue flushing
commit: 475eb39b00478b1898bc9080344dcd8e86c53c7a
[06/10] io_uring/zcrx: count zcrx users
commit: 39c9676f789eb71ce1005a22eebe2be80a00de6a
[07/10] io_uring/zcrx: move io_zcrx_scrub() and dependencies up
commit: 742cb2e14ecb059cd4a77b92aa4945c20f85d414
[08/10] io_uring/zcrx: export zcrx via a file
commit: d7af80b213e5675664b14f12240cb282e81773d5
[09/10] io_uring/zcrx: add io_fill_zcrx_offsets()
commit: 0926f94ab36a6d76d07fa8f0934e65f5f66647ec
[10/10] io_uring/zcrx: share an ifq between rings
commit: 00d91481279fb2df8c46d19090578afd523ca630Best regards,
Signature · 1 line
Jens Axboe