Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e47c9093 authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] 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: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 4660c8ed
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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.
+3 −2
Original line number Diff line number Diff line
@@ -1191,7 +1191,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
	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_target *starget)
	spin_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;
+5 −1
Original line number Diff line number Diff line
/*******************************************************************
 * 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_hba *, LPFC_MBOXQ_t *);
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 *);
+29 −10
Original line number Diff line number Diff line
/*******************************************************************
 * 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, struct lpfc_dmabuf *bmp,
	/* 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,7 +489,9 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
						 */
						ndlp = lpfc_findnode_did(vport,
							Did);
						if (ndlp && (ndlp->nlp_type &
						if (ndlp &&
						    NLP_CHK_NODE_ACT(ndlp)
						    && (ndlp->nlp_type &
						     NLP_FCP_TARGET))
							lpfc_setup_disc_node
								(vport, Did);
@@ -1064,7 +1066,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
	int 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, int cmdcode,
		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, int cmdcode,
			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 *phba, struct lpfc_iocbq *cmdiocb,
	}

	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 *phba, struct lpfc_iocbq *cmdiocb,
		lpfc_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, struct lpfc_nodelist *ndlp, int cmdcode)
	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_vport *vport)
	struct 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
+32 −1
Original line number Diff line number Diff line
/*******************************************************************
 * 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)
Loading