mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
io_uring/poll: don't loop on HUP with multiple references
io_poll_check_events() drops down to one reference when a multishot
request sees HUP with more than one, so that the loop goes around once
more. It did so by subtracting one less than it had. With the cmpxchg
that only takes the local count down: the exchange fails, the next pass
reads the unchanged count, and goes through the same motions again. The
loop then only ends once io_poll_issue() stops the request.
Drop the extra references from the counter instead, and loop once more
without trying the exchange. The next pass sees one reference, like it
did before, and ends unless a wake up came in.
Fixes: 937d38dcac ("io_uring/poll: avoid retry wakeup loss when dropping ownership")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
89f193dc3e
commit
67bb1ad9a5
|
|
@ -241,12 +241,14 @@ static inline void io_poll_execute(struct io_kiocb *req, int res,
|
|||
*/
|
||||
static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)
|
||||
{
|
||||
bool again;
|
||||
int v;
|
||||
|
||||
if (unlikely(tw.cancel))
|
||||
return -ECANCELED;
|
||||
|
||||
do {
|
||||
again = false;
|
||||
v = atomic_read(&req->poll_refs);
|
||||
|
||||
if (unlikely(v != 1)) {
|
||||
|
|
@ -310,9 +312,15 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)
|
|||
} else {
|
||||
int ret;
|
||||
|
||||
/* multiple refs and HUP, ensure we loop once more */
|
||||
if ((req->cqe.res & (POLLHUP | POLLRDHUP)) && v != 1)
|
||||
v--;
|
||||
/*
|
||||
* Multiple refs and HUP, ensure we loop once more. Drop
|
||||
* down to one ref now, so the next pass ends unless a
|
||||
* wake up came in.
|
||||
*/
|
||||
if ((req->cqe.res & (POLLHUP | POLLRDHUP)) && v != 1) {
|
||||
atomic_sub(v - 1, &req->poll_refs);
|
||||
again = true;
|
||||
}
|
||||
|
||||
ret = io_poll_issue(req, tw);
|
||||
if (ret == IOU_COMPLETE)
|
||||
|
|
@ -331,7 +339,7 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)
|
|||
* task_work while we were executing it.
|
||||
*/
|
||||
v &= IO_POLL_REF_MASK;
|
||||
} while (atomic_cmpxchg(&req->poll_refs, v, 0) != v);
|
||||
} while (again || atomic_cmpxchg(&req->poll_refs, v, 0) != v);
|
||||
|
||||
io_napi_add(req);
|
||||
return IOU_POLL_NO_ACTION;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user