scsi: qla2xxx: Fix crash due to NULL pointer dereference of ctx

Fixes following signature in the stack trace:

BUG: unable to handle kernel NULL pointer dereference at 0000000000000374
IP: [<ffffffffa06ec8eb>] qla2x00_sp_free_dma+0xeb/0x2a0 [qla2xxx]

Cc: <stable@vger.kernel.org> # v4.10+
Signed-off-by: Joe Carnuccio <joe.carnuccio@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Joe Carnuccio 2017-05-24 18:06:24 -07:00 committed by Martin K. Petersen
parent 74939a0bc7
commit d5ff0eed3a
3 changed files with 32 additions and 34 deletions

View File

@ -129,28 +129,16 @@ qla2x00_clear_loop_id(fc_port_t *fcport) {
}
static inline void
qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp,
struct qla_tgt_cmd *tc)
qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx)
{
struct dsd_dma *dsd_ptr, *tdsd_ptr;
struct crc_context *ctx;
if (sp)
ctx = (struct crc_context *)GET_CMD_CTX_SP(sp);
else if (tc)
ctx = (struct crc_context *)tc->ctx;
else {
BUG();
return;
}
struct dsd_dma *dsd, *tdsd;
/* clean up allocated prev pool */
list_for_each_entry_safe(dsd_ptr, tdsd_ptr,
&ctx->dsd_list, list) {
dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr,
dsd_ptr->dsd_list_dma);
list_del(&dsd_ptr->list);
kfree(dsd_ptr);
list_for_each_entry_safe(dsd, tdsd, &ctx->dsd_list, list) {
dma_pool_free(ha->dl_dma_pool, dsd->dsd_addr,
dsd->dsd_list_dma);
list_del(&dsd->list);
kfree(dsd);
}
INIT_LIST_HEAD(&ctx->dsd_list);
}

View File

@ -630,20 +630,24 @@ qla2x00_sp_free_dma(void *ptr)
sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
}
if (!ctx)
goto end;
if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
/* List assured to be having elements */
qla2x00_clean_dsd_pool(ha, sp, NULL);
qla2x00_clean_dsd_pool(ha, ctx);
sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
}
if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
dma_pool_free(ha->dl_dma_pool, ctx,
((struct crc_context *)ctx)->crc_ctx_dma);
struct crc_context *ctx0 = ctx;
dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma);
sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
}
if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
struct ct6_dsd *ctx1 = (struct ct6_dsd *)ctx;
struct ct6_dsd *ctx1 = ctx;
dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
ctx1->fcp_cmnd_dma);
@ -653,6 +657,7 @@ qla2x00_sp_free_dma(void *ptr)
mempool_free(ctx1, ha->ctx_mempool);
}
end:
CMD_SP(cmd) = NULL;
qla2x00_rel_sp(sp);
}
@ -699,21 +704,24 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
}
if (!ctx)
goto end;
if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
/* List assured to be having elements */
qla2x00_clean_dsd_pool(ha, sp, NULL);
qla2x00_clean_dsd_pool(ha, ctx);
sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
}
if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
dma_pool_free(ha->dl_dma_pool, ctx,
((struct crc_context *)ctx)->crc_ctx_dma);
struct crc_context *ctx0 = ctx;
dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma);
sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
}
if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
struct ct6_dsd *ctx1 = (struct ct6_dsd *)ctx;
struct ct6_dsd *ctx1 = ctx;
dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
ctx1->fcp_cmnd_dma);
list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
@ -721,7 +729,7 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
mempool_free(ctx1, ha->ctx_mempool);
}
end:
CMD_SP(cmd) = NULL;
qla2xxx_rel_qpair_sp(sp->qpair, sp);
}

View File

@ -2245,10 +2245,12 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
pci_unmap_sg(ha->pdev, cmd->prot_sg, cmd->prot_sg_cnt,
cmd->dma_data_direction);
if (cmd->ctx_dsd_alloced)
qla2x00_clean_dsd_pool(ha, NULL, cmd);
if (!cmd->ctx)
return;
if (cmd->ctx_dsd_alloced)
qla2x00_clean_dsd_pool(ha, cmd->ctx);
if (cmd->ctx)
dma_pool_free(ha->dl_dma_pool, cmd->ctx, cmd->ctx->crc_ctx_dma);
}