2022-05-25 19:31:09 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
|
|
enum {
|
|
|
|
IO_APOLL_OK,
|
|
|
|
IO_APOLL_ABORTED,
|
|
|
|
IO_APOLL_READY
|
|
|
|
};
|
|
|
|
|
|
|
|
struct io_poll {
|
|
|
|
struct file *file;
|
|
|
|
struct wait_queue_head *head;
|
|
|
|
__poll_t events;
|
io_uring/poll: allow some retries for poll triggering spuriously
If we get woken spuriously when polling and fail the operation with
-EAGAIN again, then we generally only allow polling again if data
had been transferred at some point. This is indicated with
REQ_F_PARTIAL_IO. However, if the spurious poll triggers when the socket
was originally empty, then we haven't transferred data yet and we will
fail the poll re-arm. This either punts the socket to io-wq if it's
blocking, or it fails the request with -EAGAIN if not. Neither condition
is desirable, as the former will slow things down, while the latter
will make the application confused.
We want to ensure that a repeated poll trigger doesn't lead to infinite
work making no progress, that's what the REQ_F_PARTIAL_IO check was
for. But it doesn't protect against a loop post the first receive, and
it's unnecessarily strict if we started out with an empty socket.
Add a somewhat random retry count, just to put an upper limit on the
potential number of retries that will be done. This should be high enough
that we won't really hit it in practice, unless something needs to be
aborted anyway.
Cc: stable@vger.kernel.org # v5.10+
Link: https://github.com/axboe/liburing/issues/364
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2023-02-25 12:53:53 -07:00
|
|
|
int retries;
|
2022-05-25 19:31:09 -07:00
|
|
|
struct wait_queue_entry wait;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct async_poll {
|
2024-03-20 14:19:44 -07:00
|
|
|
struct io_poll poll;
|
2022-05-25 19:31:09 -07:00
|
|
|
struct io_poll *double_poll;
|
|
|
|
};
|
|
|
|
|
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: https://github.com/axboe/liburing/issues/1041
Fixes: fc68fcda0491 ("io_uring/rw: add support for IORING_OP_READ_MULTISHOT")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2024-01-27 13:44:58 -07:00
|
|
|
/*
|
|
|
|
* Must only be called inside issue_flags & IO_URING_F_MULTISHOT, or
|
|
|
|
* potentially other cases where we already "own" this poll request.
|
|
|
|
*/
|
|
|
|
static inline void io_poll_multishot_retry(struct io_kiocb *req)
|
|
|
|
{
|
|
|
|
atomic_inc(&req->poll_refs);
|
|
|
|
}
|
|
|
|
|
2022-05-25 19:31:09 -07:00
|
|
|
int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
|
|
|
int io_poll_add(struct io_kiocb *req, unsigned int issue_flags);
|
|
|
|
|
|
|
|
int io_poll_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
|
|
|
int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags);
|
|
|
|
|
2022-06-18 18:44:33 -07:00
|
|
|
struct io_cancel_data;
|
2022-06-16 02:22:11 -07:00
|
|
|
int io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
|
|
|
|
unsigned issue_flags);
|
2022-05-25 19:31:09 -07:00
|
|
|
int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags);
|
|
|
|
bool io_poll_remove_all(struct io_ring_ctx *ctx, struct task_struct *tsk,
|
|
|
|
bool cancel_all);
|
2022-07-07 10:18:33 -07:00
|
|
|
|
2023-06-02 07:41:46 -07:00
|
|
|
void io_poll_task_func(struct io_kiocb *req, struct io_tw_state *ts);
|