diff options
author | James Smart <james.smart@broadcom.com> | 2020-11-15 22:26:30 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2020-11-17 08:43:54 +0300 |
commit | 307e338097dc320afb9f62493a325c7b9208d574 (patch) | |
tree | f132b6b897bd8e2b201fbd9430c6e1aeefaed017 /drivers/scsi/lpfc/lpfc_vport.c | |
parent | 4ab2990a5ce15e6a689f349ba6ab1e6e23df57df (diff) | |
download | linux-307e338097dc320afb9f62493a325c7b9208d574.tar.xz |
scsi: lpfc: Rework remote port ref counting and node freeing
When a remote port is disconnected and disappears, its node structure
(ndlp) stays allocated and on a vport node list. While on the list it can
be matched, thus requires validation checks on state to be added in
numerous code paths. If the node comes back, its possible for there to be
multiple node structures for the same device on the vport node list. There
is no reason to keep the node structure around after it is no longer in
existence, and the current implementation creates problems for itself
(multiple nodes) and lots of unnecessary code for state validation.
Additionally, the reference taking on the node structure didn't follow the
normal model used by the kernel kref api. It included lots of odd logic to
match state with reference count. The combination of this odd logic plus
the way it was implicitly used in the discovery engine made its reference
taking implementation suspect and extremely hard to follow.
Change the driver such that the reference taking routines are now normal
ref increments/decrements and callout on refcount=0.
With this in place, the rework can be done such that the node structure is
fully removed and deallocated when the remote port no longer exists and all
references are removed. This removal logic, and the basic ref counting are
intrically tied, thus in a single patch.
Link: https://lore.kernel.org/r/20201115192646.12977-2-james.smart@broadcom.com
Co-developed-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_vport.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 57 |
1 files changed, 7 insertions, 50 deletions
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index aa4e451d5dc1..6ab78131b94d 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -462,7 +462,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); @@ -495,8 +495,7 @@ disable_vport(struct fc_vport *fc_vport) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && phba->link_state >= LPFC_LINK_UP) { + if (ndlp && phba->link_state >= LPFC_LINK_UP) { vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); if (!lpfc_issue_els_npiv_logo(vport, ndlp)) @@ -510,8 +509,6 @@ disable_vport(struct fc_vport *fc_vport) * calling lpfc_cleanup_rpis(vport, 1) */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; lpfc_disc_state_machine(vport, ndlp, NULL, @@ -568,8 +565,7 @@ enable_vport(struct fc_vport *fc_vport) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); lpfc_initial_fdisc(vport); @@ -663,7 +659,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) * being released. */ ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp) { lpfc_nlp_get(ndlp); ns_ndlp_referenced = true; } @@ -679,26 +675,16 @@ lpfc_vport_delete(struct fc_vport *fc_vport) * can safely skip the fabric logo. */ if (phba->pport->load_flag & FC_UNLOADING) { - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && phba->link_state >= LPFC_LINK_UP) { /* First look for the Fabric ndlp */ ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) goto skip_logo; - else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; - } + /* Remove ndlp from vport npld list */ lpfc_dequeue_node(vport, ndlp); - /* Indicate free memory when release */ - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); /* Kick off release ndlp when it can be safely done */ lpfc_nlp_put(ndlp); } @@ -706,8 +692,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) } /* Otherwise, we will perform fabric logo as needed */ - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && phba->link_state >= LPFC_LINK_UP && phba->fc_topology != LPFC_TOPOLOGY_LOOP) { if (vport->cfg_enable_da_id) { @@ -728,28 +713,6 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ndlp = lpfc_nlp_init(vport, Fabric_DID); if (!ndlp) goto skip_logo; - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - } else { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; - } - - /* Remove ndlp from vport list */ - lpfc_dequeue_node(vport, ndlp); - spin_lock_irq(&phba->ndlp_lock); - if (!NLP_CHK_FREE_REQ(ndlp)) - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - else { - /* Skip this if ndlp is already in free mode */ - spin_unlock_irq(&phba->ndlp_lock); - goto skip_logo; - } - spin_unlock_irq(&phba->ndlp_lock); } /* @@ -865,8 +828,6 @@ lpfc_vport_reset_stat_data(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->lat_data) memset(ndlp->lat_data, 0, LPFC_MAX_BUCKET_COUNT * sizeof(struct lpfc_scsicmd_bkt)); @@ -887,8 +848,6 @@ lpfc_alloc_bucket(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; kfree(ndlp->lat_data); ndlp->lat_data = NULL; @@ -921,8 +880,6 @@ lpfc_free_bucket(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; kfree(ndlp->lat_data); ndlp->lat_data = NULL; |