6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Josef Bacik Commit 83cce67298ab1f4d2e9205a49f56975475cdb154 upstream. When the min wait time is over and there is work to run, which for DEFER_TASKRUN includes task_work that was queued lazily and didn't wake the waiter, io_cqring_min_timer_wakeup() ends the wait via io_cqring_timer_wakeup(). That flags it as timed out. io_cqring_wait() runs the work, leaves the loop, and returns 0 if the CQ ring holds something. Running task_work doesn't have to result in a CQE, though. A poll wake up can turn out to be spurious, for instance if somebody else has read the data by the time the request is retried. The application then gets -ETIME once the min wait time has passed, no matter how far away the timeout it asked for is. Wake the task without declaring a timeout. From now on a single CQE satisfies the wait, like in the case where the timer is switched over to the normal timeout. If running the work doesn't post one, the loop in io_cqring_wait() goes back to sleep with the normal timeout. [ 6.12: io_cqring_min_timer_wakeup() is in io_uring.c ] Fixes: 1100c4a2656d ("io_uring: add support for batch wait timeout") Assisted-by: LLM Signed-off-by: Josef Bacik Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-32-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe Co-Authored-By: Claude Fable 5.1 Signed-off-by: Greg Kroah-Hartman --- io_uring/io_uring.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -2435,9 +2435,16 @@ static enum hrtimer_restart io_cqring_mi if (iowq->timeout == KTIME_MAX || ktime_compare(iowq->min_timeout, iowq->timeout) >= 0) goto out_wake; - /* work we may need to run, wake function will see if we need to wake */ - if (io_has_work(ctx)) - goto out_wake; + /* + * Work we need to run. It isn't known if that is going to post a CQE, + * so this isn't a timeout. Carry on with the normal one if it doesn't. + */ + if (io_has_work(ctx)) { + iowq->min_timeout = 0; + iowq->cq_tail = iowq->cq_min_tail + 1; + wake_up_process(iowq->wq.private); + return HRTIMER_NORESTART; + } /* got events since we started waiting, min timeout is done */ if (iowq->cq_min_tail != READ_ONCE(ctx->rings->cq.tail)) goto out_wake;