All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	patches@lists.linux.dev, Wei Gao <wegao@suse.com>,
	Jens Axboe <axboe@kernel.dk>
Subject: [PATCH 7.3 18/38] io_uring: end the drain when the drain request completes
Date: Wed, 28 Oct 2026 18:00:05 +0100	[thread overview]
Message-ID: <20261028165940.861225633@linuxfoundation.org> (raw)
In-Reply-To: <20261028165940.394092994@linuxfoundation.org>

7.3-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Jens Axboe <axboe@kernel.dk>

commit ecb6817b769fd7d71af2c9f446188649020b2e53 upstream.

Since requests are drained based on allocated requests, the drain stays
active after the drain request has posted its CQE, until it is freed and
a new request finds the defer list empty. A drain request run by io-wq
is freed only after the worker drops its reference, so a request
submitted after the drain completed can still be deferred behind it,
and get issued much later than the application expects.

A drain request dispatched from the defer list runs alone. Track it,
and end the drain when its CQE is flushed and nothing else is deferred.
Have io-wq complete drain requests through task_work, so that this
happens under ->uring_lock before the CQE is visible. Linked drain
requests keep waiting until the link is freed.

Reported-by: Wei Gao <wegao@suse.com>
Link: https://lore.kernel.org/io-uring/20261018070154.16944-1-wegao@suse.com/
Fixes: 8fb7aee05591 ("io_uring: drain based on allocates reqs")
Cc: stable@vger.kernel.org
Tested-by: Wei Gao <wegao@suse.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 include/linux/io_uring_types.h |    2 +
 io_uring/io_uring.c            |   42 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 41 insertions(+), 3 deletions(-)

--- a/include/linux/io_uring_types.h
+++ b/include/linux/io_uring_types.h
@@ -521,6 +521,8 @@ struct io_ring_ctx {
 	struct callback_head		poll_wq_task_work;
 	struct list_head		defer_list;
 	unsigned			nr_drained;
+	/* drain request dispatched from ->defer_list, until it completes */
+	struct io_kiocb			*drain_req;
 
 	/* protected by ->completion_lock */
 	unsigned			nr_req_allocated;
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -451,6 +451,9 @@ static __cold noinline void io_queue_def
 
 	lockdep_assert_held(&ctx->uring_lock);
 	__io_req_caches_free(ctx);
+	/* nothing outside of ->defer_list is alive */
+	if (ctx->nr_req_allocated == ctx->nr_drained)
+		ctx->drain_req = NULL;
 
 	while (!list_empty(&ctx->defer_list)) {
 		struct io_defer_entry *de = list_first_entry(&ctx->defer_list,
@@ -462,6 +465,9 @@ static __cold noinline void io_queue_def
 
 		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;
 		io_req_task_queue(de->req);
 		kfree(de);
 		first = false;
@@ -923,9 +929,11 @@ static void io_req_complete_post(struct
 
 	/*
 	 * Handle special CQ sync cases via task_work. DEFER_TASKRUN requires
-	 * the submitter task context, IOPOLL protects with uring_lock.
+	 * the submitter task context, IOPOLL protects with uring_lock. A drain
+	 * request ends the drain under uring_lock as its CQE is posted.
 	 */
-	if ((ctx->int_flags & IO_RING_F_LOCKLESS_CQ) || (req->flags & REQ_F_REISSUE)) {
+	if ((ctx->int_flags & IO_RING_F_LOCKLESS_CQ) ||
+	    (req->flags & (REQ_F_REISSUE | REQ_F_IO_DRAIN))) {
 defer_complete:
 		req->io_task_work.func = io_req_task_complete;
 		io_req_task_work_add(req);
@@ -1126,11 +1134,33 @@ static void io_free_batch_list(struct io
 	} while (node);
 }
 
+/*
+ * The dispatched drain request ran alone, and anything submitted after it was
+ * deferred. Once it completed, new requests may run if nothing is waiting.
+ */
+static __cold bool io_drain_req_completed(struct io_ring_ctx *ctx)
+{
+	struct io_wq_work_node *node;
+
+	__wq_list_for_each(node, &ctx->submit_state.compl_reqs) {
+		struct io_kiocb *req = container_of(node, struct io_kiocb,
+					    comp_list);
+
+		/* a requeued request hasn't completed */
+		if (req == ctx->drain_req && !(req->flags & REQ_F_REISSUE)) {
+			ctx->drain_req = NULL;
+			return true;
+		}
+	}
+	return false;
+}
+
 void __io_submit_flush_completions(struct io_ring_ctx *ctx)
 	__must_hold(&ctx->uring_lock)
 {
 	struct io_submit_state *state = &ctx->submit_state;
 	struct io_wq_work_node *node;
+	bool drain_done = false;
 
 	__io_cq_lock(ctx);
 	__wq_list_for_each(node, &state->compl_reqs) {
@@ -1152,13 +1182,19 @@ void __io_submit_flush_completions(struc
 	}
 	__io_cq_unlock_post(ctx);
 
+	if (unlikely(ctx->int_flags & IO_RING_F_DRAIN_ACTIVE) && ctx->drain_req)
+		drain_done = io_drain_req_completed(ctx);
+
 	if (!wq_list_empty(&state->compl_reqs)) {
 		io_free_batch_list(ctx, state->compl_reqs.first);
 		INIT_WQ_LIST(&state->compl_reqs);
 	}
 
-	if (unlikely(ctx->int_flags & IO_RING_F_DRAIN_ACTIVE))
+	if (unlikely(ctx->int_flags & IO_RING_F_DRAIN_ACTIVE)) {
 		io_queue_deferred(ctx);
+		if (drain_done && list_empty(&ctx->defer_list))
+			ctx->int_flags &= ~IO_RING_F_DRAIN_ACTIVE;
+	}
 
 	ctx->submit_state.cq_flush = false;
 }



  parent reply	other threads:[~2026-10-28 17:04 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-28 16:59 [PATCH 7.3 00/38] 7.3.1-rc1 review Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 01/38] genirq/proc: Fix missing CPU header in /proc/interrupts Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 02/38] mm/damon/core: error damos_commit_quota_goal() for zero target_value Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 03/38] Bluetooth: L2CAP: refuse __l2cap_chan_add if chan already has conn Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 04/38] tools/dma: fix building with O= Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 05/38] tracing: Hold trace_types_lock when updating modules in persistent instances Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 06/38] tracing: Hold trace_types_lock when resetting last boot data from readers Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 07/38] tracing: Reject incomplete event filter expressions Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 08/38] tracing: Save the event file instead of the compatible histogram Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 09/38] tracing: Unregister field variable histograms when the command fails Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 10/38] tracing: Add the bucket size to expr_field_str() Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 11/38] tracing: Fix 64-bit and signed histogram fields on 32-bit kernels Greg Kroah-Hartman
