forked from Minki/linux
scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure
Because of the shifting around of code in qla2x00_probe_one recently,
failures during adapter initialization can lead to problems, i.e. NULL
pointer crashes and doubly freed data structures which cause eventual
panics.
This V2 version makes the relevant memory free routines idempotent, so
repeat calls won't cause any harm. I also removed the problematic
probe_init_failed exit point as it is not needed.
Fixes: d64d6c5671
("scsi: qla2xxx: Fix NULL pointer crash due to probe failure")
Signed-off-by: Bill Kuzeja <william.kuzeja@stratus.com>
Acked-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
4b433924b2
commit
6a2cf8d366
@ -454,7 +454,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
|
|||||||
ha->req_q_map[0] = req;
|
ha->req_q_map[0] = req;
|
||||||
set_bit(0, ha->rsp_qid_map);
|
set_bit(0, ha->rsp_qid_map);
|
||||||
set_bit(0, ha->req_qid_map);
|
set_bit(0, ha->req_qid_map);
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
fail_qpair_map:
|
fail_qpair_map:
|
||||||
kfree(ha->base_qpair);
|
kfree(ha->base_qpair);
|
||||||
@ -471,6 +471,9 @@ fail_req_map:
|
|||||||
|
|
||||||
static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
||||||
{
|
{
|
||||||
|
if (!ha->req_q_map)
|
||||||
|
return;
|
||||||
|
|
||||||
if (IS_QLAFX00(ha)) {
|
if (IS_QLAFX00(ha)) {
|
||||||
if (req && req->ring_fx00)
|
if (req && req->ring_fx00)
|
||||||
dma_free_coherent(&ha->pdev->dev,
|
dma_free_coherent(&ha->pdev->dev,
|
||||||
@ -481,14 +484,17 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
|||||||
(req->length + 1) * sizeof(request_t),
|
(req->length + 1) * sizeof(request_t),
|
||||||
req->ring, req->dma);
|
req->ring, req->dma);
|
||||||
|
|
||||||
if (req)
|
if (req) {
|
||||||
kfree(req->outstanding_cmds);
|
kfree(req->outstanding_cmds);
|
||||||
|
kfree(req);
|
||||||
kfree(req);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
|
static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
|
||||||
{
|
{
|
||||||
|
if (!ha->rsp_q_map)
|
||||||
|
return;
|
||||||
|
|
||||||
if (IS_QLAFX00(ha)) {
|
if (IS_QLAFX00(ha)) {
|
||||||
if (rsp && rsp->ring)
|
if (rsp && rsp->ring)
|
||||||
dma_free_coherent(&ha->pdev->dev,
|
dma_free_coherent(&ha->pdev->dev,
|
||||||
@ -499,7 +505,8 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
|
|||||||
(rsp->length + 1) * sizeof(response_t),
|
(rsp->length + 1) * sizeof(response_t),
|
||||||
rsp->ring, rsp->dma);
|
rsp->ring, rsp->dma);
|
||||||
}
|
}
|
||||||
kfree(rsp);
|
if (rsp)
|
||||||
|
kfree(rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qla2x00_free_queues(struct qla_hw_data *ha)
|
static void qla2x00_free_queues(struct qla_hw_data *ha)
|
||||||
@ -1723,6 +1730,8 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
|
|||||||
struct qla_tgt_cmd *cmd;
|
struct qla_tgt_cmd *cmd;
|
||||||
uint8_t trace = 0;
|
uint8_t trace = 0;
|
||||||
|
|
||||||
|
if (!ha->req_q_map)
|
||||||
|
return;
|
||||||
spin_lock_irqsave(qp->qp_lock_ptr, flags);
|
spin_lock_irqsave(qp->qp_lock_ptr, flags);
|
||||||
req = qp->req;
|
req = qp->req;
|
||||||
for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
|
for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
|
||||||
@ -3095,14 +3104,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||||||
/* Set up the irqs */
|
/* Set up the irqs */
|
||||||
ret = qla2x00_request_irqs(ha, rsp);
|
ret = qla2x00_request_irqs(ha, rsp);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto probe_hw_failed;
|
goto probe_failed;
|
||||||
|
|
||||||
/* Alloc arrays of request and response ring ptrs */
|
/* Alloc arrays of request and response ring ptrs */
|
||||||
if (!qla2x00_alloc_queues(ha, req, rsp)) {
|
if (qla2x00_alloc_queues(ha, req, rsp)) {
|
||||||
ql_log(ql_log_fatal, base_vha, 0x003d,
|
ql_log(ql_log_fatal, base_vha, 0x003d,
|
||||||
"Failed to allocate memory for queue pointers..."
|
"Failed to allocate memory for queue pointers..."
|
||||||
"aborting.\n");
|
"aborting.\n");
|
||||||
goto probe_init_failed;
|
goto probe_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ha->mqenable && shost_use_blk_mq(host)) {
|
if (ha->mqenable && shost_use_blk_mq(host)) {
|
||||||
@ -3387,15 +3396,6 @@ skip_dpc:
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
probe_init_failed:
|
|
||||||
qla2x00_free_req_que(ha, req);
|
|
||||||
ha->req_q_map[0] = NULL;
|
|
||||||
clear_bit(0, ha->req_qid_map);
|
|
||||||
qla2x00_free_rsp_que(ha, rsp);
|
|
||||||
ha->rsp_q_map[0] = NULL;
|
|
||||||
clear_bit(0, ha->rsp_qid_map);
|
|
||||||
ha->max_req_queues = ha->max_rsp_queues = 0;
|
|
||||||
|
|
||||||
probe_failed:
|
probe_failed:
|
||||||
if (base_vha->timer_active)
|
if (base_vha->timer_active)
|
||||||
qla2x00_stop_timer(base_vha);
|
qla2x00_stop_timer(base_vha);
|
||||||
@ -4508,11 +4508,17 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
|||||||
if (ha->init_cb)
|
if (ha->init_cb)
|
||||||
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
|
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
|
||||||
ha->init_cb, ha->init_cb_dma);
|
ha->init_cb, ha->init_cb_dma);
|
||||||
vfree(ha->optrom_buffer);
|
|
||||||
kfree(ha->nvram);
|
if (ha->optrom_buffer)
|
||||||
kfree(ha->npiv_info);
|
vfree(ha->optrom_buffer);
|
||||||
kfree(ha->swl);
|
if (ha->nvram)
|
||||||
kfree(ha->loop_id_map);
|
kfree(ha->nvram);
|
||||||
|
if (ha->npiv_info)
|
||||||
|
kfree(ha->npiv_info);
|
||||||
|
if (ha->swl)
|
||||||
|
kfree(ha->swl);
|
||||||
|
if (ha->loop_id_map)
|
||||||
|
kfree(ha->loop_id_map);
|
||||||
|
|
||||||
ha->srb_mempool = NULL;
|
ha->srb_mempool = NULL;
|
||||||
ha->ctx_mempool = NULL;
|
ha->ctx_mempool = NULL;
|
||||||
@ -4528,6 +4534,15 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
|||||||
ha->ex_init_cb_dma = 0;
|
ha->ex_init_cb_dma = 0;
|
||||||
ha->async_pd = NULL;
|
ha->async_pd = NULL;
|
||||||
ha->async_pd_dma = 0;
|
ha->async_pd_dma = 0;
|
||||||
|
ha->loop_id_map = NULL;
|
||||||
|
ha->npiv_info = NULL;
|
||||||
|
ha->optrom_buffer = NULL;
|
||||||
|
ha->swl = NULL;
|
||||||
|
ha->nvram = NULL;
|
||||||
|
ha->mctp_dump = NULL;
|
||||||
|
ha->dcbx_tlv = NULL;
|
||||||
|
ha->xgmac_data = NULL;
|
||||||
|
ha->sfp_data = NULL;
|
||||||
|
|
||||||
ha->s_dma_pool = NULL;
|
ha->s_dma_pool = NULL;
|
||||||
ha->dl_dma_pool = NULL;
|
ha->dl_dma_pool = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user