Linux kernel -stable discussions
 help / color / mirror / Atom feed
From: Jens Axboe <axboe@kernel.dk>
To: stable@vger.kernel.org
Subject: [PATCH 7.3.y 06/16] io_uring: keep the drain active when a deferred drain request is started
Date: Wed,  4 Nov 2026 11:44:37 -0700	[thread overview]
Message-ID: <20261104184447.516768-7-axboe@kernel.dk> (raw)
In-Reply-To: <20261104184447.516768-1-axboe@kernel.dk>

Commit 2295613cd3713beffc8665e956135a5d48dfc208 upstream.

ecb6817b769f ends the drain when the dispatched drain request has posted
its CQE and nothing else is deferred. But the deferred list is processed
in between, and if the request it starts is itself a drain request, the
drain is over before that one has even run. A request submitted after
that point then runs ahead of it:

  1. P0 in flight, D1 and D2 (both IOSQE_IO_DRAIN) deferred behind it
  2. P0 completes, D1 is started
  3. D1 completes, drain_done is set, D2 is started, the list is empty
  4. IO_RING_F_DRAIN_ACTIVE is cleared with D2 still in flight

Anything submitted now bypasses the drain. The same happens with D2 as
the head of a link, as those aren't tracked in ->drain_req at all.

Have io_queue_deferred() report whether it started a drain request, and
don't end the drain if it did. Starting non-drain requests and ending it
is still fine, they were only waiting on the drain request that just
completed.

Fixes: ecb6817b769f ("io_uring: end the drain when the drain request completes")
Reported-by: Karl Mehltretter <kmehltretter@gmail.com>
Link: https://lore.kernel.org/io-uring/20261027043323.98916-1-kmehltretter@gmail.com/
Cc: stable@vger.kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
 io_uring/io_uring.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 3d715536df72..dd6ad02d0e89 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -474,9 +474,9 @@ unsigned io_linked_nr(struct io_kiocb *req)
 	return nr;
 }
 
-static __cold noinline void io_queue_deferred(struct io_ring_ctx *ctx)
+static __cold noinline bool io_queue_deferred(struct io_ring_ctx *ctx)
 {
-	bool drain_seen = false, first = true;
+	bool drain_seen = false, first = true, drain_queued = false;
 
 	lockdep_assert_held(&ctx->uring_lock);
 	__io_req_caches_free(ctx);
@@ -490,17 +490,21 @@ static __cold noinline void io_queue_deferred(struct io_ring_ctx *ctx)
 
 		drain_seen |= de->req->flags & REQ_F_IO_DRAIN;
 		if ((drain_seen || first) && ctx->nr_req_allocated != ctx->nr_drained)
-			return;
+			return drain_queued;
 
 		list_del_init(&de->list);
 		ctx->nr_drained -= io_linked_nr(de->req);
-		/* it runs alone, track its completion unless it's a link */
-		if ((de->req->flags & REQ_F_IO_DRAIN) && !de->req->link)
-			ctx->drain_req = de->req;
+		if (de->req->flags & REQ_F_IO_DRAIN) {
+			drain_queued = true;
+			/* it runs alone, track its completion unless it's a link */
+			if (!de->req->link)
+				ctx->drain_req = de->req;
+		}
 		io_req_task_queue(de->req);
 		kfree(de);
 		first = false;
 	}
+	return drain_queued;
 }
 
 void __io_commit_cqring_flush(struct io_ring_ctx *ctx)
@@ -1227,7 +1231,9 @@ void __io_submit_flush_completions(struct io_ring_ctx *ctx)
 	}
 
 	if (unlikely(ctx->int_flags & IO_RING_F_DRAIN_ACTIVE)) {
-		io_queue_deferred(ctx);
+		/* a drain request started from the list keeps the drain going */
+		if (io_queue_deferred(ctx))
+			drain_done = false;
 		if (drain_done && list_empty(&ctx->defer_list))
 			ctx->int_flags &= ~IO_RING_F_DRAIN_ACTIVE;
 	}
-- 
2.56.0


  parent reply	other threads:[~2026-11-04 18:45 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 18:44 [PATCH 7.3.y 00/16] io_uring fixes for 7.3-stable Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 01/16] io_uring/kbuf: advance head when a pickup empties the buffer ring Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 02/16] io_uring/net: keep recvmsg buffer select length within MAX_RW_COUNT Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 03/16] io_uring/net: mask socket type with SOCK_TYPE_MASK in io_socket_bpf_populate() Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 04/16] io_uring/register: enforce per-task restrictions in io_uring_register_blind() Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 05/16] io_uring/net: don't retry a non-blocking connect() that fails with -EAGAIN Jens Axboe
2026-11-04 18:44 ` Jens Axboe [this message]
2026-11-04 18:44 ` [PATCH 7.3.y 07/16] io_uring/io-wq: no new workers once the exit has begun Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 08/16] io_uring/rsrc: charge buffer arrays and nodes to memcg Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 09/16] io_uring: charge tctx nodes and personalities Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 10/16] io_uring: free XArray nodes left by a failed store Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 11/16] io_uring/bpf-ops: clear bpf_ctx while submitting SQEs Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 12/16] io_uring: free the task context after a grace period Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 13/16] io_uring/sqpoll: don't wait for the thread to exit Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 14/16] io_uring: defer foreign io-wq enqueues to task_work Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 15/16] io_uring/timeout: count cancelled timeouts in cq_timeouts Jens Axboe
2026-11-04 18:44 ` [PATCH 7.3.y 16/16] io_uring/net: fix multishot recv length limit accounting Jens Axboe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261104184447.516768-7-axboe@kernel.dk \
    --to=axboe@kernel.dk \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox