diff mbox series

[13/17] lpfc: Protect vport fc_nodes list with an explicit spin lock

Message ID 20240131003549.147784-14-justintee8345@gmail.com (mailing list archive)
State Superseded
Headers show
Series lpfc: Update lpfc to revision 14.4.0.0 | expand

Commit Message

Justin Tee Jan. 31, 2024, 12:35 a.m. UTC
In attempt to reduce the amount of unnecessary shost_lock acquisitions in
the lpfc driver, replace shost_lock with an explicit fc_nodes_list_lock
spinlock when accessing vport->fc_nodes lists.  Although vport memory
region is owned by shost->hostdata, it is driver private memory and an
explicit fc_nodes list lock for fc_nodes list mutations is more appropriate
than locking the entire shost.

Signed-off-by: Justin Tee <justin.tee@broadcom.com>
---
 drivers/scsi/lpfc/lpfc.h         |  1 +
 drivers/scsi/lpfc/lpfc_attr.c    | 35 +++++++++++-----------
 drivers/scsi/lpfc/lpfc_ct.c      |  7 ++---
 drivers/scsi/lpfc/lpfc_debugfs.c | 12 ++++----
 drivers/scsi/lpfc/lpfc_hbadisc.c | 50 ++++++++++++++++----------------
 drivers/scsi/lpfc/lpfc_init.c    |  2 +-
 6 files changed, 53 insertions(+), 54 deletions(-)

Comments

Himanshu Madhani Jan. 31, 2024, 2:50 a.m. UTC | #1
On 1/30/24 16:35, Justin Tee wrote:
> In attempt to reduce the amount of unnecessary shost_lock acquisitions in
> the lpfc driver, replace shost_lock with an explicit fc_nodes_list_lock
> spinlock when accessing vport->fc_nodes lists.  Although vport memory
> region is owned by shost->hostdata, it is driver private memory and an
> explicit fc_nodes list lock for fc_nodes list mutations is more appropriate
> than locking the entire shost.
> 
> Signed-off-by: Justin Tee <justin.tee@broadcom.com>
> ---
>   drivers/scsi/lpfc/lpfc.h         |  1 +
>   drivers/scsi/lpfc/lpfc_attr.c    | 35 +++++++++++-----------
>   drivers/scsi/lpfc/lpfc_ct.c      |  7 ++---
>   drivers/scsi/lpfc/lpfc_debugfs.c | 12 ++++----
>   drivers/scsi/lpfc/lpfc_hbadisc.c | 50 ++++++++++++++++----------------
>   drivers/scsi/lpfc/lpfc_init.c    |  2 +-
>   6 files changed, 53 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
> index 8f3cac09a381..da9f87f89941 100644
> --- a/drivers/scsi/lpfc/lpfc.h
> +++ b/drivers/scsi/lpfc/lpfc.h
> @@ -587,6 +587,7 @@ struct lpfc_vport {
>   #define FC_CT_RPRT_DEFER	0x20	 /* Defer issuing FDMI RPRT */
>   
>   	struct list_head fc_nodes;
> +	spinlock_t fc_nodes_list_lock; /* spinlock for fc_nodes list */
>   
>   	/* Keep counters for the number of entries in each list. */
>   	atomic_t fc_plogi_cnt;
> diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
> index 142c90eb210f..023f4f2c62a6 100644
> --- a/drivers/scsi/lpfc/lpfc_attr.c
> +++ b/drivers/scsi/lpfc/lpfc_attr.c
> @@ -344,6 +344,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
>   	struct lpfc_fc4_ctrl_stat *cstat;
>   	uint64_t data1, data2, data3;
>   	uint64_t totin, totout, tot;
> +	unsigned long iflags;
>   	char *statep;
>   	int i;
>   	int len = 0;
> @@ -543,7 +544,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
>   	if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
>   		goto buffer_done;
>   
> -	spin_lock_irq(shost->host_lock);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   
>   	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
>   		nrport = NULL;
> @@ -617,7 +618,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
>   		if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
>   			goto unlock_buf_done;
>   	}
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   
>   	if (!lport)
>   		goto buffer_done;
> @@ -681,7 +682,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
>   	goto buffer_done;
>   
>    unlock_buf_done:
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   
>    buffer_done:
>   	len = strnlen(buf, PAGE_SIZE);
> @@ -3765,15 +3766,14 @@ lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val)
>   static void
>   lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
>   {
> -	struct Scsi_Host  *shost;
>   	struct lpfc_nodelist  *ndlp;
> +	unsigned long iflags;
>   #if (IS_ENABLED(CONFIG_NVME_FC))
>   	struct lpfc_nvme_rport *rport;
>   	struct nvme_fc_remote_port *remoteport = NULL;
>   #endif
>   
> -	shost = lpfc_shost_from_vport(vport);
> -	spin_lock_irq(shost->host_lock);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
>   		if (ndlp->rport)
>   			ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo;
> @@ -3788,7 +3788,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
>   						       vport->cfg_devloss_tmo);
>   #endif
>   	}
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   }
>   
>   /**
> @@ -3974,8 +3974,8 @@ lpfc_vport_param_init(tgt_queue_depth, LPFC_MAX_TGT_QDEPTH,
>   static int
>   lpfc_tgt_queue_depth_set(struct lpfc_vport *vport, uint val)
>   {
> -	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
>   	struct lpfc_nodelist *ndlp;
> +	unsigned long iflags;
>   
>   	if (!lpfc_rangecheck(val, LPFC_MIN_TGT_QDEPTH, LPFC_MAX_TGT_QDEPTH))
>   		return -EINVAL;
> @@ -3983,14 +3983,13 @@ lpfc_tgt_queue_depth_set(struct lpfc_vport *vport, uint val)
>   	if (val == vport->cfg_tgt_queue_depth)
>   		return 0;
>   
> -	spin_lock_irq(shost->host_lock);
>   	vport->cfg_tgt_queue_depth = val;
>   
>   	/* Next loop thru nodelist and change cmd_qdepth */
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
>   		ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
> -
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   	return 0;
>   }
>   
> @@ -5236,8 +5235,8 @@ lpfc_vport_param_show(max_scsicmpl_time);
>   static int
>   lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
>   {
> -	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
>   	struct lpfc_nodelist *ndlp, *next_ndlp;
> +	unsigned long iflags;
>   
>   	if (val == vport->cfg_max_scsicmpl_time)
>   		return 0;
> @@ -5245,13 +5244,13 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
>   		return -EINVAL;
>   	vport->cfg_max_scsicmpl_time = val;
>   
> -	spin_lock_irq(shost->host_lock);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
>   		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
>   			continue;
>   		ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
>   	}
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   	return 0;
>   }
>   lpfc_vport_param_store(max_scsicmpl_time);
> @@ -6853,17 +6852,19 @@ lpfc_get_node_by_target(struct scsi_target *starget)
>   	struct Scsi_Host  *shost = dev_to_shost(starget->dev.parent);
>   	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
>   	struct lpfc_nodelist *ndlp;
> +	unsigned long iflags;
>   
> -	spin_lock_irq(shost->host_lock);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	/* Search for this, mapped, target ID */
>   	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
>   		if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
>   		    starget->id == ndlp->nlp_sid) {
> -			spin_unlock_irq(shost->host_lock);
> +			spin_unlock_irqrestore(&vport->fc_nodes_list_lock,
> +					       iflags);
>   			return ndlp;
>   		}
>   	}
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   	return NULL;
>   }
>   
> diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
> index 315db836404a..633b8ba25bc3 100644
> --- a/drivers/scsi/lpfc/lpfc_ct.c
> +++ b/drivers/scsi/lpfc/lpfc_ct.c
> @@ -1853,11 +1853,10 @@ static uint32_t
>   lpfc_find_map_node(struct lpfc_vport *vport)
>   {
>   	struct lpfc_nodelist *ndlp, *next_ndlp;
> -	struct Scsi_Host  *shost;
> +	unsigned long iflags;
>   	uint32_t cnt = 0;
>   
> -	shost = lpfc_shost_from_vport(vport);
> -	spin_lock_irq(shost->host_lock);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
>   		if (ndlp->nlp_type & NLP_FABRIC)
>   			continue;
> @@ -1865,7 +1864,7 @@ lpfc_find_map_node(struct lpfc_vport *vport)
>   		    (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE))
>   			cnt++;
>   	}
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   	return cnt;
>   }
>   
> diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
> index ea9b42225e62..03abc401c5f2 100644
> --- a/drivers/scsi/lpfc/lpfc_debugfs.c
> +++ b/drivers/scsi/lpfc/lpfc_debugfs.c
> @@ -806,10 +806,10 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
>   {
>   	int len = 0;
>   	int i, iocnt, outio, cnt;
> -	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
>   	struct lpfc_hba  *phba = vport->phba;
>   	struct lpfc_nodelist *ndlp;
>   	unsigned char *statep;
> +	unsigned long iflags;
>   	struct nvme_fc_local_port *localport;
>   	struct nvme_fc_remote_port *nrport = NULL;
>   	struct lpfc_nvme_rport *rport;
> @@ -818,7 +818,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
>   	outio = 0;
>   
>   	len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n");
> -	spin_lock_irq(shost->host_lock);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
>   		iocnt = 0;
>   		if (!cnt) {
> @@ -908,7 +908,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
>   					 ndlp->nlp_defer_did);
>   		len +=  scnprintf(buf+len, size-len, "\n");
>   	}
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   
>   	len += scnprintf(buf + len, size - len,
>   			"\nOutstanding IO x%x\n",  outio);
> @@ -940,8 +940,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
>   	if (!localport)
>   		goto out_exit;
>   
> -	spin_lock_irq(shost->host_lock);
> -
>   	/* Port state is only one of two values for now. */
>   	if (localport->port_id)
>   		statep = "ONLINE";
> @@ -953,6 +951,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
>   			localport->port_id, statep);
>   
>   	len += scnprintf(buf + len, size - len, "\tRport List:\n");
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
>   		/* local short-hand pointer. */
>   		spin_lock(&ndlp->lock);
> @@ -1006,8 +1005,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
>   		/* Terminate the string. */
>   		len +=  scnprintf(buf + len, size - len, "\n");
>   	}
> -
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>    out_exit:
>   	return len;
>   }
> diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
> index 7c4356d87730..08acd5d398aa 100644
> --- a/drivers/scsi/lpfc/lpfc_hbadisc.c
> +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
> @@ -4860,10 +4860,10 @@ void
>   lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
>   		   int state)
>   {
> -	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
>   	int  old_state = ndlp->nlp_state;
>   	int node_dropped = ndlp->nlp_flag & NLP_DROPPED;
>   	char name1[16], name2[16];
> +	unsigned long iflags;
>   
>   	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
>   			 "0904 NPort state transition x%06x, %s -> %s\n",
> @@ -4890,9 +4890,9 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
>   	}
>   
>   	if (list_empty(&ndlp->nlp_listp)) {
> -		spin_lock_irq(shost->host_lock);
> +		spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
> -		spin_unlock_irq(shost->host_lock);
> +		spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   	} else if (old_state)
>   		lpfc_nlp_counters(vport, old_state, -1);
>   
> @@ -4904,26 +4904,26 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
>   void
>   lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
>   {
> -	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
> +	unsigned long iflags;
>   
>   	if (list_empty(&ndlp->nlp_listp)) {
> -		spin_lock_irq(shost->host_lock);
> +		spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
> -		spin_unlock_irq(shost->host_lock);
> +		spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   	}
>   }
>   
>   void
>   lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
>   {
> -	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
> +	unsigned long iflags;
>   
>   	lpfc_cancel_retry_delay_tmo(vport, ndlp);
>   	if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
>   		lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
> -	spin_lock_irq(shost->host_lock);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   	list_del_init(&ndlp->nlp_listp);
> -	spin_unlock_irq(shost->host_lock);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   	lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
>   				NLP_STE_UNUSED_NODE);
>   }
> @@ -5421,8 +5421,8 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
>   {
>   	struct lpfc_vport **vports;
>   	struct lpfc_nodelist *ndlp;
> -	struct Scsi_Host *shost;
>   	int i;
> +	unsigned long iflags;
>   
>   	vports = lpfc_create_vport_work_array(phba);
>   	if (!vports) {
> @@ -5431,17 +5431,18 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
>   		return;
>   	}
>   	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
> -		shost = lpfc_shost_from_vport(vports[i]);
> -		spin_lock_irq(shost->host_lock);
> +		spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags);
>   		list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
>   			if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
>   				/* The mempool_alloc might sleep */
> -				spin_unlock_irq(shost->host_lock);
> +				spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock,
> +						       iflags);
>   				lpfc_unreg_rpi(vports[i], ndlp);
> -				spin_lock_irq(shost->host_lock);
> +				spin_lock_irqsave(&vports[i]->fc_nodes_list_lock,
> +						  iflags);
>   			}
>   		}
> -		spin_unlock_irq(shost->host_lock);
> +		spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags);
>   	}
>   	lpfc_destroy_vport_work_array(phba, vports);
>   }
> @@ -5683,12 +5684,11 @@ lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
>   struct lpfc_nodelist *
>   lpfc_findnode_mapped(struct lpfc_vport *vport)
>   {
> -	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
>   	struct lpfc_nodelist *ndlp;
>   	uint32_t data1;
>   	unsigned long iflags;
>   
> -	spin_lock_irqsave(shost->host_lock, iflags);
> +	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
>   
>   	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
>   		if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE ||
> @@ -5697,7 +5697,8 @@ lpfc_findnode_mapped(struct lpfc_vport *vport)
>   				 ((uint32_t)ndlp->nlp_xri << 16) |
>   				 ((uint32_t)ndlp->nlp_type << 8) |
>   				 ((uint32_t)ndlp->nlp_rpi & 0xff));
> -			spin_unlock_irqrestore(shost->host_lock, iflags);
> +			spin_unlock_irqrestore(&vport->fc_nodes_list_lock,
> +					       iflags);
>   			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE_VERBOSE,
>   					 "2025 FIND node DID MAPPED "
>   					 "Data: x%px x%x x%x x%x x%px\n",
> @@ -5707,7 +5708,7 @@ lpfc_findnode_mapped(struct lpfc_vport *vport)
>   			return ndlp;
>   		}
>   	}
> -	spin_unlock_irqrestore(shost->host_lock, iflags);
> +	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
>   
>   	/* FIND node did <did> NOT FOUND */
>   	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
> @@ -6742,7 +6743,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
>   	struct lpfc_vport **vports;
>   	int i, ret = 0;
>   	struct lpfc_nodelist *ndlp;
> -	struct Scsi_Host  *shost;
> +	unsigned long iflags;
>   
>   	vports = lpfc_create_vport_work_array(phba);
>   
> @@ -6751,8 +6752,6 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
>   		return 1;
>   
>   	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
> -		shost = lpfc_shost_from_vport(vports[i]);
> -		spin_lock_irq(shost->host_lock);
>   		/*
>   		 * IF the CVL_RCVD bit is not set then we have sent the
>   		 * flogi.
> @@ -6760,15 +6759,16 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
>   		 * unreg the fcf.
>   		 */
>   		if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) {
> -			spin_unlock_irq(shost->host_lock);
>   			ret =  1;
>   			goto out;
>   		}
> +		spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags);
>   		list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
>   			if (ndlp->rport &&
>   			  (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
>   				ret = 1;
> -				spin_unlock_irq(shost->host_lock);
> +				spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock,
> +						       iflags);
>   				goto out;
>   			} else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
>   				ret = 1;
> @@ -6780,7 +6780,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
>   						ndlp->nlp_flag);
>   			}
>   		}
> -		spin_unlock_irq(shost->host_lock);
> +		spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags);
>   	}
>   out:
>   	lpfc_destroy_vport_work_array(phba, vports);
> diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
> index 1285a7bbdced..c43118fab4aa 100644
> --- a/drivers/scsi/lpfc/lpfc_init.c
> +++ b/drivers/scsi/lpfc/lpfc_init.c
> @@ -3829,7 +3829,6 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
>   			vports[i]->fc_flag &= ~FC_VFI_REGISTERED;
>   			spin_unlock_irq(shost->host_lock);
>   
> -			shost =	lpfc_shost_from_vport(vports[i]);
>   			list_for_each_entry_safe(ndlp, next_ndlp,
>   						 &vports[i]->fc_nodes,
>   						 nlp_listp) {
> @@ -4833,6 +4832,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
>   
>   	/* Initialize all internally managed lists. */
>   	INIT_LIST_HEAD(&vport->fc_nodes);
> +	spin_lock_init(&vport->fc_nodes_list_lock);
>   	INIT_LIST_HEAD(&vport->rcv_buffer_list);
>   	spin_lock_init(&vport->work_port_lock);
>   

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
diff mbox series

Patch

diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 8f3cac09a381..da9f87f89941 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -587,6 +587,7 @@  struct lpfc_vport {
 #define FC_CT_RPRT_DEFER	0x20	 /* Defer issuing FDMI RPRT */
 
 	struct list_head fc_nodes;
+	spinlock_t fc_nodes_list_lock; /* spinlock for fc_nodes list */
 
 	/* Keep counters for the number of entries in each list. */
 	atomic_t fc_plogi_cnt;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 142c90eb210f..023f4f2c62a6 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -344,6 +344,7 @@  lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
 	struct lpfc_fc4_ctrl_stat *cstat;
 	uint64_t data1, data2, data3;
 	uint64_t totin, totout, tot;
+	unsigned long iflags;
 	char *statep;
 	int i;
 	int len = 0;
@@ -543,7 +544,7 @@  lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
 	if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
 		goto buffer_done;
 
-	spin_lock_irq(shost->host_lock);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
 		nrport = NULL;
@@ -617,7 +618,7 @@  lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
 		if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
 			goto unlock_buf_done;
 	}
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 
 	if (!lport)
 		goto buffer_done;
@@ -681,7 +682,7 @@  lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
 	goto buffer_done;
 
  unlock_buf_done:
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 
  buffer_done:
 	len = strnlen(buf, PAGE_SIZE);
@@ -3765,15 +3766,14 @@  lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val)
 static void
 lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
 {
-	struct Scsi_Host  *shost;
 	struct lpfc_nodelist  *ndlp;
+	unsigned long iflags;
 #if (IS_ENABLED(CONFIG_NVME_FC))
 	struct lpfc_nvme_rport *rport;
 	struct nvme_fc_remote_port *remoteport = NULL;
 #endif
 
-	shost = lpfc_shost_from_vport(vport);
-	spin_lock_irq(shost->host_lock);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
 		if (ndlp->rport)
 			ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo;
@@ -3788,7 +3788,7 @@  lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
 						       vport->cfg_devloss_tmo);
 #endif
 	}
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 }
 
 /**
@@ -3974,8 +3974,8 @@  lpfc_vport_param_init(tgt_queue_depth, LPFC_MAX_TGT_QDEPTH,
 static int
 lpfc_tgt_queue_depth_set(struct lpfc_vport *vport, uint val)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_nodelist *ndlp;
+	unsigned long iflags;
 
 	if (!lpfc_rangecheck(val, LPFC_MIN_TGT_QDEPTH, LPFC_MAX_TGT_QDEPTH))
 		return -EINVAL;
@@ -3983,14 +3983,13 @@  lpfc_tgt_queue_depth_set(struct lpfc_vport *vport, uint val)
 	if (val == vport->cfg_tgt_queue_depth)
 		return 0;
 
-	spin_lock_irq(shost->host_lock);
 	vport->cfg_tgt_queue_depth = val;
 
 	/* Next loop thru nodelist and change cmd_qdepth */
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
 		ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
