Skip to content

Commit c79f52f

Browse files
committed
io_uring/rw: ensure poll based multishot read retries appropriately
io_read_mshot() always relies on poll triggering retries, and this works fine as long as we do a retry per size of the buffer being read. The buffer size is given by the size of the buffer(s) in the given buffer group ID. But if we're reading less than what is available, then we don't always get to read everything that is available. For example, if the buffers available are 32 bytes and we have 64 bytes to read, then we'll correctly read the first 32 bytes and then wait for another poll trigger before we attempt the next read. This next poll trigger may never happen, in which case we just sit forever and never make progress, or it may trigger at some point in the future, and now we're just delivering the available data much later than we should have. io_read_mshot() could do retries itself, but that is wasteful as we'll be going through all of __io_read() again, and most likely in vain. Rather than do that, bump our poll reference count and have io_poll_check_events() do one more loop and check with vfs_poll() if we have more data to read. If we do, io_read_mshot() will get invoked again directly and we'll read the next chunk. io_poll_multishot_retry() must only get called from inside io_poll_issue(), which is our multishot retry handler, as we know we already "own" the request at this point. Cc: stable@vger.kernel.org Link: axboe/liburing#1041 Fixes: fc68fcd ("io_uring/rw: add support for IORING_OP_READ_MULTISHOT") Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 16bae3e commit c79f52f

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

io_uring/poll.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ struct async_poll {
2424
struct io_poll *double_poll;
2525
};
2626

27+
/*
28+
* Must only be called inside issue_flags & IO_URING_F_MULTISHOT, or
29+
* potentially other cases where we already "own" this poll request.
30+
*/
31+
static inline void io_poll_multishot_retry(struct io_kiocb *req)
32+
{
33+
atomic_inc(&req->poll_refs);
34+
}
35+
2736
int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
2837
int io_poll_add(struct io_kiocb *req, unsigned int issue_flags);
2938

io_uring/rw.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "opdef.h"
1919
#include "kbuf.h"
2020
#include "rsrc.h"
21+
#include "poll.h"
2122
#include "rw.h"
2223

2324
struct io_rw {
@@ -962,8 +963,15 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
962963
if (io_fill_cqe_req_aux(req,
963964
issue_flags & IO_URING_F_COMPLETE_DEFER,
964965
ret, cflags | IORING_CQE_F_MORE)) {
965-
if (issue_flags & IO_URING_F_MULTISHOT)
966+
if (issue_flags & IO_URING_F_MULTISHOT) {
967+
/*
968+
* Force retry, as we might have more data to
969+
* be read and otherwise it won't get retried
970+
* until (if ever) another poll is triggered.
971+
*/
972+
io_poll_multishot_retry(req);
966973
return IOU_ISSUE_SKIP_COMPLETE;
974+
}
967975
return -EAGAIN;
968976
}
969977
}

0 commit comments

Comments
 (0)