Skip to content

Commit 5e1f689

Browse files
author
Christoph Hellwig
committed
nvme-multipath: fix double initialization of ANA state
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: 0d0b660 ("nvme: add ANA support") Reported-by: Martin Wilck <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Keith Busch <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]>
1 parent efed9a3 commit 5e1f689

File tree

3 files changed

+37
-29
lines changed

3 files changed

+37
-29
lines changed

drivers/nvme/host/core.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2901,7 +2901,7 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
29012901
ctrl->hmmaxd = le16_to_cpu(id->hmmaxd);
29022902
}
29032903

2904-
ret = nvme_mpath_init(ctrl, id);
2904+
ret = nvme_mpath_init_identify(ctrl, id);
29052905
if (ret < 0)
29062906
goto out_free;
29072907

@@ -4364,6 +4364,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
43644364
min(default_ps_max_latency_us, (unsigned long)S32_MAX));
43654365

43664366
nvme_fault_inject_init(&ctrl->fault_inject, dev_name(ctrl->device));
4367+
nvme_mpath_init_ctrl(ctrl);
43674368

43684369
return 0;
43694370
out_free_name:

drivers/nvme/host/multipath.c

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -781,9 +781,18 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
781781
put_disk(head->disk);
782782
}
783783

784-
int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
784+
void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl)
785785
{
786-
int error;
786+
mutex_init(&ctrl->ana_lock);
787+
timer_setup(&ctrl->anatt_timer, nvme_anatt_timeout, 0);
788+
INIT_WORK(&ctrl->ana_work, nvme_ana_work);
789+
}
790+
791+
int nvme_mpath_init_identify(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
792+
{
793+
size_t max_transfer_size = ctrl->max_hw_sectors << SECTOR_SHIFT;
794+
size_t ana_log_size;
795+
int error = 0;
787796

788797
/* check if multipath is enabled and we have the capability */
789798
if (!multipath || !ctrl->subsys ||
@@ -795,37 +804,31 @@ int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
795804
ctrl->nanagrpid = le32_to_cpu(id->nanagrpid);
796805
ctrl->anagrpmax = le32_to_cpu(id->anagrpmax);
797806

798-
mutex_init(&ctrl->ana_lock);
799-
timer_setup(&ctrl->anatt_timer, nvme_anatt_timeout, 0);
800-
ctrl->ana_log_size = sizeof(struct nvme_ana_rsp_hdr) +
801-
ctrl->nanagrpid * sizeof(struct nvme_ana_group_desc);
802-
ctrl->ana_log_size += ctrl->max_namespaces * sizeof(__le32);
803-
804-
if (ctrl->ana_log_size > ctrl->max_hw_sectors << SECTOR_SHIFT) {
807+
ana_log_size = sizeof(struct nvme_ana_rsp_hdr) +
808+
ctrl->nanagrpid * sizeof(struct nvme_ana_group_desc) +
809+
ctrl->max_namespaces * sizeof(__le32);
810+
if (ana_log_size > max_transfer_size) {
805811
dev_err(ctrl->device,
806-
"ANA log page size (%zd) larger than MDTS (%d).\n",
807-
ctrl->ana_log_size,
808-
ctrl->max_hw_sectors << SECTOR_SHIFT);
812+
"ANA log page size (%zd) larger than MDTS (%zd).\n",
813+
ana_log_size, max_transfer_size);
809814
dev_err(ctrl->device, "disabling ANA support.\n");
810-
return 0;
815+
goto out_uninit;
811816
}
812-
813-
INIT_WORK(&ctrl->ana_work, nvme_ana_work);
814-
kfree(ctrl->ana_log_buf);
815-
ctrl->ana_log_buf = kmalloc(ctrl->ana_log_size, GFP_KERNEL);
816-
if (!ctrl->ana_log_buf) {
817-
error = -ENOMEM;
818-
goto out;
817+
if (ana_log_size > ctrl->ana_log_size) {
818+
nvme_mpath_stop(ctrl);
819+
kfree(ctrl->ana_log_buf);
820+
ctrl->ana_log_buf = kmalloc(ctrl->ana_log_size, GFP_KERNEL);
821+
if (!ctrl->ana_log_buf)
822+
return -ENOMEM;
819823
}
820-
824+
ctrl->ana_log_size = ana_log_size;
821825
error = nvme_read_ana_log(ctrl);
822826
if (error)
823-
goto out_free_ana_log_buf;
827+
goto out_uninit;
824828
return 0;
825-
out_free_ana_log_buf:
826-
kfree(ctrl->ana_log_buf);
827-
ctrl->ana_log_buf = NULL;
828-
out:
829+
830+
out_uninit:
831+
nvme_mpath_uninit(ctrl);
829832
return error;
830833
}
831834

drivers/nvme/host/nvme.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,8 @@ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl);
712712
int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
713713
void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id);
714714
void nvme_mpath_remove_disk(struct nvme_ns_head *head);
715-
int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id);
715+
int nvme_mpath_init_identify(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id);
716+
void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl);
716717
void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
717718
void nvme_mpath_stop(struct nvme_ctrl *ctrl);
718719
bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
@@ -780,7 +781,10 @@ static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
780781
static inline void nvme_trace_bio_complete(struct request *req)
781782
{
782783
}
783-
static inline int nvme_mpath_init(struct nvme_ctrl *ctrl,
784+
static inline void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl)
785+
{
786+
}
787+
static inline int nvme_mpath_init_identify(struct nvme_ctrl *ctrl,
784788
struct nvme_id_ctrl *id)
785789
{
786790
if (ctrl->subsys->cmic & NVME_CTRL_CMIC_ANA)

0 commit comments

Comments
 (0)