-
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 	return 0;
 }
 
@@ -5236,8 +5235,8 @@  lpfc_vport_param_show(max_scsicmpl_time);
 static int
 lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_nodelist *ndlp, *next_ndlp;
+	unsigned long iflags;
 
 	if (val == vport->cfg_max_scsicmpl_time)
 		return 0;
@@ -5245,13 +5244,13 @@  lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
 		return -EINVAL;
 	vport->cfg_max_scsicmpl_time = val;
 
-	spin_lock_irq(shost->host_lock);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
 			continue;
 		ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
 	}
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 	return 0;
 }
 lpfc_vport_param_store(max_scsicmpl_time);
@@ -6853,17 +6852,19 @@  lpfc_get_node_by_target(struct scsi_target *starget)
 	struct Scsi_Host  *shost = dev_to_shost(starget->dev.parent);
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_nodelist *ndlp;
+	unsigned long iflags;
 
-	spin_lock_irq(shost->host_lock);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	/* Search for this, mapped, target ID */
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
 		if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
 		    starget->id == ndlp->nlp_sid) {
-			spin_unlock_irq(shost->host_lock);
+			spin_unlock_irqrestore(&vport->fc_nodes_list_lock,
+					       iflags);
 			return ndlp;
 		}
 	}
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 	return NULL;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 315db836404a..633b8ba25bc3 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1853,11 +1853,10 @@  static uint32_t
 lpfc_find_map_node(struct lpfc_vport *vport)
 {
 	struct lpfc_nodelist *ndlp, *next_ndlp;
-	struct Scsi_Host  *shost;
+	unsigned long iflags;
 	uint32_t cnt = 0;
 
-	shost = lpfc_shost_from_vport(vport);
-	spin_lock_irq(shost->host_lock);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
 		if (ndlp->nlp_type & NLP_FABRIC)
 			continue;
@@ -1865,7 +1864,7 @@  lpfc_find_map_node(struct lpfc_vport *vport)
 		    (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE))
 			cnt++;
 	}
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 	return cnt;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index ea9b42225e62..03abc401c5f2 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -806,10 +806,10 @@  lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
 {
 	int len = 0;
 	int i, iocnt, outio, cnt;
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 	struct lpfc_nodelist *ndlp;
 	unsigned char *statep;
+	unsigned long iflags;
 	struct nvme_fc_local_port *localport;
 	struct nvme_fc_remote_port *nrport = NULL;
 	struct lpfc_nvme_rport *rport;
@@ -818,7 +818,7 @@  lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
 	outio = 0;
 
 	len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n");
-	spin_lock_irq(shost->host_lock);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
 		iocnt = 0;
 		if (!cnt) {
@@ -908,7 +908,7 @@  lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
 					 ndlp->nlp_defer_did);
 		len +=  scnprintf(buf+len, size-len, "\n");
 	}
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 
 	len += scnprintf(buf + len, size - len,
 			"\nOutstanding IO x%x\n",  outio);