2026-10-28 16:59 ` [PATCH 7.3 12/38] tracing/histograms: Verify event_call identity when updating synth_event refcount Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 13/38] tracing/syscalls: Use copy_from_user for the faultable syscall buffer Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 14/38] io_uring/poll: avoid retry wakeup loss when dropping ownership Greg Kroah-Hartman
2026-10-29  7:53   ` Jiri Slaby
2026-10-29  9:07     ` Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 15/38] io_uring/wait: wake real-time waiters from hard interrupt context Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 16/38] io_uring/net: keep recv buffer select length within MAX_RW_COUNT Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 17/38] io_uring/waitid: prevent cancel reference wrap Greg Kroah-Hartman
2026-10-28 17:00 ` Greg Kroah-Hartman [this message]
2026-10-28 17:00 ` [PATCH 7.3 19/38] keys: Avoid the owner account dereference in named keyring lookup Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 20/38] keys: Check the authorization payload in process keyring searches Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 21/38] keys: Protect the type name while describing a key Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 22/38] keys: make keyring indexes independent of kernel addresses Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 23/38] keys: Protect the read method check against type removal Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 24/38] KEYS: Fix key_reject_and_link() race with keyring restriction Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 25/38] KEYS: trusted: Fix blob allocation size in tpm2_key_decode() Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 26/38] keys/trusted_keys: return immediately after TPM unseal failure Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 27/38] asymmetric_keys: reject trust keys without IDs Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 28/38] ftrace: Initialize modname and offset in print_rec() Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 29/38] coredump: hold RCU while releasing parked threads Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 30/38] signal: only SIGKILL and the freezers interrupt a coredumping task Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 31/38] io-wq: order the exit bit against worker creation task work Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 32/38] signal: dont retarget shared signals in a dying thread group Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 33/38] ptrace: refuse to change the signal mask of a user worker Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 34/38] fork: release the files of a failed fork after sched_cancel_fork() Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 35/38] exit: hang up the tty before closing the files Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 36/38] coredump: prevent TIF_NOTIFY_SIGNAL from interrupting coredumps Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 37/38] pid_namespace: prevent TIF_NOTIFY_SIGNAL from interrupting the reaper Greg Kroah-Hartman
2026-10-28 17:00 ` [PATCH 7.3 38/38] signal: allow taks to temporarily block TIF_NOTIFY_SIGNAL Greg Kroah-Hartman
2026-10-28 18:08 ` [PATCH 7.3 00/38] 7.3.1-rc1 review Ronald Warsow
2026-10-28 19:40 ` Brett A C Sheffield
2026-10-29  4:01 ` Takeshi Ogasawara
2026-10-29  5:00 ` Peter Schneider
2026-10-29 12:06 ` Barry K. Nathan
2026-10-29 13:53 ` Miguel Ojeda
2026-10-29 14:12 ` Ron Economos
2026-10-29 14:42 ` SJ Park
2026-10-29 15:17 ` Shuah Khan
2026-10-29 17:48 ` Florian Fainelli

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=20261028165940.861225633@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=axboe@kernel.dk \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    --cc=wegao@suse.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.