Skip to content

Commit d4d957b

Browse files
sagigrimbergChristoph Hellwig
authored andcommitted
nvme-multipath: support io stats on the mpath device
Our mpath stack device is just a shim that selects a bottom namespace and submits the bio to it without any fancy splitting. This also means that we don't clone the bio or have any context to the bio beyond submission. However it really sucks that we don't see the mpath device io stats. Given that the mpath device can't do that without adding some context to it, we let the bottom device do it on its behalf (somewhat similar to the approach taken in nvme_trace_bio_complete). When the IO starts, we account the request for multipath IO stats using REQ_NVME_MPATH_IO_STATS nvme_request flag to avoid queue io stats disable in the middle of the request. Signed-off-by: Sagi Grimberg <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Keith Busch <[email protected]>
1 parent 6887fc6 commit d4d957b

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

drivers/nvme/host/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ static inline void nvme_end_req(struct request *req)
384384
nvme_log_error(req);
385385
nvme_end_req_zoned(req);
386386
nvme_trace_bio_complete(req);
387+
if (req->cmd_flags & REQ_NVME_MPATH)
388+
nvme_mpath_end_request(req);
387389
blk_mq_end_request(req, status);
388390
}
389391

drivers/nvme/host/multipath.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,31 @@ void nvme_failover_req(struct request *req)
114114
kblockd_schedule_work(&ns->head->requeue_work);
115115
}
116116

117+
void nvme_mpath_start_request(struct request *rq)
118+
{
119+
struct nvme_ns *ns = rq->q->queuedata;
120+
struct gendisk *disk = ns->head->disk;
121+
122+
if (!blk_queue_io_stat(disk->queue) || blk_rq_is_passthrough(rq))
123+
return;
124+
125+
nvme_req(rq)->flags |= NVME_MPATH_IO_STATS;
126+
nvme_req(rq)->start_time = bdev_start_io_acct(disk->part0,
127+
blk_rq_bytes(rq) >> SECTOR_SHIFT,
128+
req_op(rq), jiffies);
129+
}
130+
EXPORT_SYMBOL_GPL(nvme_mpath_start_request);
131+
132+
void nvme_mpath_end_request(struct request *rq)
133+
{
134+
struct nvme_ns *ns = rq->q->queuedata;
135+
136+
if (!(nvme_req(rq)->flags & NVME_MPATH_IO_STATS))
137+
return;
138+
bdev_end_io_acct(ns->head->disk->part0, req_op(rq),
139+
nvme_req(rq)->start_time);
140+
}
141+
117142
void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
118143
{
119144
struct nvme_ns *ns;
@@ -503,6 +528,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
503528

504529
blk_queue_flag_set(QUEUE_FLAG_NONROT, head->disk->queue);
505530
blk_queue_flag_set(QUEUE_FLAG_NOWAIT, head->disk->queue);
531+
blk_queue_flag_set(QUEUE_FLAG_IO_STAT, head->disk->queue);
506532
/*
507533
* This assumes all controllers that refer to a namespace either
508534
* support poll queues or not. That is not a strict guarantee,

drivers/nvme/host/nvme.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ struct nvme_request {
162162
u8 retries;
163163
u8 flags;
164164
u16 status;
165+
#ifdef CONFIG_NVME_MULTIPATH
166+
unsigned long start_time;
167+
#endif
165168
struct nvme_ctrl *ctrl;
166169
};
167170

@@ -173,6 +176,7 @@ struct nvme_request {
173176
enum {
174177
NVME_REQ_CANCELLED = (1 << 0),
175178
NVME_REQ_USERCMD = (1 << 1),
179+
NVME_MPATH_IO_STATS = (1 << 2),
176180
};
177181

178182
static inline struct nvme_request *nvme_req(struct request *req)
@@ -882,6 +886,8 @@ bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
882886
void nvme_mpath_revalidate_paths(struct nvme_ns *ns);
883887
void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl);
884888
void nvme_mpath_shutdown_disk(struct nvme_ns_head *head);
889+
void nvme_mpath_start_request(struct request *rq);
890+
void nvme_mpath_end_request(struct request *rq);
885891

886892
static inline void nvme_trace_bio_complete(struct request *req)
887893
{
@@ -967,6 +973,12 @@ static inline void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
967973
static inline void nvme_mpath_default_iopolicy(struct nvme_subsystem *subsys)
968974
{
969975
}
976+
static inline void nvme_mpath_start_request(struct request *rq)
977+
{
978+
}
979+
static inline void nvme_mpath_end_request(struct request *rq)
980+
{
981+
}
970982
#endif /* CONFIG_NVME_MULTIPATH */
971983

972984
int nvme_revalidate_zones(struct nvme_ns *ns);
@@ -1014,6 +1026,8 @@ static inline void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
10141026

10151027
static inline void nvme_start_request(struct request *rq)
10161028
{
1029+
if (rq->cmd_flags & REQ_NVME_MPATH)
1030+
nvme_mpath_start_request(rq);
10171031
blk_mq_start_request(rq);
10181032
}
10191033

0 commit comments

Comments
 (0)