| From 7993df71c334f02e5e57cebddb8ffabed34647f1 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 30 Jun 2020 14:49:54 -0700 |
| Subject: scsi: lpfc: Fix shost refcount mismatch when deleting vport |
| |
| From: Dick Kennedy <dick.kennedy@broadcom.com> |
| |
| [ Upstream commit 03dbfe0668e6692917ac278883e0586cd7f7d753 ] |
| |
| When vports are deleted, it is observed that there is memory/kthread |
| leakage as the vport isn't fully being released. |
| |
| There is a shost reference taken in scsi_add_host_dma that is not released |
| during scsi_remove_host. It was noticed that other drivers resolve this by |
| doing a scsi_host_put after calling scsi_remove_host. |
| |
| The vport_delete routine is taking two references one that corresponds to |
| an access to the scsi_host in the vport_delete routine and another that is |
| released after the adapter mailbox command completes that destroys the VPI |
| that corresponds to the vport. |
| |
| Remove one of the references taken such that the second reference that is |
| put will complete the missing scsi_add_host_dma reference and the shost |
| will be terminated. |
| |
| Link: https://lore.kernel.org/r/20200630215001.70793-8-jsmart2021@gmail.com |
| Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> |
| Signed-off-by: James Smart <jsmart2021@gmail.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/scsi/lpfc/lpfc_vport.c | 26 ++++++++------------------ |
| 1 file changed, 8 insertions(+), 18 deletions(-) |
| |
| diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c |
| index e18bbc66e83b1..77cb16d8dfd35 100644 |
| --- a/drivers/scsi/lpfc/lpfc_vport.c |
| +++ b/drivers/scsi/lpfc/lpfc_vport.c |
| @@ -624,27 +624,16 @@ lpfc_vport_delete(struct fc_vport *fc_vport) |
| vport->port_state < LPFC_VPORT_READY) |
| return -EAGAIN; |
| } |
| + |
| /* |
| - * This is a bit of a mess. We want to ensure the shost doesn't get |
| - * torn down until we're done with the embedded lpfc_vport structure. |
| - * |
| - * Beyond holding a reference for this function, we also need a |
| - * reference for outstanding I/O requests we schedule during delete |
| - * processing. But once we scsi_remove_host() we can no longer obtain |
| - * a reference through scsi_host_get(). |
| - * |
| - * So we take two references here. We release one reference at the |
| - * bottom of the function -- after delinking the vport. And we |
| - * release the other at the completion of the unreg_vpi that get's |
| - * initiated after we've disposed of all other resources associated |
| - * with the port. |
| + * Take early refcount for outstanding I/O requests we schedule during |
| + * delete processing for unreg_vpi. Always keep this before |
| + * scsi_remove_host() as we can no longer obtain a reference through |
| + * scsi_host_get() after scsi_host_remove as shost is set to SHOST_DEL. |
| */ |
| if (!scsi_host_get(shost)) |
| return VPORT_INVAL; |
| - if (!scsi_host_get(shost)) { |
| - scsi_host_put(shost); |
| - return VPORT_INVAL; |
| - } |
| + |
| lpfc_free_sysfs_attr(vport); |
| |
| lpfc_debugfs_terminate(vport); |
| @@ -792,8 +781,9 @@ skip_logo: |
| if (!(vport->vpi_state & LPFC_VPI_REGISTERED) || |
| lpfc_mbx_unreg_vpi(vport)) |
| scsi_host_put(shost); |
| - } else |
| + } else { |
| scsi_host_put(shost); |
| + } |
| |
| lpfc_free_vpi(phba, vport->vpi); |
| vport->work_port_events = 0; |
| -- |
| 2.25.1 |
| |