From: "Ewan D. Milne" <emilne@xxxxxxxxxx> The atomic updates of ctrl->nr_active are unnecessary when using numa or round-robin iopolicy, so avoid that cost on a per-request basis. Clear nr_active when changing iopolicy and do not decrement below zero. (This handles changing the iopolicy while requests are in flight.) Tested-by: John Meneghini <jmeneghi@xxxxxxxxxx> Signed-off-by: Ewan D. Milne <emilne@xxxxxxxxxx> --- drivers/nvme/host/core.c | 2 +- drivers/nvme/host/multipath.c | 21 ++++++++++++++++++--- drivers/nvme/host/nvme.h | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index a066429b790d..1dd7c52293ff 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -110,7 +110,7 @@ struct workqueue_struct *nvme_delete_wq; EXPORT_SYMBOL_GPL(nvme_delete_wq); static LIST_HEAD(nvme_subsystems); -static DEFINE_MUTEX(nvme_subsystems_lock); +DEFINE_MUTEX(nvme_subsystems_lock); static DEFINE_IDA(nvme_instance_ida); static dev_t nvme_ctrl_base_chr_devt; diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 9e36002d0831..1e9338543ded 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -133,7 +133,8 @@ void nvme_mpath_start_request(struct request *rq) if (!blk_queue_io_stat(disk->queue) || blk_rq_is_passthrough(rq)) return; - atomic_inc(&ns->ctrl->nr_active); + if (READ_ONCE(ns->head->subsys->iopolicy) == NVME_IOPOLICY_QD) + atomic_inc(&ns->ctrl->nr_active); nvme_req(rq)->flags |= NVME_MPATH_IO_STATS; nvme_req(rq)->start_time = bdev_start_io_acct(disk->part0, req_op(rq), jiffies); @@ -147,7 +148,8 @@ void nvme_mpath_end_request(struct request *rq) if (!(nvme_req(rq)->flags & NVME_MPATH_IO_STATS)) return; - atomic_dec(&ns->ctrl->nr_active); + if (READ_ONCE(ns->head->subsys->iopolicy) == NVME_IOPOLICY_QD) + atomic_dec_if_positive(&ns->ctrl->nr_active); bdev_end_io_acct(ns->head->disk->part0, req_op(rq), blk_rq_bytes(rq) >> SECTOR_SHIFT, nvme_req(rq)->start_time); @@ -850,6 +852,19 @@ static ssize_t nvme_subsys_iopolicy_show(struct device *dev, nvme_iopolicy_names[READ_ONCE(subsys->iopolicy)]); } +void nvme_subsys_iopolicy_update(struct nvme_subsystem *subsys, int iopolicy) +{ + struct nvme_ctrl *ctrl; + + WRITE_ONCE(subsys->iopolicy, iopolicy); + + mutex_lock(&nvme_subsystems_lock); + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { + atomic_set(&ctrl->nr_active, 0); + } + mutex_unlock(&nvme_subsystems_lock); +} + static ssize_t nvme_subsys_iopolicy_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -859,7 +874,7 @@ static ssize_t nvme_subsys_iopolicy_store(struct device *dev, for (i = 0; i < ARRAY_SIZE(nvme_iopolicy_names); i++) { if (sysfs_streq(buf, nvme_iopolicy_names[i])) { - WRITE_ONCE(subsys->iopolicy, i); + nvme_subsys_iopolicy_update(subsys, i); return count; } } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index e7d0a56d35d4..4e876524726a 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -50,6 +50,8 @@ extern struct workqueue_struct *nvme_wq; extern struct workqueue_struct *nvme_reset_wq; extern struct workqueue_struct *nvme_delete_wq; +extern struct mutex nvme_subsystems_lock; + /* * List of workarounds for devices that required behavior not specified in * the standard. @@ -937,6 +939,7 @@ void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl); void nvme_mpath_shutdown_disk(struct nvme_ns_head *head); void nvme_mpath_start_request(struct request *rq); void nvme_mpath_end_request(struct request *rq); +void nvme_subsys_iopolicy_update(struct nvme_subsystem *subsys, int iopolicy); static inline void nvme_trace_bio_complete(struct request *req) { @@ -1036,6 +1039,9 @@ static inline bool nvme_disk_is_ns_head(struct gendisk *disk) { return false; } +static inline void nvme_subsys_iopolicy_update(struct nvme_subsystem *subsys, int iopolicy) +{ +} #endif /* CONFIG_NVME_MULTIPATH */ int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector, -- 2.39.3