NVMe PCI may start a new reset context to run nested reset for recovering from reset context, and we may not change the rule of state machine until other kinds of NVMe controller support that, so use the 'reset_lock' to sync the state change here. Cc: Jianchao Wang <jianchao.w.wang@xxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: Sagi Grimberg <sagi@xxxxxxxxxxx> Cc: linux-nvme@xxxxxxxxxxxxxxxxxxx Cc: Laurence Oberman <loberman@xxxxxxxxxx> Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- drivers/nvme/host/core.c | 20 +++++++++++++++++--- drivers/nvme/host/nvme.h | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 9df4f71e58ca..3aaee4dbf58e 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -100,13 +100,25 @@ static struct class *nvme_subsys_class; static void nvme_ns_remove(struct nvme_ns *ns); static int nvme_revalidate_disk(struct gendisk *disk); +/* + * NVMe PCI may support nested reset for recovering from reset context, + * and we may not change the rule of state machine until other kinds of + * NVMe controller support that, so use the 'reset_lock' to sync the + * state change here. + */ int nvme_reset_ctrl(struct nvme_ctrl *ctrl) { + int ret = -EBUSY; + + mutex_lock(&ctrl->reset_lock); if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) - return -EBUSY; + goto fail; if (!queue_work(nvme_reset_wq, &ctrl->reset_work)) - return -EBUSY; - return 0; + goto fail; + ret = 0; + fail: + mutex_unlock(&ctrl->reset_lock); + return ret; } EXPORT_SYMBOL_GPL(nvme_reset_ctrl); @@ -3447,6 +3459,8 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, INIT_WORK(&ctrl->fw_act_work, nvme_fw_act_work); INIT_WORK(&ctrl->delete_work, nvme_delete_ctrl_work); + mutex_init(&ctrl->reset_lock); + ret = ida_simple_get(&nvme_instance_ida, 0, 0, GFP_KERNEL); if (ret < 0) goto out; diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 061fecfd44f5..99f55c6f69f8 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -146,6 +146,9 @@ struct nvme_ctrl { struct device ctrl_device; struct device *device; /* char device */ struct cdev cdev; + + /* sync reset state update and related reset activities */ + struct mutex reset_lock; struct work_struct reset_work; struct work_struct delete_work; -- 2.9.5