From: Ming Lei <tom.leiming@gmail.com>
To: linux-block@vger.kernel.org
Cc: Ming Lei <tom.leiming@gmail.com>, Jens Axboe <axboe@kernel.dk>,
Caleb Sander Mateos <csander@purestorage.com>,
Josef Bacik <josef@toxicpanda.com>
Subject: [PATCH 3/8] ublk: mark the batch fetch command cancelable before linking it
Date: Thu, 1 Oct 2026 07:54:17 -0500 [thread overview]
Message-ID: <20261001125422.1364260-4-tom.leiming@gmail.com> (raw)
In-Reply-To: <20261001125422.1364260-1-tom.leiming@gmail.com>
UBLK_U_IO_FETCH_IO_CMDS has the same order problem as the per-io
commands: ublk_batch_attach() links the fetch command into fcmd_head
and marks it cancelable only after dropping evts_lock. A cancel from
the control path (ublk_batch_cancel_queue()) can take it in between and
complete it, and the later mark puts a completed request on io_uring's
cancelable list.
Mark it before linking it. evts_lock orders the mark before the link,
which is where the cancel finds it.
Batch commands are not bounced to task work, so they can run from io-wq
without uring_lock, and io_uring's cancel walk can now find a fetch
command before it is linked. Two things make that safe:
- initialize fcmd->node: it came from kzalloc(), so list_empty() saw a
linked node and ublk_batch_cancel_cmd() would list_del_init() NULL
pointers
- on the -ENODEV path, complete the command with io_uring_cmd_done()
before freeing fcmd: that removes it from the cancelable list under
uring_lock, after which nothing can see fcmd
Also use data->cmd instead of fcmd->cmd after dropping evts_lock: once
fcmd is linked and not the active one, a control-path cancel may
complete and free it.
Fixes: a4d883755399 ("ublk: add UBLK_U_IO_FETCH_IO_CMDS for batch I/O processing")
Cc: stable@vger.kernel.org # v7.0+
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
---
drivers/block/ublk_drv.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 6015fb2fb925..5e37b8e9d9ac 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -815,6 +815,8 @@ ublk_batch_alloc_fcmd(struct io_uring_cmd *cmd)
if (fcmd) {
fcmd->cmd = cmd;
fcmd->buf_group = READ_ONCE(cmd->sqe->buf_index);
+ /* a cancel may look at it before it is linked */
+ INIT_LIST_HEAD(&fcmd->node);
}
return fcmd;
}
@@ -3915,6 +3917,15 @@ static int ublk_batch_attach(struct ublk_queue *ubq,
bool free = false;
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(data->cmd);
+ /*
+ * Mark it cancelable before linking it into fcmd_head, where a cancel
+ * from the control path can take and complete it: see
+ * ublk_prep_cancel(). evts_lock orders the mark before the link.
+ */
+ pdu->ubq = ubq;
+ pdu->fcmd = fcmd;
+ io_uring_cmd_mark_cancelable(fcmd->cmd, data->issue_flags);
+
spin_lock(&ubq->evts_lock);
if (unlikely(ubq->force_abort || ubq->canceling)) {
free = true;
@@ -3925,14 +3936,12 @@ static int ublk_batch_attach(struct ublk_queue *ubq,
spin_unlock(&ubq->evts_lock);
if (unlikely(free)) {
+ /* off the cancelable list first, then nothing can see fcmd */
+ io_uring_cmd_done(data->cmd, -ENODEV, data->issue_flags);
ublk_batch_free_fcmd(fcmd);
- return -ENODEV;
+ return -EIOCBQUEUED;
}
- pdu->ubq = ubq;
- pdu->fcmd = fcmd;
- io_uring_cmd_mark_cancelable(fcmd->cmd, data->issue_flags);
-
if (!new_fcmd)
goto out;
@@ -3940,9 +3949,12 @@ static int ublk_batch_attach(struct ublk_queue *ubq,
* If the two fetch commands are originated from same io_ring_ctx,
* run batch dispatch directly. Otherwise, schedule task work for
* doing it.
+ *
+ * Use data->cmd, not fcmd->cmd: once fcmd is linked and not active,
+ * a cancel from the control path may complete and free it.
*/
if (io_uring_cmd_ctx_handle(new_fcmd->cmd) ==
- io_uring_cmd_ctx_handle(fcmd->cmd)) {
+ io_uring_cmd_ctx_handle(data->cmd)) {
data->cmd = new_fcmd->cmd;
ublk_batch_dispatch(ubq, data, new_fcmd);
} else {
--
2.55.0
next prev parent reply other threads:[~2026-10-01 12:54 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 12:54 [PATCH 0/8] ublk: don't dispatch to canceled io commands Ming Lei
2026-10-01 12:54 ` [PATCH 1/8] ublk: keep a canceled FETCH round canceling until the server is gone Ming Lei
2026-10-01 12:54 ` [PATCH 2/8] ublk: mark the io command cancelable before publishing it Ming Lei
2026-10-01 12:54 ` Ming Lei [this message]
2026-10-01 12:54 ` [PATCH 4/8] ublk: reset the FETCH round in release also without a disk Ming Lei
2026-10-01 12:54 ` [PATCH 5/8] ublk: reset the FETCH round under ub->mutex Ming Lei
2026-10-01 12:54 ` [PATCH 6/8] ublk: let STOP_DEV cancel the server's commands before its release Ming Lei
2026-10-01 12:54 ` [PATCH 7/8] selftests: ublk: move the control command helpers into ctrl.c Ming Lei
2026-10-01 12:54 ` [PATCH 8/8] selftests: ublk: add test for going live over canceled io commands Ming Lei
2026-10-05 16:23 ` [PATCH] ublk: refuse to go live after an io command was canceled Josef Bacik
2026-10-06 14:14 ` Ming Lei
2026-10-05 16:23 ` [PATCH v2] " Josef Bacik
2026-10-05 18:50 ` [PATCH 0/8] ublk: don't dispatch to canceled io commands Josef Bacik
2026-10-06 16:10 ` [PATCH 0/4] ublk: fix UBLK_CMD_QUIESCE_DEV leaving commands behind Josef Bacik
2026-10-06 13:05 ` [PATCH 1/4] ublk: don't cancel commands in QUIESCE_DEV on a device that isn't live Josef Bacik
2026-10-06 14:49 ` [PATCH 2/4] ublk: drop QUIESCE_DEV's wait for an idle command Josef Bacik
2026-10-06 14:50 ` [PATCH 3/4] ublk: give the command back from COMMIT_AND_FETCH on a canceling queue Josef Bacik
2026-10-06 14:50 ` [PATCH 4/4] ublk: keep canceling in QUIESCE_DEV until the server's commands are taken Josef Bacik
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=20261001125422.1364260-4-tom.leiming@gmail.com \
--to=tom.leiming@gmail.com \
--cc=axboe@kernel.dk \
--cc=csander@purestorage.com \
--cc=josef@toxicpanda.com \
--cc=linux-block@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 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.