Skip to content

Commit

Permalink
scsi: lpfc: nvmet: avoid hang / use-after-free when destroying target…
Browse files Browse the repository at this point in the history
…port

[ Upstream commit c41f59884be5cca293ed61f3d64637dbba3a6381 ]

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: Ewan D. Milne <[email protected]>
Acked-by: James Smart <[email protected]>
Signed-off-by: Martin K. Petersen <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
  • Loading branch information
Ewan D. Milne authored and gregkh committed Mar 5, 2019
1 parent 30b6265 commit ee2a02a
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 4 deletions.
8 changes: 5 additions & 3 deletions drivers/scsi/lpfc/lpfc_nvmet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,8 @@ lpfc_nvmet_targetport_delete(struct nvmet_fc_target_port *targetport)
struct lpfc_nvmet_tgtport *tport = targetport->private;

/* 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
Expand Down Expand Up @@ -1700,6 +1701,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
struct lpfc_nvmet_tgtport *tgtp;
struct lpfc_queue *wq;
uint32_t qidx;
DECLARE_COMPLETION_ONSTACK(tport_unreg_cmp);

if (phba->nvmet_support == 0)
return;
Expand All @@ -1709,9 +1711,9 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
wq = phba->sli4_hba.nvme_wq[qidx];
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);
wait_for_completion_timeout(&tgtp->tport_unreg_done, 5);
wait_for_completion_timeout(&tport_unreg_cmp, 5);
lpfc_nvmet_cleanup_io_context(phba);
}
phba->targetport = NULL;
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/lpfc/lpfc_nvmet.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
/* Used for NVME Target */
struct lpfc_nvmet_tgtport {
struct lpfc_hba *phba;
struct completion tport_unreg_done;
struct completion *tport_unreg_cmp;

/* Stats counters - lpfc_nvmet_unsol_ls_buffer */
atomic_t rcv_ls_req_in;
Expand Down

0 comments on commit ee2a02a

Please sign in to comment.