From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793207963; b=3eiEzXgKA7lJMX4yRqOC0NykigXKs37hLB6gnl4ynt624PcrXqQ00aA0NGa08iQDsUs7 gHG3aQFUVE0o1nOTtLPFKIWvxNHGv29I4tbnqalhcuCRFTjRkdTQJ/jO0bwnCF9IY6RQ/ 3/CKH6hDR6itmmPNUPdznPwz6fsruw+c/yXbj4jHzlVQd/et/7uHyo2pqsD+EqFkO9Ldl y57Pg0FpXgKzHC1P8wwB1IkZYn21HacKL84M3a1pWPIS/NTOAa0akD2pIABmyzEzNk/rc F/UuNF9XDFAHyWR8qmb46ghvCUVCfFcc3G0uqECvy42Xi28JgDs9bJrnxxJETTSlzvA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793207963; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=w+bptJSIUm9TleA81lnnriMwuZSWXv5o+v4YcVBejDs=; b=CmYq1ar4wrAqmhQPwNNkJR/Gms0GJgNDNP7pg4r6FPRtkHng3BhNJlrp1sSBXMZvyazE B3qkaTdyGEZuaQ4/gR34GDsLtKabmAbIE7cKW36IskgjuJbdfvB1bn8SPz6jaUkQZy6Ph lpy0jlc3NFaRkjKvesJi8U1lbfMivmeyc5NQ8dYIt4xJWb/Qe1eNDbBpWnV6/nAMHYQvI gRzF48hVyPdoTLQ1p5V1/bBE+7snmZeh9md3K6sl3l6FCS/ugwEphcmxXZ/ZfDgSeHFGr QLAMtEyoXeRPRVmdt5H9PauD5H6g0+kXxIQN60TTq/mY6FjZoQOAMJbeyc1grDm1U4A== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b="SiTIP/9u"; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 759BC606A31C; Wed, 28 Oct 2026 17:19:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=SiTIP/9u Received: by smtp.kernel.org (Postfix) with ESMTPSA id C3F9E1F01825; Wed, 28 Oct 2026 17:19:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1793207963; bh=w+bptJSIUm9TleA81lnnriMwuZSWXv5o+v4YcVBejDs=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=SiTIP/9uEW3N9M1KQX3rzm9IBd+7zaDq8B+CQO/OqI/YhrnbDPIZ8WZNP2t1Q4SyZ 8+qB3XQOxwGa+sYD6hvwDJ5mcYA75gAP8kbIqZoz5ZAftaQQahq+nSibkiDcLSDEpM e6O7RMKFpKmQZ7ifkVSGDHisZU2RLBcnMO31PXsU= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Josef Bacik , Jens Axboe Subject: [PATCH 6.12 201/247] io_uring/io-wq: let cancel find picked up hashed work Date: Wed, 28 Oct 2026 18:00:04 +0100 Message-ID: <20261028165952.180550346@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028165947.349197979@linuxfoundation.org> References: <20261028165947.349197979@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: patches@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Josef Bacik Commit e9efeb4fc97b0879512a3c3b995ed448f2487e12 upstream. io_get_next_work() takes all the work items that share a hash off the work list in one go, and the worker runs them one after the other. Only the one it is working on is visible as ->cur_work. The others are neither on the list nor current, so io_wq_cancel_cb() can't find them. IORING_OP_ASYNC_CANCEL and IORING_REGISTER_SYNC_CANCEL return -ENOENT for a request that has not even been started, e.g. a buffered write queued behind another write to the same file that is blocked, and the request is carried out. The cancellation done for a task or ring that goes away gets there in the end, as it keeps trying, but it has to wait for each item to become current. Keep a pointer to the remainder of the chain next to ->cur_work, and have io_wq_worker_cancel() look at it. The items on it belong to the worker, which needs ->lock to move on to the next one. Matching work is flagged with IO_WQ_WORK_CANCEL and fails with -ECANCELED when its turn comes. The worker isn't signalled for it, that would interrupt the unrelated work it is busy with. As the request isn't gone yet, it is reported like running work, with -EALREADY. Fixes: 86f3cd1b589a ("io-wq: handle hashed writes in chains") Assisted-by: LLM Signed-off-by: Josef Bacik Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-13-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/io-wq.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) --- a/io_uring/io-wq.c +++ b/io_uring/io-wq.c @@ -54,6 +54,8 @@ struct io_worker { struct io_wq *wq; struct io_wq_work *cur_work; + /* rest of the hashed chain ->cur_work was taken off the list with */ + struct io_wq_work *next_work; raw_spinlock_t lock; struct completion ref_done; @@ -535,6 +537,17 @@ static struct io_wq_work *io_get_next_wo return NULL; } +static void __io_assign_current_work(struct io_worker *worker, + struct io_wq_work *work) +{ + raw_spin_lock(&worker->lock); + worker->cur_work = work; + /* stays valid while in between two items of a chain */ + if (work) + worker->next_work = wq_next_work(work); + raw_spin_unlock(&worker->lock); +} + static void io_assign_current_work(struct io_worker *worker, struct io_wq_work *work) { @@ -543,9 +556,7 @@ static void io_assign_current_work(struc cond_resched(); } - raw_spin_lock(&worker->lock); - worker->cur_work = work; - raw_spin_unlock(&worker->lock); + __io_assign_current_work(worker, work); } /* @@ -576,9 +587,7 @@ static void io_worker_handle_work(struct * work list, but isn't yet discoverable as the * current work item for this worker. */ - raw_spin_lock(&worker->lock); - worker->cur_work = work; - raw_spin_unlock(&worker->lock); + __io_assign_current_work(worker, work); } raw_spin_unlock(&acct->lock); @@ -1083,6 +1092,7 @@ static bool __io_wq_worker_cancel(struct static bool io_wq_worker_cancel(struct io_worker *worker, void *data) { struct io_cb_cancel_data *match = data; + struct io_wq_work *work; /* * Hold the lock to avoid ->cur_work going out of scope, caller @@ -1091,6 +1101,19 @@ static bool io_wq_worker_cancel(struct i raw_spin_lock(&worker->lock); if (__io_wq_worker_cancel(worker, match, worker->cur_work)) match->nr_running++; + /* + * Hashed work is taken off the work list a chain at a time, what the + * worker hasn't started yet can only be found here. It doesn't move on + * without the lock. Just mark the work, it fails once it is its turn. + */ + for (work = worker->next_work; work; work = wq_next_work(work)) { + if (match->nr_running && !match->cancel_all) + break; + if (match->fn(work, match->data)) { + atomic_or(IO_WQ_WORK_CANCEL, &work->flags); + match->nr_running++; + } + } raw_spin_unlock(&worker->lock); return match->nr_running && !match->cancel_all;