* [PATCH 1/3] io_uring/kbuf: flag request if buffer pool is empty after buffer pick
2024-02-27 18:51 [PATCHSET 0/3] Misc io_uring networking Jens Axboe
@ 2024-02-27 18:51 ` Jens Axboe
2024-02-27 18:51 ` [PATCH 2/3] io_uring/net: avoid redundant -ENOBUFS on recv multishot retry Jens Axboe
2024-02-27 18:51 ` [PATCH 3/3] io_uring/net: move recv/recvmsg flags out of retry loop Jens Axboe
2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2024-02-27 18:51 UTC (permalink / raw)
To: io-uring; +Cc: Jens Axboe
Normally we do an extra roundtrip for retries even if the buffer pool has
depleted, as we don't check that upfront. Rather than add this check, have
the buffer selection methods mark the request with REQ_F_BL_EMPTY if the
used buffer group is out of buffers after this selection. This is very
cheap to do once we're all the way inside there anyway, and it gives the
caller a chance to make better decisions on how to proceed.
For example, recv/recvmsg multishot could check this flag when it
decides whether to keep receiving or not.
Signed-off-by: Jens Axboe <[email protected]>
---
include/linux/io_uring_types.h | 3 +++
io_uring/kbuf.c | 10 ++++++++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h
index bd7071aeec5d..d8111d64812b 100644
--- a/include/linux/io_uring_types.h
+++ b/include/linux/io_uring_types.h
@@ -480,6 +480,7 @@ enum {
REQ_F_POLL_NO_LAZY_BIT,
REQ_F_CANCEL_SEQ_BIT,
REQ_F_CAN_POLL_BIT,
+ REQ_F_BL_EMPTY_BIT,
/* not a real bit, just to check we're not overflowing the space */
__REQ_F_LAST_BIT,
@@ -556,6 +557,8 @@ enum {
REQ_F_CANCEL_SEQ = IO_REQ_FLAG(REQ_F_CANCEL_SEQ_BIT),
/* file is pollable */
REQ_F_CAN_POLL = IO_REQ_FLAG(REQ_F_CAN_POLL_BIT),
+ /* buffer list was empty after selection of buffer */
+ REQ_F_BL_EMPTY = IO_REQ_FLAG(REQ_F_BL_EMPTY_BIT),
};
typedef void (*io_req_tw_func_t)(struct io_kiocb *req, struct io_tw_state *ts);
diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
index ee866d646997..3d257ed9031b 100644
--- a/io_uring/kbuf.c
+++ b/io_uring/kbuf.c
@@ -139,6 +139,8 @@ static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
list_del(&kbuf->list);
if (*len == 0 || *len > kbuf->len)
*len = kbuf->len;
+ if (list_empty(&bl->buf_list))
+ req->flags |= REQ_F_BL_EMPTY;
req->flags |= REQ_F_BUFFER_SELECTED;
req->kbuf = kbuf;
req->buf_index = kbuf->bid;
@@ -152,12 +154,16 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
unsigned int issue_flags)
{
struct io_uring_buf_ring *br = bl->buf_ring;
+ __u16 tail, head = bl->head;
struct io_uring_buf *buf;
- __u16 head = bl->head;
- if (unlikely(smp_load_acquire(&br->tail) == head))
+ tail = smp_load_acquire(&br->tail);
+ if (unlikely(tail == head))
return NULL;
+ if (head + 1 == tail)
+ req->flags |= REQ_F_BL_EMPTY;
+
head &= bl->mask;
/* mmaped buffers are always contig */
if (bl->is_mmap || head < IO_BUFFER_LIST_BUF_PER_PAGE) {
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/3] io_uring/net: avoid redundant -ENOBUFS on recv multishot retry
2024-02-27 18:51 [PATCHSET 0/3] Misc io_uring networking Jens Axboe
2024-02-27 18:51 ` [PATCH 1/3] io_uring/kbuf: flag request if buffer pool is empty after buffer pick Jens Axboe
@ 2024-02-27 18:51 ` Jens Axboe
2024-02-27 18:51 ` [PATCH 3/3] io_uring/net: move recv/recvmsg flags out of retry loop Jens Axboe
2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2024-02-27 18:51 UTC (permalink / raw)
To: io-uring; +Cc: Jens Axboe
Now that we know if the buffer list is empty upfront, there's no point
doing a retry for that case. This can help avoid a redundant -ENOBUFS
which would terminate the multishot receive, requiring the app to
re-arm it.
Signed-off-by: Jens Axboe <[email protected]>
---
io_uring/net.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/io_uring/net.c b/io_uring/net.c
index 9fe2a11f3554..ef91a1af6ba6 100644
--- a/io_uring/net.c
+++ b/io_uring/net.c
@@ -716,6 +716,11 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
int mshot_retry_ret = IOU_ISSUE_SKIP_COMPLETE;
io_recv_prep_retry(req);
+
+ /* buffer list now empty, no point trying again */
+ if (req->flags & REQ_F_BL_EMPTY)
+ goto enobufs;
+
/* Known not-empty or unknown state, retry */
if (cflags & IORING_CQE_F_SOCK_NONEMPTY || msg->msg_inq == -1) {
if (sr->nr_multishot_loops++ < MULTISHOT_MAX_RETRY)
@@ -724,6 +729,7 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
sr->nr_multishot_loops = 0;
mshot_retry_ret = IOU_REQUEUE;
}
+enobufs:
if (issue_flags & IO_URING_F_MULTISHOT)
*ret = mshot_retry_ret;
else
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/3] io_uring/net: move recv/recvmsg flags out of retry loop
2024-02-27 18:51 [PATCHSET 0/3] Misc io_uring networking Jens Axboe
2024-02-27 18:51 ` [PATCH 1/3] io_uring/kbuf: flag request if buffer pool is empty after buffer pick Jens Axboe
2024-02-27 18:51 ` [PATCH 2/3] io_uring/net: avoid redundant -ENOBUFS on recv multishot retry Jens Axboe
@ 2024-02-27 18:51 ` Jens Axboe
2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2024-02-27 18:51 UTC (permalink / raw)
To: io-uring; +Cc: Jens Axboe
The flags don't change, just intialize them once rather than every loop
for multishot.
Signed-off-by: Jens Axboe <[email protected]>
---
io_uring/net.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/io_uring/net.c b/io_uring/net.c
index ef91a1af6ba6..926d1fb0335d 100644
--- a/io_uring/net.c
+++ b/io_uring/net.c
@@ -861,6 +861,10 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
if (!io_check_multishot(req, issue_flags))
return io_setup_async_msg(req, kmsg, issue_flags);
+ flags = sr->msg_flags;
+ if (force_nonblock)
+ flags |= MSG_DONTWAIT;
+
retry_multishot:
if (io_do_buffer_select(req)) {
void __user *buf;
@@ -881,10 +885,6 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
iov_iter_ubuf(&kmsg->msg.msg_iter, ITER_DEST, buf, len);
}
- flags = sr->msg_flags;
- if (force_nonblock)
- flags |= MSG_DONTWAIT;
-
kmsg->msg.msg_get_inq = 1;
kmsg->msg.msg_inq = -1;
if (req->flags & REQ_F_APOLL_MULTISHOT) {
@@ -970,6 +970,10 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
msg.msg_iocb = NULL;
msg.msg_ubuf = NULL;
+ flags = sr->msg_flags;
+ if (force_nonblock)
+ flags |= MSG_DONTWAIT;
+
retry_multishot:
if (io_do_buffer_select(req)) {
void __user *buf;
@@ -988,9 +992,6 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
msg.msg_inq = -1;
msg.msg_flags = 0;
- flags = sr->msg_flags;
- if (force_nonblock)
- flags |= MSG_DONTWAIT;
if (flags & MSG_WAITALL)
min_ret = iov_iter_count(&msg.msg_iter);
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread