Re: [PATCH 5.10 491/491] io_uring/poll: correctly handle io_poll_add() return value on update

Jens Axboe
2026-05-01T23:27:30Z

[-- Attachment #1: Type: text/plain, Size: 695 bytes --]

On 5/1/26 4:29 PM, Jens Axboe wrote:
> On 5/1/26 4:26 PM, Fedor Pchelkin wrote:
>>> @@ -6188,7 +6184,7 @@ static int io_poll_update(struct io_kiocb *req, unsigned int issue_flags)
>>> preq->result = ret2;
>>>
>>> }
>>> - if (preq->result < 0)
>>> + if (ret2 < 0)
>>> req_set_fail(preq);
>>> io_req_complete(preq, preq->result);
>>> out:
>>
>> I'm really uncomfortable to raise this but - ret2 should be initialized in
>> beginning of the function io_poll_update().
>
> It's your second version... I'll send out a new set.

OK, here's the new set for both 5.10-stable and 5.15-stable. Ran it through the
usual testing.

Let's hope we can put this one to bed now :-)

--
Jens Axboe

[-- Attachment #2: 0001-io_uring-poll-fix-EPOLL_URING_WAKE-sometimes-not-bei.patch --]
[-- Type: text/x-patch, Size: 1810 bytes --]

From 38ebae3b93403e03d2e6a44afd2d980cce49db8c Mon Sep 17 00:00:00 2001
From: Jens Axboe <axboe@kernel.dk>
Date: Tue, 21 Apr 2026 16:41:32 -0600
Subject: [PATCH 1/2] io_uring/poll: fix EPOLL_URING_WAKE sometimes not being
honored

Rather than do the masking only when we jump straight to execution,
mark it as EPOLLONESHOT regardless. This ensures it doesn't get lost.
And just kill the poll entry upfront, if marked. This is an optimization
in later kernels, but it's actually required on the older kernels to
note the EPOLL_URING_WAKE mask correctly.

Fixes: ccf06b5a981c ("io_uring: pass in EPOLL_URING_WAKE for eventfd signaling and wakeups")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
io_uring/io_uring.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 38decfc1a914..4f1dda7d68c2 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -5794,14 +5794,19 @@ static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
if (mask && !(mask & poll->events))
return 0;

+ /*
+ * If we trigger a multishot poll off our own wakeup path,
+ * disable multishot as there is a circular dependency between
+ * CQ posting and triggering the event.
+ */
+ if (mask & EPOLL_URING_WAKE)
+ poll->events |= EPOLLONESHOT;
+
if (io_poll_get_ownership(req)) {
- /*
- * If we trigger a multishot poll off our own wakeup path,
- * disable multishot as there is a circular dependency between
- * CQ posting and triggering the event.
- */
- if (mask & EPOLL_URING_WAKE)
- poll->events |= EPOLLONESHOT;
+ if (mask && poll->events & EPOLLONESHOT) {
+ list_del_init(&poll->wait.entry);
+ smp_store_release(&poll->head, NULL);
+ }

__io_poll_execute(req, mask);
}
--
2.53.0

[-- Attachment #3: 0002-io_uring-poll-fix-backport-of-io_poll_add-changes.patch --]
[-- Type: text/x-patch, Size: 1859 bytes --]

From 1a074b61239613231b0d6cb68a33b001ca8e46ce Mon Sep 17 00:00:00 2001
From: Jens Axboe <axboe@kernel.dk>
Date: Tue, 21 Apr 2026 16:44:06 -0600
Subject: [PATCH 2/2] io_uring/poll: fix backport of io_poll_add() changes

The 5.15/5.10 backport of 84230ad2d2af had a few issues, due to the
older poll base. Notably return value handling __io_arm_poll_handler()
and in return __io_poll_add() as well. Fix them up.

Reported-by: Ben Hutchings <ben@decadent.org.uk>
Fixes: 349ef5d2e7bf ("io_uring/poll: correctly handle io_poll_add() return value on update")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
io_uring/io_uring.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 4f1dda7d68c2..cb54ebda0a8a 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -6144,26 +6144,22 @@ static int __io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
if (!ret && ipt.error)
req_set_fail(req);
ret = ret ?: ipt.error;
- if (ret > 0) {
+ if (ret)
__io_req_complete(req, issue_flags, ret, 0);
- return ret;
- }
- return 0;
+ return ret;
}

static int io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
{
- int ret;
-
- ret = __io_poll_add(req, issue_flags);
- return ret < 0 ? ret : 0;
+ __io_poll_add(req, issue_flags);
+ return 0;
}

static int io_poll_update(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_ring_ctx *ctx = req->ctx;
struct io_kiocb *preq;
- int ret2, ret = 0;
+ int ret2 = -ECANCELED, ret = 0;

io_ring_submit_lock(ctx, !(issue_flags & IO_URING_F_NONBLOCK));

@@ -6194,7 +6190,7 @@ static int io_poll_update(struct io_kiocb *req, unsigned int issue_flags)
preq->result = ret2;

}
- if (preq->result < 0)
+ if (ret2 < 0)
req_set_fail(preq);
io_req_complete(preq, preq->result);
out:
--
2.53.0