@@ -940,8 +940,6 @@  lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
 	if (!localport)
 		goto out_exit;
 
-	spin_lock_irq(shost->host_lock);
-
 	/* Port state is only one of two values for now. */
 	if (localport->port_id)
 		statep = "ONLINE";
@@ -953,6 +951,7 @@  lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
 			localport->port_id, statep);
 
 	len += scnprintf(buf + len, size - len, "\tRport List:\n");
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
 		/* local short-hand pointer. */
 		spin_lock(&ndlp->lock);
@@ -1006,8 +1005,7 @@  lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
 		/* Terminate the string. */
 		len +=  scnprintf(buf + len, size - len, "\n");
 	}
-
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
  out_exit:
 	return len;
 }
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 7c4356d87730..08acd5d398aa 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -4860,10 +4860,10 @@  void
 lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		   int state)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	int  old_state = ndlp->nlp_state;
 	int node_dropped = ndlp->nlp_flag & NLP_DROPPED;
 	char name1[16], name2[16];
+	unsigned long iflags;
 
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
 			 "0904 NPort state transition x%06x, %s -> %s\n",
@@ -4890,9 +4890,9 @@  lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	}
 
 	if (list_empty(&ndlp->nlp_listp)) {
-		spin_lock_irq(shost->host_lock);
+		spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
-		spin_unlock_irq(shost->host_lock);
+		spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 	} else if (old_state)
 		lpfc_nlp_counters(vport, old_state, -1);
 
