Commit c41f5988 authored by Ewan D. Milne's avatar Ewan D. Milne Committed by Martin K. Petersen

scsi: lpfc: nvmet: avoid hang / use-after-free when destroying targetport

We cannot wait on a completion object in the lpfc_nvme_targetport structure
in the _destroy_targetport() code path because the NVMe/fc transport will
free that structure immediately after the .targetport_delete() callback.
This results in a use-after-free, and a hang if slub_debug=FZPU is enabled.

Fix this by putting the completion on the stack.
Signed-off-by: default avatarEwan D. Milne <emilne@redhat.com>
Acked-by: default avatarJames Smart <james.smart@broadcom.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 7961cba6
...@@ -1003,7 +1003,8 @@ lpfc_nvmet_targetport_delete(struct nvmet_fc_target_port *targetport) ...@@ -1003,7 +1003,8 @@ lpfc_nvmet_targetport_delete(struct nvmet_fc_target_port *targetport)
struct lpfc_nvmet_tgtport *tport = targetport->private; struct lpfc_nvmet_tgtport *tport = targetport->private;
/* release any threads waiting for the unreg to complete */ /* release any threads waiting for the unreg to complete */
complete(&tport->tport_unreg_done); if (tport->phba->targetport)
complete(tport->tport_unreg_cmp);
} }
static void static void
...@@ -1692,6 +1693,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) ...@@ -1692,6 +1693,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
struct lpfc_nvmet_tgtport *tgtp; struct lpfc_nvmet_tgtport *tgtp;
struct lpfc_queue *wq; struct lpfc_queue *wq;
uint32_t qidx; uint32_t qidx;
DECLARE_COMPLETION_ONSTACK(tport_unreg_cmp);
if (phba->nvmet_support == 0) if (phba->nvmet_support == 0)
return; return;
...@@ -1701,9 +1703,9 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) ...@@ -1701,9 +1703,9 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
wq = phba->sli4_hba.nvme_wq[qidx]; wq = phba->sli4_hba.nvme_wq[qidx];
lpfc_nvmet_wqfull_flush(phba, wq, NULL); lpfc_nvmet_wqfull_flush(phba, wq, NULL);
} }
init_completion(&tgtp->tport_unreg_done); tgtp->tport_unreg_cmp = &tport_unreg_cmp;
nvmet_fc_unregister_targetport(phba->targetport); nvmet_fc_unregister_targetport(phba->targetport);
wait_for_completion_timeout(&tgtp->tport_unreg_done, 5); wait_for_completion_timeout(&tport_unreg_cmp, 5);
lpfc_nvmet_cleanup_io_context(phba); lpfc_nvmet_cleanup_io_context(phba);
} }
phba->targetport = NULL; phba->targetport = NULL;
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
/* Used for NVME Target */ /* Used for NVME Target */
struct lpfc_nvmet_tgtport { struct lpfc_nvmet_tgtport {
struct lpfc_hba *phba; struct lpfc_hba *phba;
struct completion tport_unreg_done; struct completion *tport_unreg_cmp;
/* Stats counters - lpfc_nvmet_unsol_ls_buffer */ /* Stats counters - lpfc_nvmet_unsol_ls_buffer */
atomic_t rcv_ls_req_in; atomic_t rcv_ls_req_in;
......
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