[PATCH] scsi: qedf: Add missing checks for create_workqueue

From: Jiasheng Jiang
Date: Tue Feb 07 2023 - 21:07:07 EST


Add the checks for the return value of the create_workqueue in order to
avoid NULL pointer dereference.
Moreover, the allocated "qedf->link_update_wq" should be destroyed when
__qedf_probe fails later in order to avoid memory leak.

Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.")
Signed-off-by: Jiasheng Jiang <jiasheng@xxxxxxxxxxx>
---
drivers/scsi/qedf/qedf_main.c | 56 ++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index 35e16600fc63..ff90291530a7 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -3360,6 +3360,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
sprintf(host_buf, "qedf_%u_link",
qedf->lport->host->host_no);
qedf->link_update_wq = create_workqueue(host_buf);
+ if (!qedf->link_update_wq) {
+ QEDF_ERR(&(qedf->dbg_ctx), "Failed to link workqueue.\n");
+ rc = -ENOMEM;
+ goto err1;
+ }
INIT_DELAYED_WORK(&qedf->link_update, qedf_handle_link_update);
INIT_DELAYED_WORK(&qedf->link_recovery, qedf_link_recovery);
INIT_DELAYED_WORK(&qedf->grcdump_work, qedf_wq_grcdump);
@@ -3394,14 +3399,14 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
}
QEDF_ERR(&qedf->dbg_ctx, "common probe failed.\n");
rc = -ENODEV;
- goto err1;
+ goto err2;
}

/* Learn information crucial for qedf to progress */
rc = qed_ops->fill_dev_info(qedf->cdev, &qedf->dev_info);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to dev info.\n");
- goto err1;
+ goto err2;
}

QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
@@ -3420,7 +3425,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
rc = qedf_set_fcoe_pf_param(qedf);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Cannot set fcoe pf param.\n");
- goto err2;
+ goto err3;
}
qed_ops->common->update_pf_params(qedf->cdev, &qedf->pf_params);

@@ -3428,7 +3433,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
rc = qed_ops->fill_dev_info(qedf->cdev, &qedf->dev_info);
if (rc) {
QEDF_ERR(&qedf->dbg_ctx, "Failed to fill dev info.\n");
- goto err2;
+ goto err3;
}

if (mode != QEDF_MODE_RECOVERY) {
@@ -3437,7 +3442,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
QEDF_ERR(&qedf->dbg_ctx, "Cannot register devlink\n");
rc = PTR_ERR(qedf->devlink);
qedf->devlink = NULL;
- goto err2;
+ goto err3;
}
}

@@ -3454,7 +3459,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
if (rc) {

QEDF_ERR(&(qedf->dbg_ctx), "Cannot start slowpath.\n");
- goto err2;
+ goto err3;
}

/* Start the Slowpath-process */
@@ -3467,7 +3472,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
rc = qed_ops->common->slowpath_start(qedf->cdev, &slowpath_params);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Cannot start slowpath.\n");
- goto err2;
+ goto err3;
}

/*
@@ -3480,13 +3485,13 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
rc = qedf_setup_int(qedf);
if (rc) {
QEDF_ERR(&qedf->dbg_ctx, "Setup interrupts failed.\n");
- goto err3;
+ goto err4;
}

rc = qed_ops->start(qedf->cdev, &qedf->tasks);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Cannot start FCoE function.\n");
- goto err4;
+ goto err5;
}
task_start = qedf_get_task_mem(&qedf->tasks, 0);
task_end = qedf_get_task_mem(&qedf->tasks, MAX_TID_BLOCKS_FCOE - 1);
@@ -3546,7 +3551,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
if (!qedf->cmd_mgr) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to allocate cmd mgr.\n");
rc = -ENOMEM;
- goto err5;
+ goto err6;
}

if (mode != QEDF_MODE_RECOVERY) {
@@ -3559,7 +3564,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
if (rc) {
QEDF_WARN(&qedf->dbg_ctx,
"Error adding Scsi_Host rc=0x%x.\n", rc);
- goto err6;
+ goto err7;
}
}

@@ -3574,7 +3579,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
if (!qedf->ll2_recv_wq) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to LL2 workqueue.\n");
rc = -ENOMEM;
- goto err7;
+ goto err8;
}

#ifdef CONFIG_DEBUG_FS
@@ -3587,7 +3592,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
rc = qed_ops->ll2->start(qedf->cdev, &params);
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx), "Could not start Light L2.\n");
- goto err7;
+ goto err8;
}
set_bit(QEDF_LL2_STARTED, &qedf->flags);

@@ -3607,7 +3612,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
if (rc) {
QEDF_ERR(&(qedf->dbg_ctx),
"qedf_lport_setup failed.\n");
- goto err7;
+ goto err8;
}
}

@@ -3618,7 +3623,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
QEDF_ERR(&(qedf->dbg_ctx), "Failed to start timer "
"workqueue.\n");
rc = -ENOMEM;
- goto err7;
+ goto err8;
}

/* DPC workqueue is not reaped during recovery unload */
@@ -3626,6 +3631,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
sprintf(host_buf, "qedf_%u_dpc",
qedf->lport->host->host_no);
qedf->dpc_wq = create_workqueue(host_buf);
+ if (!qedf->dpc_wq) {
+ QEDF_ERR(&(qedf->dbg_ctx), "Failed to dpc workqueue.\n");
+ rc = -ENOMEM;
+ goto err9;
+ }
}
INIT_DELAYED_WORK(&qedf->recovery_work, qedf_recovery_handler);

@@ -3682,7 +3692,9 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
/* All good */
return 0;

-err7:
+err9:
+ destroy_workqueue(qedf->timer_work_queue);
+err8:
if (qedf->ll2_recv_wq)
destroy_workqueue(qedf->ll2_recv_wq);
fc_remove_host(qedf->lport->host);
@@ -3690,17 +3702,19 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
#ifdef CONFIG_DEBUG_FS
qedf_dbg_host_exit(&(qedf->dbg_ctx));
#endif
-err6:
+err7:
qedf_cmd_mgr_free(qedf->cmd_mgr);
-err5:
+err6:
qed_ops->stop(qedf->cdev);
-err4:
+err5:
qedf_free_fcoe_pf_param(qedf);
qedf_sync_free_irqs(qedf);
-err3:
+err4:
qed_ops->common->slowpath_stop(qedf->cdev);
-err2:
+err3:
qed_ops->common->remove(qedf->cdev);
+err2:
+ destroy_workqueue(qedf->link_update_wq);
err1:
scsi_host_put(lport->host);
err0:
--
2.25.1