Skip to content

Commit f7c9134

Browse files
committed
io_uring/rw: allow pollable non-blocking attempts for !FMODE_NOWAIT
The checking for whether or not io_uring can do a non-blocking read or write attempt is gated on FMODE_NOWAIT. However, if the file is pollable, it's feasible to just check if it's currently in a state in which it can sanely receive or send _some_ data. This avoids unnecessary io-wq punts, and repeated worthless retries before doing that punt, by assuming that some data can get delivered or received if poll tells us that is true. It also allows multishot reads to properly work with these types of files, enabling a bit of a cleanup of the logic that: c9d952b ("io_uring/rw: fix cflags posting for single issue multishot read") had to put in place. Signed-off-by: Jens Axboe <[email protected]>
1 parent c9d952b commit f7c9134

File tree

1 file changed

+16
-17
lines changed

1 file changed

+16
-17
lines changed

io_uring/rw.c

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,19 @@ struct io_rw {
3131
rwf_t flags;
3232
};
3333

34-
static inline bool io_file_supports_nowait(struct io_kiocb *req)
34+
static bool io_file_supports_nowait(struct io_kiocb *req, __poll_t mask)
3535
{
36-
return req->flags & REQ_F_SUPPORT_NOWAIT;
36+
/* If FMODE_NOWAIT is set for a file, we're golden */
37+
if (req->flags & REQ_F_SUPPORT_NOWAIT)
38+
return true;
39+
/* No FMODE_NOWAIT, if we can poll, check the status */
40+
if (io_file_can_poll(req)) {
41+
struct poll_table_struct pt = { ._key = mask };
42+
43+
return vfs_poll(req->file, &pt) & mask;
44+
}
45+
/* No FMODE_NOWAIT support, and file isn't pollable. Tough luck. */
46+
return false;
3747
}
3848

3949
#ifdef CONFIG_COMPAT
@@ -796,8 +806,8 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode, int rw_type)
796806
* supports async. Otherwise it's impossible to use O_NONBLOCK files
797807
* reliably. If not, or it IOCB_NOWAIT is set, don't retry.
798808
*/
799-
if ((kiocb->ki_flags & IOCB_NOWAIT) ||
800-
((file->f_flags & O_NONBLOCK) && !io_file_supports_nowait(req)))
809+
if (kiocb->ki_flags & IOCB_NOWAIT ||
810+
((file->f_flags & O_NONBLOCK && (req->flags & REQ_F_SUPPORT_NOWAIT))))
801811
req->flags |= REQ_F_NOWAIT;
802812

803813
if (ctx->flags & IORING_SETUP_IOPOLL) {
@@ -838,7 +848,7 @@ static int __io_read(struct io_kiocb *req, unsigned int issue_flags)
838848

839849
if (force_nonblock) {
840850
/* If the file doesn't support async, just async punt */
841-
if (unlikely(!io_file_supports_nowait(req)))
851+
if (unlikely(!io_file_supports_nowait(req, EPOLLIN)))
842852
return -EAGAIN;
843853
kiocb->ki_flags |= IOCB_NOWAIT;
844854
} else {
@@ -951,13 +961,6 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
951961

952962
ret = __io_read(req, issue_flags);
953963

954-
/*
955-
* If the file doesn't support proper NOWAIT, then disable multishot
956-
* and stay in single shot mode.
957-
*/
958-
if (!io_file_supports_nowait(req))
959-
req->flags &= ~REQ_F_APOLL_MULTISHOT;
960-
961964
/*
962965
* If we get -EAGAIN, recycle our buffer and just let normal poll
963966
* handling arm it.
@@ -984,9 +987,6 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
984987
* jump to the termination path. This request is then done.
985988
*/
986989
cflags = io_put_kbuf(req, ret, issue_flags);
987-
if (!(req->flags & REQ_F_APOLL_MULTISHOT))
988-
goto done;
989-
990990
rw->len = 0; /* similarly to above, reset len to 0 */
991991

992992
if (io_req_post_cqe(req, ret, cflags | IORING_CQE_F_MORE)) {
@@ -1007,7 +1007,6 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
10071007
* Either an error, or we've hit overflow posting the CQE. For any
10081008
* multishot request, hitting overflow will terminate it.
10091009
*/
1010-
done:
10111010
io_req_set_res(req, ret, cflags);
10121011
io_req_rw_cleanup(req, issue_flags);
10131012
if (issue_flags & IO_URING_F_MULTISHOT)
@@ -1031,7 +1030,7 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags)
10311030

10321031
if (force_nonblock) {
10331032
/* If the file doesn't support async, just async punt */
1034-
if (unlikely(!io_file_supports_nowait(req)))
1033+
if (unlikely(!io_file_supports_nowait(req, EPOLLOUT)))
10351034
goto ret_eagain;
10361035

10371036
/* Check if we can support NOWAIT. */

0 commit comments

Comments
 (0)