From: John Garry <john.garry@linux.dev>
To: axboe@kernel.dk, kbusch@kernel.org, sagi@grimberg.me, hch@lst.de
Cc: linux-block@vger.kernel.org, linux-nvme@lists.infradead.org,
John Garry <john.garry@linux.dev>
Subject: [PATCH v4 4/4] nvme-multipath: fix diskstats for partitions
Date: Mon, 21 Sep 2026 09:37:52 +0100 [thread overview]
Message-ID: <20260921083752.1154316-5-john.garry@linux.dev> (raw)
In-Reply-To: <20260921083752.1154316-1-john.garry@linux.dev>
Currently diskstats for partitions are never updated:
$ ./fio_read nvme1n1p1 # run traffic on /dev/nvme1n1p1
...
$ more /proc/diskstats | grep nvme1
259 2 nvme1c1n1 49857 0 400344 768565 0 0 0 0 0 2334 768565 0 0 0 0 0 0
259 3 nvme1n1 99710 0 800680 1599285 0 0 0 0 0 2346 1599285 0 0 0 0 0 0
259 5 nvme1n1p1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
259 4 nvme1c2n1 49853 0 400336 831472 0 0 0 0 0 2315 831472 0 0 0 0 0 0
This is because we only ever update the diskstats for the multipath disk in
nvme_mpath_end_request(), and we never take into account that the original
bi_bdev may been a partition of this disk.
Functions bdev_start_io_acct() and bdev_start_io_acct() do handle
updating diskstats for a partition, in that they also update the whole
disk also (if a partition), so use the partition (if applicable) when
calling those functions.
Change any functionality which used to lookup the gendisk part0 to now
lookup the specific gendisk partition.
Signed-off-by: John Garry <john.garry@linux.dev>
---
drivers/nvme/host/multipath.c | 51 ++++++++++++++++++++++++++++-------
1 file changed, 41 insertions(+), 10 deletions(-)
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index e871ad40d893..2969c0e5187c 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -144,6 +144,23 @@ void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
blk_freeze_queue_start(h->disk->queue);
}
+static struct block_device *nvme_disk_to_part(struct gendisk *disk,
+ u8 partno)
+{
+ /* Quick lookup for whole disk */
+ if (!partno)
+ return disk->part0;
+ return xa_load(&disk->part_tbl, partno);
+}
+
+static struct block_device *nvme_to_disk_part(struct gendisk *disk,
+ struct block_device *bdev)
+{
+ if (!bdev)
+ return disk->part0;
+ return nvme_disk_to_part(disk, bdev_partno(bdev));
+}
+
void nvme_failover_req(struct request *req)
{
struct nvme_ns *ns = req->q->queuedata;
@@ -165,8 +182,10 @@ void nvme_failover_req(struct request *req)
}
spin_lock_irqsave(&ns->head->requeue_lock, flags);
- for (bio = req->bio; bio; bio = bio->bi_next)
- bio_set_dev(bio, ns->head->disk->part0);
+ for (bio = req->bio; bio; bio = bio->bi_next) {
+ bio_set_dev(bio, nvme_to_disk_part(ns->head->disk,
+ bio->bi_bdev));
+ }
blk_steal_bios(&ns->head->requeue_list, req);
spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
@@ -194,8 +213,9 @@ void nvme_mpath_start_request(struct request *rq)
return;
nvme_req(rq)->flags |= NVME_MPATH_IO_STATS;
- nvme_req(rq)->start_time = bdev_start_io_acct(disk->part0, req_op(rq),
- jiffies);
+ nvme_req(rq)->start_time = bdev_start_io_acct(
+ nvme_to_disk_part(disk, rq->part),
+ req_op(rq), jiffies);
}
EXPORT_SYMBOL_GPL(nvme_mpath_start_request);
@@ -208,7 +228,8 @@ void nvme_mpath_end_request(struct request *rq)
if (!(nvme_req(rq)->flags & NVME_MPATH_IO_STATS))
return;
- bdev_end_io_acct(ns->head->disk->part0, req_op(rq),
+ bdev_end_io_acct(nvme_to_disk_part(ns->head->disk,
+ rq->part), req_op(rq),
blk_rq_bytes(rq) >> SECTOR_SHIFT,
nvme_req(rq)->start_time);
}
@@ -530,11 +551,21 @@ static bool nvme_available_path(struct nvme_ns_head *head)
return nvme_mpath_queue_if_no_path(head);
}
+static struct block_device *nvme_find_path_bdev(struct nvme_ns_head *head,
+ u8 partno)
+{
+ struct nvme_ns *ns = nvme_find_path(head);
+
+ if (!ns)
+ return NULL;
+ return nvme_disk_to_part(ns->disk, partno);
+}
+
static void nvme_ns_head_submit_bio(struct bio *bio)
{
struct nvme_ns_head *head = bio->bi_bdev->bd_disk->private_data;
struct device *dev = disk_to_dev(head->disk);
- struct nvme_ns *ns;
+ struct block_device *bdev;
int srcu_idx;
/*
@@ -547,9 +578,9 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
return;
srcu_idx = srcu_read_lock(&head->srcu);
- ns = nvme_find_path(head);
- if (likely(ns)) {
- bio_set_dev(bio, ns->disk->part0);
+ bdev = nvme_find_path_bdev(head, bdev_partno(bio->bi_bdev));
+ if (likely(bdev)) {
+ bio_set_dev(bio, bdev);
/*
* Use BIO_REMAPPED to skip bio_check_eod() when this bio
* enters submit_bio_noacct() for the per-path device. The EOD
@@ -557,7 +588,7 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
*/
bio_set_flag(bio, BIO_REMAPPED);
bio->bi_opf |= REQ_NVME_MPATH;
- trace_block_bio_remap(bio, disk_devt(ns->head->disk),
+ trace_block_bio_remap(bio, disk_devt(head->disk),
bio->bi_iter.bi_sector);
submit_bio_noacct(bio);
} else if (nvme_available_path(head)) {
--
2.43.0
next prev parent reply other threads:[~2026-09-21 8:38 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 8:37 [PATCH v4 0/4] fix NVMe multipath partition diskstats John Garry
2026-09-21 8:37 ` [PATCH v4 1/4] block: support cloning partitions John Garry
2026-09-21 8:37 ` [PATCH v4 2/4] block: don't show partition diskstats for GENHD_FL_HIDDEN John Garry
2026-09-21 8:37 ` [PATCH v4 3/4] nvme-multipath: clone head disk partitions to per-path disks John Garry
2026-09-21 8:37 ` John Garry [this message]
2026-09-28 7:30 ` [PATCH v4 0/4] fix NVMe multipath partition diskstats John Garry
2026-09-28 9:14 ` Christoph Hellwig
2026-09-28 10:16 ` John Garry
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=20260921083752.1154316-5-john.garry@linux.dev \
--to=john.garry@linux.dev \
--cc=axboe@kernel.dk \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=linux-block@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
/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.