From 2b0e87e46f675fdf7e9522d7fc1a7bc00e9fa9c3 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 26 May 2026 08:39:20 -0700 Subject: [PATCH 1/2] block: export passthrough stats enabled A user can enable io accounting for passthrough requests, so export the helper that checks if the request should be tracked. This will enable stacking drivers to to report iostats for passthrough workloads. Signed-off-by: Keith Busch Reviewed-by: Nilay Shroff Reviewed-by: Nitesh Shetty --- block/blk-mq.c | 32 +------------------------------- include/linux/blk-mq.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 28c2d931e75ea..48115e1d9d6a8 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1088,43 +1088,13 @@ static inline void blk_account_io_done(struct request *req, u64 now) } } -static inline bool blk_rq_passthrough_stats(struct request *req) -{ - struct bio *bio = req->bio; - - if (!blk_queue_passthrough_stat(req->q)) - return false; - - /* Requests without a bio do not transfer data. */ - if (!bio) - return false; - - /* - * Stats are accumulated in the bdev, so must have one attached to a - * bio to track stats. Most drivers do not set the bdev for passthrough - * requests, but nvme is one that will set it. - */ - if (!bio->bi_bdev) - return false; - - /* - * We don't know what a passthrough command does, but we know the - * payload size and data direction. Ensuring the size is aligned to the - * block size filters out most commands with payloads that don't - * represent sector access. - */ - if (blk_rq_bytes(req) & (bdev_logical_block_size(bio->bi_bdev) - 1)) - return false; - return true; -} - static inline void blk_account_io_start(struct request *req) { trace_block_io_start(req); if (!blk_queue_io_stat(req->q)) return; - if (blk_rq_is_passthrough(req) && !blk_rq_passthrough_stats(req)) + if (blk_rq_is_passthrough(req) && !blk_rq_passthrough_stats(req, req->q)) return; req->rq_flags |= RQF_IO_STAT; diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 18a2388ba581d..25931a8076d2a 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -1243,4 +1243,34 @@ static inline int blk_rq_map_sg(struct request *rq, struct scatterlist *sglist) } void blk_dump_rq_flags(struct request *, char *); +static inline bool blk_rq_passthrough_stats(struct request *req, + struct request_queue *q) +{ + struct bio *bio = req->bio; + + if (!blk_queue_passthrough_stat(q)) + return false; + + /* Requests without a bio do not transfer data. */ + if (!bio) + return false; + + /* + * Stats are accumulated in the bdev, so must have one attached to a + * bio to track stats. Most drivers do not set the bdev for passthrough + * requests, but nvme is one that will set it. + */ + if (!bio->bi_bdev) + return false; + + /* + * We don't know what a passthrough command does, but we know the + * payload size and data direction. Ensuring the size is aligned to the + * block size filters out most commands with payloads that don't + * represent sector access. + */ + if (blk_rq_bytes(req) & (bdev_logical_block_size(bio->bi_bdev) - 1)) + return false; + return true; +} #endif /* BLK_MQ_H */ From c059677a7caab4ffd50d0c2dc435103f596d5ad0 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 26 May 2026 08:39:21 -0700 Subject: [PATCH 2/2] nvme: add support multipath passthrough iostats Don't skip io accounting for passthrough commands if the user enabled tracking these. Signed-off-by: Keith Busch Reviewed-by: Nilay Shroff Reviewed-by: Nitesh Shetty --- drivers/nvme/host/ioctl.c | 4 ++++ drivers/nvme/host/multipath.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index 08889b20e5d8c..38ca04567406a 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -102,8 +102,12 @@ static struct request *nvme_alloc_user_request(struct request_queue *q, struct nvme_command *cmd, blk_opf_t rq_flags, blk_mq_req_flags_t blk_flags) { + struct nvme_ns *ns = q->queuedata; struct request *req; + if (ns && nvme_ns_head_multipath(ns->head)) + rq_flags |= REQ_NVME_MPATH; + req = blk_mq_alloc_request(q, nvme_req_op(cmd) | rq_flags, blk_flags); if (IS_ERR(req)) return req; diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 263161cb8ac06..d0a95cde181c4 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -175,9 +175,12 @@ void nvme_mpath_start_request(struct request *rq) nvme_req(rq)->flags |= NVME_MPATH_CNT_ACTIVE; } - if (!blk_queue_io_stat(disk->queue) || blk_rq_is_passthrough(rq) || + if (!blk_queue_io_stat(disk->queue) || (nvme_req(rq)->flags & NVME_MPATH_IO_STATS)) return; + if (blk_rq_is_passthrough(rq) && + !blk_rq_passthrough_stats(rq, disk->queue)) + return; nvme_req(rq)->flags |= NVME_MPATH_IO_STATS; nvme_req(rq)->start_time = bdev_start_io_acct(disk->part0, req_op(rq),