@@ -4904,26 +4904,26 @@  lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 void
 lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+	unsigned long iflags;
 
 	if (list_empty(&ndlp->nlp_listp)) {
-		spin_lock_irq(shost->host_lock);
+		spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
-		spin_unlock_irq(shost->host_lock);
+		spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 	}
 }
 
 void
 lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+	unsigned long iflags;
 
 	lpfc_cancel_retry_delay_tmo(vport, ndlp);
 	if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
 		lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
-	spin_lock_irq(shost->host_lock);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 	list_del_init(&ndlp->nlp_listp);
-	spin_unlock_irq(shost->host_lock);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 	lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
 				NLP_STE_UNUSED_NODE);
 }
@@ -5421,8 +5421,8 @@  lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
 {
 	struct lpfc_vport **vports;
 	struct lpfc_nodelist *ndlp;
-	struct Scsi_Host *shost;
 	int i;
+	unsigned long iflags;
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (!vports) {
@@ -5431,17 +5431,18 @@  lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
 		return;
 	}
 	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
-		shost = lpfc_shost_from_vport(vports[i]);
-		spin_lock_irq(shost->host_lock);
+		spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags);
 		list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
 			if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
 				/* The mempool_alloc might sleep */
-				spin_unlock_irq(shost->host_lock);
+				spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock,
+						       iflags);
 				lpfc_unreg_rpi(vports[i], ndlp);
-				spin_lock_irq(shost->host_lock);
+				spin_lock_irqsave(&vports[i]->fc_nodes_list_lock,
+						  iflags);
 			}
 		}
-		spin_unlock_irq(shost->host_lock);
+		spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags);
 	}
 	lpfc_destroy_vport_work_array(phba, vports);
 }
@@ -5683,12 +5684,11 @@  lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
 struct lpfc_nodelist *
 lpfc_findnode_mapped(struct lpfc_vport *vport)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_nodelist *ndlp;
 	uint32_t data1;
 	unsigned long iflags;
 
-	spin_lock_irqsave(shost->host_lock, iflags);
+	spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
 
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
 		if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE ||
@@ -5697,7 +5697,8 @@  lpfc_findnode_mapped(struct lpfc_vport *vport)
 				 ((uint32_t)ndlp->nlp_xri << 16) |
 				 ((uint32_t)ndlp->nlp_type << 8) |
 				 ((uint32_t)ndlp->nlp_rpi & 0xff));
-			spin_unlock_irqrestore(shost->host_lock, iflags);
+			spin_unlock_irqrestore(&vport->fc_nodes_list_lock,
+					       iflags);
 			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE_VERBOSE,
 					 "2025 FIND node DID MAPPED "
 					 "Data: x%px x%x x%x x%x x%px\n",
@@ -5707,7 +5708,7 @@  lpfc_findnode_mapped(struct lpfc_vport *vport)
 			return ndlp;
 		}
 	}
-	spin_unlock_irqrestore(shost->host_lock, iflags);
+	spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
 
 	/* FIND node did <did> NOT FOUND */
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
@@ -6742,7 +6743,7 @@  lpfc_fcf_inuse(struct lpfc_hba *phba)
 	struct lpfc_vport **vports;
 	int i, ret = 0;
 	struct lpfc_nodelist *ndlp;
-	struct Scsi_Host  *shost;
+	unsigned long iflags;
 
 	vports = lpfc_create_vport_work_array(phba);
 
@@ -6751,8 +6752,6 @@  lpfc_fcf_inuse(struct lpfc_hba *phba)
 		return 1;
 
 	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
-		shost = lpfc_shost_from_vport(vports[i]);
-		spin_lock_irq(shost->host_lock);
 		/*
 		 * IF the CVL_RCVD bit is not set then we have sent the
 		 * flogi.
@@ -6760,15 +6759,16 @@  lpfc_fcf_inuse(struct lpfc_hba *phba)
 		 * unreg the fcf.
 		 */
 		if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) {
-			spin_unlock_irq(shost->host_lock);
 			ret =  1;
 			goto out;
 		}
+		spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags);
 		list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
 			if (ndlp->rport &&
 			  (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
 				ret = 1;
-				spin_unlock_irq(shost->host_lock);
+				spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock,
+						       iflags);
 				goto out;
 			} else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
 				ret = 1;
@@ -6780,7 +6780,7 @@  lpfc_fcf_inuse(struct lpfc_hba *phba)
 						ndlp->nlp_flag);
 			}
 		}
-		spin_unlock_irq(shost->host_lock);
+		spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags);
 	}
 out:
 	lpfc_destroy_vport_work_array(phba, vports);
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 1285a7bbdced..c43118fab4aa 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -3829,7 +3829,6 @@  lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
 			vports[i]->fc_flag &= ~FC_VFI_REGISTERED;
 			spin_unlock_irq(shost->host_lock);
 
-			shost =	lpfc_shost_from_vport(vports[i]);
 			list_for_each_entry_safe(ndlp, next_ndlp,
 						 &vports[i]->fc_nodes,
 						 nlp_listp) {
@@ -4833,6 +4832,7 @@  lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 
 	/* Initialize all internally managed lists. */
 	INIT_LIST_HEAD(&vport->fc_nodes);
+	spin_lock_init(&vport->fc_nodes_list_lock);
 	INIT_LIST_HEAD(&vport->rcv_buffer_list);
 	spin_lock_init(&vport->work_port_lock);