Commit febb985c authored by Jens Axboe's avatar Jens Axboe
Browse files

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: 49f1c68e ("io_uring: optimise submission side poll_refs")
Reported-and-tested-by: default avatar <syzbot+6c95df01470a47fc3af4@syzkaller.appspotmail.com>
Link: https://lore.kernel.org/io-uring/0000000000009f829805f1ce87b2@google.com/


Suggested-by: default avatarPavel Begunkov <asml.silence@gmail.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent e6db6f93
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -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)) {