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 <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Sagi Grimberg <[email protected]>
Cc: [email protected]
Cc: Laurence Oberman <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
 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

Reply via email to