Commit d5ff0eed authored by Joe Carnuccio's avatar Joe Carnuccio Committed by Martin K. Petersen

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: default avatarJoe Carnuccio <joe.carnuccio@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 74939a0b
...@@ -129,28 +129,16 @@ qla2x00_clear_loop_id(fc_port_t *fcport) { ...@@ -129,28 +129,16 @@ qla2x00_clear_loop_id(fc_port_t *fcport) {
} }
static inline void static inline void
qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp, qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx)
struct qla_tgt_cmd *tc)
{ {
struct dsd_dma *dsd_ptr, *tdsd_ptr; struct dsd_dma *dsd, *tdsd;
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;
}
/* clean up allocated prev pool */ /* clean up allocated prev pool */
list_for_each_entry_safe(dsd_ptr, tdsd_ptr, list_for_each_entry_safe(dsd, tdsd, &ctx->dsd_list, list) {
&ctx->dsd_list, list) { dma_pool_free(ha->dl_dma_pool, dsd->dsd_addr,
dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr, dsd->dsd_list_dma);
dsd_ptr->dsd_list_dma); list_del(&dsd->list);
list_del(&dsd_ptr->list); kfree(dsd);
kfree(dsd_ptr);
} }
INIT_LIST_HEAD(&ctx->dsd_list); INIT_LIST_HEAD(&ctx->dsd_list);
} }
......
...@@ -630,29 +630,34 @@ qla2x00_sp_free_dma(void *ptr) ...@@ -630,29 +630,34 @@ qla2x00_sp_free_dma(void *ptr)
sp->flags &= ~SRB_CRC_PROT_DMA_VALID; sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
} }
if (!ctx)
goto end;
if (sp->flags & SRB_CRC_CTX_DSD_VALID) { if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
/* List assured to be having elements */ /* 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; sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
} }
if (sp->flags & SRB_CRC_CTX_DMA_VALID) { if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
dma_pool_free(ha->dl_dma_pool, ctx, struct crc_context *ctx0 = ctx;
((struct crc_context *)ctx)->crc_ctx_dma);
dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma);
sp->flags &= ~SRB_CRC_CTX_DMA_VALID; sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
} }
if (sp->flags & SRB_FCP_CMND_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, dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
ctx1->fcp_cmnd_dma); ctx1->fcp_cmnd_dma);
list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
ha->gbl_dsd_avail += ctx1->dsd_use_cnt; ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
mempool_free(ctx1, ha->ctx_mempool); mempool_free(ctx1, ha->ctx_mempool);
} }
end:
CMD_SP(cmd) = NULL; CMD_SP(cmd) = NULL;
qla2x00_rel_sp(sp); qla2x00_rel_sp(sp);
} }
...@@ -699,21 +704,24 @@ qla2xxx_qpair_sp_free_dma(void *ptr) ...@@ -699,21 +704,24 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
sp->flags &= ~SRB_CRC_PROT_DMA_VALID; sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
} }
if (!ctx)
goto end;
if (sp->flags & SRB_CRC_CTX_DSD_VALID) { if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
/* List assured to be having elements */ /* 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; sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
} }
if (sp->flags & SRB_CRC_CTX_DMA_VALID) { if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
dma_pool_free(ha->dl_dma_pool, ctx, struct crc_context *ctx0 = ctx;
((struct crc_context *)ctx)->crc_ctx_dma);
dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma);
sp->flags &= ~SRB_CRC_CTX_DMA_VALID; sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
} }
if (sp->flags & SRB_FCP_CMND_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, dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
ctx1->fcp_cmnd_dma); ctx1->fcp_cmnd_dma);
list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
...@@ -721,7 +729,7 @@ qla2xxx_qpair_sp_free_dma(void *ptr) ...@@ -721,7 +729,7 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
ha->gbl_dsd_avail += ctx1->dsd_use_cnt; ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
mempool_free(ctx1, ha->ctx_mempool); mempool_free(ctx1, ha->ctx_mempool);
} }
end:
CMD_SP(cmd) = NULL; CMD_SP(cmd) = NULL;
qla2xxx_rel_qpair_sp(sp->qpair, sp); qla2xxx_rel_qpair_sp(sp->qpair, sp);
} }
......
...@@ -2245,11 +2245,13 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) ...@@ -2245,11 +2245,13 @@ 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, pci_unmap_sg(ha->pdev, cmd->prot_sg, cmd->prot_sg_cnt,
cmd->dma_data_direction); cmd->dma_data_direction);
if (!cmd->ctx)
return;
if (cmd->ctx_dsd_alloced) if (cmd->ctx_dsd_alloced)
qla2x00_clean_dsd_pool(ha, NULL, cmd); qla2x00_clean_dsd_pool(ha, cmd->ctx);
if (cmd->ctx) dma_pool_free(ha->dl_dma_pool, cmd->ctx, cmd->ctx->crc_ctx_dma);
dma_pool_free(ha->dl_dma_pool, cmd->ctx, cmd->ctx->crc_ctx_dma);
} }
static int qlt_check_reserve_free_req(struct scsi_qla_host *vha, static int qlt_check_reserve_free_req(struct scsi_qla_host *vha,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment