lpfc 8.2.5 : Correct ndlp referencing issues
Subsystems (2)
PATCH 1/6 lpfc 8.2.5 : Correct ndlp referencing issues
Correct ndlp referencing issues:
- Fix ndlp kref issues due to race conditions between threads
- Fix cancel els delay retry event which missed an ndlp reference count
Signed-off-by James Smart <[email protected]>
---
lpfc.h | 2 lpfc_attr.c | 5 lpfc_crtn.h | 6 - lpfc_ct.c | 39 +++++-- lpfc_disc.h | 33 +++++- lpfc_els.c | 237 +++++++++++++++++++++++++++++++------------- lpfc_hbadisc.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++-------- lpfc_init.c | 41 +++++++ lpfc_nportdisc.c | 39 +++++-- lpfc_scsi.c | 4 lpfc_vport.c | 70 +++++++++++-- 11 files changed, 630 insertions(+), 142 deletions(-)
drivers/scsi/lpfc/lpfc_attr.c +3 -2
@@ -1191,7 +1191,7 @@ lpfc_update_rport_devloss_tmo(struct lpf shost =lpfc_shost_from_vport (vport);spin_lock_irq (shost->host_lock);list_for_each_entry (ndlp, &vport->fc_nodes, nlp_listp) -if (ndlp->rport) +if (NLP_CHK_NODE_ACT (ndlp) && ndlp->rport) ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo;spin_unlock_irq (shost->host_lock); }
@@ -2384,7 +2384,8 @@ lpfc_get_node_by_target(struct scsi_targspin_lock_irq (shost->host_lock);/* Search for this, mapped, target ID */ list_for_each_entry (ndlp, &vport->fc_nodes, nlp_listp) { -if (ndlp->nlp_state ==NLP_STE_MAPPED_NODE && +if (NLP_CHK_NODE_ACT (ndlp) && + ndlp->nlp_state ==NLP_STE_MAPPED_NODE && starget->id == ndlp->nlp_sid) {spin_unlock_irq (shost->host_lock);return ndlp;
drivers/scsi/lpfc/lpfc_crtn.h +5 -1
@@ -1,7 +1,7 @@/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * -* Copyright (C) 2004-2007 Emulex. All rights reserved. * +* Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * *
@@ -53,7 +53,11 @@ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_void lpfc_mbx_cmpl_fabric_reg_login (struct lpfc_hba *,LPFC_MBOXQ_t *);void lpfc_mbx_cmpl_ns_reg_login (struct lpfc_hba *,LPFC_MBOXQ_t *);void lpfc_mbx_cmpl_fdmi_reg_login (struct lpfc_hba *,LPFC_MBOXQ_t *); +void lpfc_enqueue_node (struct lpfc_vport *,struct lpfc_nodelist *);void lpfc_dequeue_node (struct lpfc_vport *,struct lpfc_nodelist *); +void lpfc_disable_node (struct lpfc_vport *,struct lpfc_nodelist *); +struct lpfc_nodelist *lpfc_enable_node (struct lpfc_vport *, +struct lpfc_nodelist *,int );void lpfc_nlp_set_state (struct lpfc_vport *,struct lpfc_nodelist *,int );void lpfc_drop_node (struct lpfc_vport *,struct lpfc_nodelist *);void lpfc_set_disctmo (struct lpfc_vport *);
drivers/scsi/lpfc/lpfc_ct.c +29 -10
@@ -1,7 +1,7 @@/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * -* Copyright (C) 2004-2007 Emulex. All rights reserved. * +* Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * *
@@ -294,7 +294,7 @@ lpfc_gen_req(struct lpfc_vport *vport, s/* Save for completion so we can release these resources */ geniocb->context1 = (uint8_t *) inp; geniocb->context2 = (uint8_t *) outp; - geniocb->context_un.ndlp = ndlp; + geniocb->context_un.ndlp =lpfc_nlp_get (ndlp);/* Fill in payload, bp points to frame payload */ icmd->ulpCommand =CMD_GEN_REQUEST64_CR ;
@@ -489,8 +489,10 @@ lpfc_ns_rsp(struct lpfc_vport *vport, st*/ ndlp =lpfc_findnode_did (vport, Did); -if (ndlp && (ndlp->nlp_type & -NLP_FCP_TARGET )) +if (ndlp && +NLP_CHK_NODE_ACT (ndlp) + && (ndlp->nlp_type & +NLP_FCP_TARGET ))lpfc_setup_disc_node (vport, Did); else if (lpfc_ns_cmd(vport,
@@ -1064,7 +1066,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, inint rc =0 ; ndlp =lpfc_findnode_did (vport, NameServer_DID); -if (ndlp ==NULL || ndlp->nlp_state !=NLP_STE_UNMAPPED_NODE ) { +if (!ndlp || !NLP_CHK_NODE_ACT (ndlp) + || ndlp->nlp_state !=NLP_STE_UNMAPPED_NODE ) { rc=1 ; goto ns_cmd_exit; }
@@ -1213,8 +1216,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in cmpl = lpfc_cmpl_ct_cmd_rff_id;break ; } -lpfc_nlp_get (ndlp); - +/* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count +* to hold ndlp reference for the corresponding callback function. +*/ if (!lpfc_ct_cmd (vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {/* On success, The cmpl function will free the buffers */ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
@@ -1222,9 +1226,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in cmdcode, ndlp->nlp_DID, 0);return 0 ; } - rc=6 ; + +/* Decrement ndlp reference count to release ndlp reference held +* for the failed command's callback function. +*/ lpfc_nlp_put (ndlp); +lpfc_mbuf_free (phba, bmp->virt, bmp->phys); ns_cmd_free_bmp:kfree (bmp);
@@ -1271,6 +1279,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *p } ndlp =lpfc_findnode_did (vport,FDMI_DID ); +if (!ndlp || !NLP_CHK_NODE_ACT (ndlp)) + goto fail_out; +if (fdmi_rsp ==be16_to_cpu (SLI_CT_RESPONSE_FS_RJT )) {/* FDMI rsp failed */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
@@ -1294,6 +1305,8 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *plpfc_fdmi_cmd (vport, ndlp,SLI_MGMT_RHBA );break ; } + +fail_out:lpfc_ct_free_iocb (phba, cmdiocb);return ; }
@@ -1650,12 +1663,18 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, bpl->tus.w =le32_to_cpu (bpl->tus.w); cmpl = lpfc_cmpl_ct_cmd_fdmi; -lpfc_nlp_get (ndlp); +/* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count +* to hold ndlp reference for the corresponding callback function. +*/ if (!lpfc_ct_cmd (vport, mp, bmp, ndlp, cmpl,FC_MAX_NS_RSP ,0 ))return 0 ; +/* Decrement ndlp reference count to release ndlp reference held +* for the failed command's callback function. +*/ lpfc_nlp_put (ndlp); +lpfc_mbuf_free (phba, bmp->virt, bmp->phys); fdmi_cmd_free_bmp:kfree (bmp);
@@ -1698,7 +1717,7 @@ lpfc_fdmi_timeout_handler(struct lpfc_vpstruct lpfc_nodelist *ndlp; ndlp =lpfc_findnode_did (vport,FDMI_DID ); -if (ndlp) { +if (ndlp &&NLP_CHK_NODE_ACT (ndlp)) {if (init_utsname ()->nodename[0 ] !='\0' )lpfc_fdmi_cmd (vport, ndlp,SLI_MGMT_DHBA );else
drivers/scsi/lpfc/lpfc_disc.h +32 -1
@@ -1,7 +1,7 @@/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * -* Copyright (C) 2004-2007 Emulex. All rights reserved. * +* Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * *
@@ -73,6 +73,12 @@ struct lpfc_nodelist {uint8_t nlp_fcp_info;/* class info, bits 0-3 */ #define NLP_FCP_2_DEVICE 0x10/* FCP-2 device */ +uint16_t nlp_usg_map;/* ndlp management usage bitmap */ +#define NLP_USG_NODE_ACT_BIT 0x1/* Indicate ndlp is actively used */ +#define NLP_USG_IACT_REQ_BIT 0x2/* Request to inactivate ndlp */ +#define NLP_USG_FREE_REQ_BIT 0x4/* Request to invoke ndlp memory free */ +#define NLP_USG_FREE_ACK_BIT 0x8/* Indicate ndlp memory free invoked */ +struct timer_list nlp_delayfunc;/* Used for delayed ELS cmds */ struct fc_rport *rport;/* Corresponding FC transport port structure */
@@ -105,6 +111,31 @@ struct lpfc_nodelist {#define NLP_NODEV_REMOVE 0x8000000/* Defer removal till discovery ends */ #define NLP_TARGET_REMOVE 0x10000000/* Target remove in process */ +/* ndlp usage management macros */ +#define NLP_CHK_NODE_ACT (ndlp) (((ndlp)->nlp_usg_map \ + & NLP_USG_NODE_ACT_BIT) \ + && \ + !((ndlp)->nlp_usg_map \ + & NLP_USG_FREE_ACK_BIT)) +#define NLP_SET_NODE_ACT (ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_NODE_ACT_BIT) +#define NLP_INT_NODE_ACT (ndlp) ((ndlp)->nlp_usg_map \ + = NLP_USG_NODE_ACT_BIT) +#define NLP_CLR_NODE_ACT (ndlp) ((ndlp)->nlp_usg_map \ + &= ~NLP_USG_NODE_ACT_BIT) +#define NLP_CHK_IACT_REQ (ndlp) ((ndlp)->nlp_usg_map \ + & NLP_USG_IACT_REQ_BIT) +#define NLP_SET_IACT_REQ (ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_IACT_REQ_BIT) +#define NLP_CHK_FREE_REQ (ndlp) ((ndlp)->nlp_usg_map \ + & NLP_USG_FREE_REQ_BIT) +#define NLP_SET_FREE_REQ (ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_FREE_REQ_BIT) +#define NLP_CHK_FREE_ACK (ndlp) ((ndlp)->nlp_usg_map \ + & NLP_USG_FREE_ACK_BIT) +#define NLP_SET_FREE_ACK (ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_FREE_ACK_BIT) +/* There are 4 different double linked lists nodelist entries can reside on. * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used * when Link Up discovery or Registered State Change Notification (RSCN)
drivers/scsi/lpfc/lpfc_els.c +169 -68
558 lines not on this page · raw message
drivers/scsi/lpfc/lpfc.h +2 -0
@@ -595,6 +595,8 @@ struct lpfc_hba {unsigned long last_completion_time;struct timer_list hb_tmofunc;uint8_t hb_outstanding; +/* ndlp reference management */ +spinlock_t ndlp_lock;/* * Following bit will be set for all buffer tags which are not * associated with any HBQ.
drivers/scsi/lpfc/lpfc_hbadisc.c +254 -42
474 lines not on this page · raw message
drivers/scsi/lpfc/lpfc_init.c +40 -1
74 lines not on this page · raw message
drivers/scsi/lpfc/lpfc_nportdisc.c +29 -10
@@ -1,7 +1,7 @@/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * -* Copyright (C) 2004-2007 Emulex. All rights reserved. * +* Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -249,6 +249,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport,struct Scsi_Host *shost =lpfc_shost_from_vport (vport);struct lpfc_hba *phba = vport->phba;struct lpfc_dmabuf *pcmd; +struct lpfc_work_evt *evtp;uint32_t *lp;IOCB_t *icmd;struct serv_parm *sp;
@@ -435,8 +436,14 @@ lpfc_rcv_plogi(struct lpfc_vport *vport,del_timer_sync (&ndlp->nlp_delayfunc); ndlp->nlp_last_elscmd =0 ; -if (!list_empty (&ndlp->els_retry_evt.evt_listp)) +if (!list_empty (&ndlp->els_retry_evt.evt_listp)) {list_del_init (&ndlp->els_retry_evt.evt_listp); +/* Decrement ndlp reference count held for the +* delayed retry +*/ + evtp = &ndlp->els_retry_evt; +lpfc_nlp_put ((struct lpfc_nodelist *)evtp->evt_arg1); + }if (ndlp->nlp_flag &NLP_NPR_2B_DISC ) {spin_lock_irq (shost->host_lock);
@@ -656,7 +663,7 @@ lpfc_disc_illegal(struct lpfc_vport *vpo void *arg, uint32_t evt) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, -"0253 Illegal State Transition: node x%x " +"0271 Illegal State Transition: node x%x " "event x%x, state x%x Data: x%x x%x\n" , ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_flag);
@@ -674,7 +681,7 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vpor*/ if (!(ndlp->nlp_flag &NLP_RCV_PLOGI )) {lpfc_printf_vlog (vport,KERN_ERR ,LOG_DISCOVERY , -"0253 Illegal State Transition: node x%x " +"0272 Illegal State Transition: node x%x " "event x%x, state x%x Data: x%x x%x\n" , ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_flag);
@@ -2144,8 +2151,11 @@ lpfc_disc_state_machine(struct lpfc_vporuint32_t cur_state, rc;uint32_t (*func) (struct lpfc_vport *,struct lpfc_nodelist *,void *,uint32_t ); +uint32_t got_ndlp =0 ; + +if (lpfc_nlp_get (ndlp)) + got_ndlp =1 ; -lpfc_nlp_get (ndlp); cur_state = ndlp->nlp_state;/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
@@ -2162,15 +2172,24 @@ lpfc_disc_state_machine(struct lpfc_vpor rc = (func) (vport, ndlp, arg, evt);/* DSM out state <rc> on NPort <nlp_DID> */ -lpfc_printf_vlog (vport,KERN_INFO ,LOG_DISCOVERY , +if (got_ndlp) { +lpfc_printf_vlog (vport,KERN_INFO ,LOG_DISCOVERY ,"0212 DSM out state %d on NPort x%x Data: x%x\n" , rc, ndlp->nlp_DID, ndlp->nlp_flag); -lpfc_debugfs_disc_trc (vport,LPFC_DISC_TRC_DSM , -"DSM out: ste:%d did:x%x flg:x%x" , - rc, ndlp->nlp_DID, ndlp->nlp_flag); +lpfc_debugfs_disc_trc (vport,LPFC_DISC_TRC_DSM , +"DSM out: ste:%d did:x%x flg:x%x" , + rc, ndlp->nlp_DID, ndlp->nlp_flag); +/* Decrement the ndlp reference count held for this function */ +lpfc_nlp_put (ndlp); + }else { +lpfc_printf_vlog (vport,KERN_INFO ,LOG_DISCOVERY , +"0212 DSM out state %d on NPort free\n" , rc); -lpfc_nlp_put (ndlp); +lpfc_debugfs_disc_trc (vport,LPFC_DISC_TRC_DSM , +"DSM out: ste:%d did:x%x flg:x%x" , + rc,0 ,0 ); + }return rc; }
drivers/scsi/lpfc/lpfc_scsi.c +3 -1
@@ -1,7 +1,7 @@/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * -* Copyright (C) 2004-2007 Emulex. All rights reserved. * +* Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -1283,6 +1283,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd match =0 ;spin_lock_irq (shost->host_lock);list_for_each_entry (ndlp, &vport->fc_nodes, nlp_listp) { +if (!NLP_CHK_NODE_ACT (ndlp)) +continue ;if (ndlp->nlp_state ==NLP_STE_MAPPED_NODE && i == ndlp->nlp_sid && ndlp->rport) {
drivers/scsi/lpfc/lpfc_vport.c +64 -6
122 lines not on this page · raw message