diff options
author | Jens Axboe <axboe@kernel.dk> | 2023-01-09 14:46:10 -0700 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2023-01-09 15:46:57 -0700 |
commit | febb985c06cb6f5fac63598c0bffd4fd823d110d (patch) | |
tree | 16968444e582cd87e6d3a0bb95839f9f7f6132f4 /io_uring | |
parent | e6db6f9398dadcbc06318a133d4c44a2d3844e61 (diff) | |
download | lwn-febb985c06cb6f5fac63598c0bffd4fd823d110d.tar.gz lwn-febb985c06cb6f5fac63598c0bffd4fd823d110d.zip |
io_uring/poll: add hash if ready poll request can't complete inline
If we don't, then we may lose access to it completely, leading to a
request leak. This will eventually stall the ring exit process as
well.
Cc: stable@vger.kernel.org
Fixes: 49f1c68e048f ("io_uring: optimise submission side poll_refs")
Reported-and-tested-by: syzbot+6c95df01470a47fc3af4@syzkaller.appspotmail.com
Link: https://lore.kernel.org/io-uring/0000000000009f829805f1ce87b2@google.com/
Suggested-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'io_uring')
-rw-r--r-- | io_uring/poll.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/io_uring/poll.c b/io_uring/poll.c index ee7da6150ec4..cf6a70bd54e0 100644 --- a/io_uring/poll.c +++ b/io_uring/poll.c @@ -533,6 +533,14 @@ static bool io_poll_can_finish_inline(struct io_kiocb *req, return pt->owning || io_poll_get_ownership(req); } +static void io_poll_add_hash(struct io_kiocb *req) +{ + if (req->flags & REQ_F_HASH_LOCKED) + io_poll_req_insert_locked(req); + else + io_poll_req_insert(req); +} + /* * Returns 0 when it's handed over for polling. The caller owns the requests if * it returns non-zero, but otherwise should not touch it. Negative values @@ -591,18 +599,17 @@ static int __io_arm_poll_handler(struct io_kiocb *req, if (mask && ((poll->events & (EPOLLET|EPOLLONESHOT)) == (EPOLLET|EPOLLONESHOT))) { - if (!io_poll_can_finish_inline(req, ipt)) + if (!io_poll_can_finish_inline(req, ipt)) { + io_poll_add_hash(req); return 0; + } io_poll_remove_entries(req); ipt->result_mask = mask; /* no one else has access to the req, forget about the ref */ return 1; } - if (req->flags & REQ_F_HASH_LOCKED) - io_poll_req_insert_locked(req); - else - io_poll_req_insert(req); + io_poll_add_hash(req); if (mask && (poll->events & EPOLLET) && io_poll_can_finish_inline(req, ipt)) { |