--- /dev/null
+From 5e1f689913a4498e3081093670ef9d85b2c60920 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Thu, 29 Apr 2021 14:18:53 +0200
+Subject: nvme-multipath: fix double initialization of ANA state
+
+From: Christoph Hellwig <hch@lst.de>
+
+commit 5e1f689913a4498e3081093670ef9d85b2c60920 upstream.
+
+nvme_init_identify and thus nvme_mpath_init can be called multiple
+times and thus must not overwrite potentially initialized or in-use
+fields. Split out a helper for the basic initialization when the
+controller is initialized and make sure the init_identify path does
+not blindly change in-use data structures.
+
+Fixes: 0d0b660f214d ("nvme: add ANA support")
+Reported-by: Martin Wilck <mwilck@suse.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <kbusch@kernel.org>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvme/host/core.c | 3 +-
+ drivers/nvme/host/multipath.c | 55 ++++++++++++++++++++++--------------------
+ drivers/nvme/host/nvme.h | 8 ++++--
+ 3 files changed, 37 insertions(+), 29 deletions(-)
+
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -3131,7 +3131,7 @@ int nvme_init_identify(struct nvme_ctrl
+ ctrl->hmmaxd = le16_to_cpu(id->hmmaxd);
+ }
+
+- ret = nvme_mpath_init(ctrl, id);
++ ret = nvme_mpath_init_identify(ctrl, id);
+ kfree(id);
+
+ if (ret < 0)
+@@ -4517,6 +4517,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctr
+ min(default_ps_max_latency_us, (unsigned long)S32_MAX));
+
+ nvme_fault_inject_init(&ctrl->fault_inject, dev_name(ctrl->device));
++ nvme_mpath_init_ctrl(ctrl);
+
+ return 0;
+ out_free_name:
+--- a/drivers/nvme/host/multipath.c
++++ b/drivers/nvme/host/multipath.c
+@@ -708,9 +708,18 @@ void nvme_mpath_remove_disk(struct nvme_
+ put_disk(head->disk);
+ }
+
+-int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
++void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl)
+ {
+- int error;
++ mutex_init(&ctrl->ana_lock);
++ timer_setup(&ctrl->anatt_timer, nvme_anatt_timeout, 0);
++ INIT_WORK(&ctrl->ana_work, nvme_ana_work);
++}
++
++int nvme_mpath_init_identify(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
++{
++ size_t max_transfer_size = ctrl->max_hw_sectors << SECTOR_SHIFT;
++ size_t ana_log_size;
++ int error = 0;
+
+ /* check if multipath is enabled and we have the capability */
+ if (!multipath || !ctrl->subsys ||
+@@ -722,37 +731,31 @@ int nvme_mpath_init(struct nvme_ctrl *ct
+ ctrl->nanagrpid = le32_to_cpu(id->nanagrpid);
+ ctrl->anagrpmax = le32_to_cpu(id->anagrpmax);
+
+- mutex_init(&ctrl->ana_lock);
+- timer_setup(&ctrl->anatt_timer, nvme_anatt_timeout, 0);
+- ctrl->ana_log_size = sizeof(struct nvme_ana_rsp_hdr) +
+- ctrl->nanagrpid * sizeof(struct nvme_ana_group_desc);
+- ctrl->ana_log_size += ctrl->max_namespaces * sizeof(__le32);
+-
+- if (ctrl->ana_log_size > ctrl->max_hw_sectors << SECTOR_SHIFT) {
++ ana_log_size = sizeof(struct nvme_ana_rsp_hdr) +
++ ctrl->nanagrpid * sizeof(struct nvme_ana_group_desc) +
++ ctrl->max_namespaces * sizeof(__le32);
++ if (ana_log_size > max_transfer_size) {
+ dev_err(ctrl->device,
+- "ANA log page size (%zd) larger than MDTS (%d).\n",
+- ctrl->ana_log_size,
+- ctrl->max_hw_sectors << SECTOR_SHIFT);
++ "ANA log page size (%zd) larger than MDTS (%zd).\n",
++ ana_log_size, max_transfer_size);
+ dev_err(ctrl->device, "disabling ANA support.\n");
+- return 0;
++ goto out_uninit;
+ }
+-
+- INIT_WORK(&ctrl->ana_work, nvme_ana_work);
+- kfree(ctrl->ana_log_buf);
+- ctrl->ana_log_buf = kmalloc(ctrl->ana_log_size, GFP_KERNEL);
+- if (!ctrl->ana_log_buf) {
+- error = -ENOMEM;
+- goto out;
++ if (ana_log_size > ctrl->ana_log_size) {
++ nvme_mpath_stop(ctrl);
++ kfree(ctrl->ana_log_buf);
++ ctrl->ana_log_buf = kmalloc(ctrl->ana_log_size, GFP_KERNEL);
++ if (!ctrl->ana_log_buf)
++ return -ENOMEM;
+ }
+-
++ ctrl->ana_log_size = ana_log_size;
+ error = nvme_read_ana_log(ctrl);
+ if (error)
+- goto out_free_ana_log_buf;
++ goto out_uninit;
+ return 0;
+-out_free_ana_log_buf:
+- kfree(ctrl->ana_log_buf);
+- ctrl->ana_log_buf = NULL;
+-out:
++
++out_uninit:
++ nvme_mpath_uninit(ctrl);
+ return error;
+ }
+
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -654,7 +654,8 @@ void nvme_kick_requeue_lists(struct nvme
+ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
+ void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id);
+ void nvme_mpath_remove_disk(struct nvme_ns_head *head);
+-int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id);
++int nvme_mpath_init_identify(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id);
++void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl);
+ void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
+ void nvme_mpath_stop(struct nvme_ctrl *ctrl);
+ bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
+@@ -730,7 +731,10 @@ static inline void nvme_trace_bio_comple
+ blk_status_t status)
+ {
+ }
+-static inline int nvme_mpath_init(struct nvme_ctrl *ctrl,
++static inline void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl)
++{
++}
++static inline int nvme_mpath_init_identify(struct nvme_ctrl *ctrl,
+ struct nvme_id_ctrl *id)
+ {
+ if (ctrl->subsys->cmic & (1 << 3))