[PATCH] io_uring/io-wq: stop a single cancel after one running match

Mark Amirkan via B4 Relay posted 1 patch 1 week, 5 days ago
io_uring/io-wq.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
[PATCH] io_uring/io-wq: stop a single cancel after one running match
Posted by Mark Amirkan via B4 Relay 1 week, 5 days ago
From: Mark Amirkan <markdamirkan@gmail.com>

io_wq_worker_cancel() asks io_acct_for_each_worker() to stop after one
match when cancel_all is clear.  io_acct_cancel_running_work() discards
that result, so io_wq_cancel_running_work() continues into the other
worker account with nr_running already set.

If the first worker there also matches, one non-ALL cancel signals a
request in both the bounded and unbounded accounts.

Return the iterator result and stop scanning accounts after a match.
IORING_ASYNC_CANCEL_ALL is unchanged because its callback does not stop
the iteration.

A test runs a blocking open in the bounded account and a blocking
pipe-to-pipe splice in the unbounded account with the same user_data.
Before this change both operations are interrupted by one cancel.  After
the change only the open is interrupted, and the splice completes when
input is supplied.

Fixes: 751eedc4b4b7 ("io_uring/io-wq: move worker lists to struct io_wq_acct")
Cc: stable@vger.kernel.org
Assisted-by: Symbolic
Signed-off-by: Mark Amirkan <markdamirkan@gmail.com>
---
 io_uring/io-wq.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c
index 2ca223e47d..9f9039e3d3 100644
--- a/io_uring/io-wq.c
+++ b/io_uring/io-wq.c
@@ -1181,12 +1181,15 @@ static void io_wq_cancel_pending_work(struct io_wq *wq,
 	}
 }
 
-static void io_acct_cancel_running_work(struct io_wq_acct *acct,
+static bool io_acct_cancel_running_work(struct io_wq_acct *acct,
 					struct io_cb_cancel_data *match)
 {
+	bool ret;
+
 	raw_spin_lock(&acct->workers_lock);
-	io_acct_for_each_worker(acct, io_wq_worker_cancel, match);
+	ret = io_acct_for_each_worker(acct, io_wq_worker_cancel, match);
 	raw_spin_unlock(&acct->workers_lock);
+	return ret;
 }
 
 static void io_wq_cancel_running_work(struct io_wq *wq,
@@ -1195,7 +1198,8 @@ static void io_wq_cancel_running_work(struct io_wq *wq,
 	rcu_read_lock();
 
 	for (int i = 0; i < IO_WQ_ACCT_NR; i++)
-		io_acct_cancel_running_work(&wq->acct[i], match);
+		if (io_acct_cancel_running_work(&wq->acct[i], match))
+			break;
 
 	rcu_read_unlock();
 }

---
base-commit: 11773ae6da9c9d92f5d1def78f7e70a9f1fa7b1c
change-id: 20260913-b4-send-io-wq-cancel-507488f72245

Best regards,
--  
Mark Amirkan <markdamirkan@gmail.com>
Re: [PATCH] io_uring/io-wq: stop a single cancel after one running match
Posted by Max Kellermann 1 week, 5 days ago
On Sun, Sep 13, 2026 at 12:30 PM Mark Amirkan via B4 Relay
<devnull+markdamirkan.gmail.com@kernel.org> wrote:
> io_wq_worker_cancel() asks io_acct_for_each_worker() to stop after one
> match when cancel_all is clear.  io_acct_cancel_running_work() discards
> that result, so io_wq_cancel_running_work() continues into the other
> worker account with nr_running already set.
>
> If the first worker there also matches, one non-ALL cancel signals a
> request in both the bounded and unbounded accounts.
>
> Return the iterator result and stop scanning accounts after a match.
> IORING_ASYNC_CANCEL_ALL is unchanged because its callback does not stop
> the iteration.
>
> A test runs a blocking open in the bounded account and a blocking
> pipe-to-pipe splice in the unbounded account with the same user_data.
> Before this change both operations are interrupted by one cancel.  After
> the change only the open is interrupted, and the splice completes when
> input is supplied.
>
> Fixes: 751eedc4b4b7 ("io_uring/io-wq: move worker lists to struct io_wq_acct")

Thanks, that is indeed a detail that I have missed in my commit.
(Bonus points for documenting the new io_acct_cancel_running_work()
return value. That's missing too often in the kernel, even in my own
commit.)

Reviewed-by: Max Kellermann <max.kellermann@ionos.com>

-- 
Max Kellermann
Principal Architect
Hosting Technology

cm4all | Im Mediapark 6a | 50670 Köln | Germany
General information about the company can be found here:
https://www.cm4all.com/impressum
A member of the IONOS Group