Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ublk: build batch from IOs in same io_ring_ctx and io task

ublk_queue_cmd_list() dispatches the whole batch list by scheduling task
work via the tail request's io_uring_cmd, this way is fine even though
more than one io_ring_ctx are involved for this batch since it is just
one running context.

However, the task work handler ublk_cmd_list_tw_cb() takes `issue_flags`
of tail uring_cmd's io_ring_ctx for completing all commands. This way is
wrong if any uring_cmd is issued from different io_ring_ctx.

Fixes it by always building batch IOs from same io_ring_ctx and io task
because ublk_dispatch_req() does validate task context, and IO needs to
be aborted in case of running from fallback task work context.

For typical per-queue or per-io daemon implementation, this way shouldn't
make difference from performance viewpoint, because single io_ring_ctx is
taken in each daemon for normal use case.

Fixes: d796cea7b9f3 ("ublk: implement ->queue_rqs()")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250625022554.883571-1-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Ming Lei and committed by
Jens Axboe
524346e9 8c847285

+10 -1
+10 -1
drivers/block/ublk_drv.c
··· 1416 1416 return BLK_STS_OK; 1417 1417 } 1418 1418 1419 + static inline bool ublk_belong_to_same_batch(const struct ublk_io *io, 1420 + const struct ublk_io *io2) 1421 + { 1422 + return (io_uring_cmd_ctx_handle(io->cmd) == 1423 + io_uring_cmd_ctx_handle(io2->cmd)) && 1424 + (io->task == io2->task); 1425 + } 1426 + 1419 1427 static void ublk_queue_rqs(struct rq_list *rqlist) 1420 1428 { 1421 1429 struct rq_list requeue_list = { }; ··· 1435 1427 struct ublk_queue *this_q = req->mq_hctx->driver_data; 1436 1428 struct ublk_io *this_io = &this_q->ios[req->tag]; 1437 1429 1438 - if (io && io->task != this_io->task && !rq_list_empty(&submit_list)) 1430 + if (io && !ublk_belong_to_same_batch(io, this_io) && 1431 + !rq_list_empty(&submit_list)) 1439 1432 ublk_queue_cmd_list(io, &submit_list); 1440 1433 io = this_io; 1441 1434