aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <james.smart@avagotech.com>2015-05-21 13:55:28 -0400
committerJames Bottomley <JBottomley@Odin.com>2015-06-06 01:40:19 -0400
commit466e840b7809e00ab3a1af9b4a5b5751e681730d (patch)
tree149a3be013344fda727df0f00086b77d5b0bc07b
parente5abba4c6aa7f094d32c0115193516697da60df8 (diff)
lpfc: Fix rport leak.
Correct locking and refcounting in tracking our rports Signed-off-by: Dick Kennedy <dick.kennedy@avagotech.com> Signed-off-by: James Smart <james.smart@avagotech.com> Signed-off-by: James Bottomley <JBottomley@Odin.com>
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c12
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c145
3 files changed, 79 insertions, 82 deletions
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 6977027979be..361f5b3d9d93 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -79,7 +79,6 @@ struct lpfc_nodelist {
79 struct lpfc_name nlp_portname; 79 struct lpfc_name nlp_portname;
80 struct lpfc_name nlp_nodename; 80 struct lpfc_name nlp_nodename;
81 uint32_t nlp_flag; /* entry flags */ 81 uint32_t nlp_flag; /* entry flags */
82 uint32_t nlp_add_flag; /* additional flags */
83 uint32_t nlp_DID; /* FC D_ID of entry */ 82 uint32_t nlp_DID; /* FC D_ID of entry */
84 uint32_t nlp_last_elscmd; /* Last ELS cmd sent */ 83 uint32_t nlp_last_elscmd; /* Last ELS cmd sent */
85 uint16_t nlp_type; 84 uint16_t nlp_type;
@@ -147,6 +146,7 @@ struct lpfc_node_rrq {
147#define NLP_LOGO_ACC 0x00100000 /* Process LOGO after ACC completes */ 146#define NLP_LOGO_ACC 0x00100000 /* Process LOGO after ACC completes */
148#define NLP_TGT_NO_SCSIID 0x00200000 /* good PRLI but no binding for scsid */ 147#define NLP_TGT_NO_SCSIID 0x00200000 /* good PRLI but no binding for scsid */
149#define NLP_ISSUE_LOGO 0x00400000 /* waiting to issue a LOGO */ 148#define NLP_ISSUE_LOGO 0x00400000 /* waiting to issue a LOGO */
149#define NLP_IN_DEV_LOSS 0x00800000 /* devloss in progress */
150#define NLP_ACC_REGLOGIN 0x01000000 /* Issue Reg Login after successful 150#define NLP_ACC_REGLOGIN 0x01000000 /* Issue Reg Login after successful
151 ACC */ 151 ACC */
152#define NLP_NPR_ADISC 0x02000000 /* Issue ADISC when dq'ed from 152#define NLP_NPR_ADISC 0x02000000 /* Issue ADISC when dq'ed from
@@ -158,8 +158,6 @@ struct lpfc_node_rrq {
158#define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */ 158#define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */
159#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */ 159#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */
160 160
161/* Defines for nlp_add_flag (uint32) */
162#define NLP_IN_DEV_LOSS 0x00000001 /* Dev Loss processing in progress */
163 161
164/* ndlp usage management macros */ 162/* ndlp usage management macros */
165#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \ 163#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 4d3d931b177a..011c8d8dba0b 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1624,8 +1624,9 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
1624 if (rport) { 1624 if (rport) {
1625 rdata = rport->dd_data; 1625 rdata = rport->dd_data;
1626 if (rdata->pnode == ndlp) { 1626 if (rdata->pnode == ndlp) {
1627 lpfc_nlp_put(ndlp); 1627 /* break the link before dropping the ref */
1628 ndlp->rport = NULL; 1628 ndlp->rport = NULL;
1629 lpfc_nlp_put(ndlp);
1629 rdata->pnode = lpfc_nlp_get(new_ndlp); 1630 rdata->pnode = lpfc_nlp_get(new_ndlp);
1630 new_ndlp->rport = rport; 1631 new_ndlp->rport = rport;
1631 } 1632 }
@@ -3674,6 +3675,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
3674 * Remove the ndlp reference if it's a fabric node that has 3675 * Remove the ndlp reference if it's a fabric node that has
3675 * sent us an unsolicted LOGO. 3676 * sent us an unsolicted LOGO.
3676 */ 3677 */
3678 /* FIXME: this one frees ndlp before breaking rport link */
3677 if (ndlp->nlp_type & NLP_FABRIC) 3679 if (ndlp->nlp_type & NLP_FABRIC)
3678 lpfc_nlp_put(ndlp); 3680 lpfc_nlp_put(ndlp);
3679 3681
@@ -7351,8 +7353,13 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
7351 * Do not process any unsolicited ELS commands 7353 * Do not process any unsolicited ELS commands
7352 * if the ndlp is in DEV_LOSS 7354 * if the ndlp is in DEV_LOSS
7353 */ 7355 */
7354 if (ndlp->nlp_add_flag & NLP_IN_DEV_LOSS) 7356 shost = lpfc_shost_from_vport(vport);
7357 spin_lock_irq(shost->host_lock);
7358 if (ndlp->nlp_flag & NLP_IN_DEV_LOSS) {
7359 spin_unlock_irq(shost->host_lock);
7355 goto dropit; 7360 goto dropit;
7361 }
7362 spin_unlock_irq(shost->host_lock);
7356 7363
7357 elsiocb->context1 = lpfc_nlp_get(ndlp); 7364 elsiocb->context1 = lpfc_nlp_get(ndlp);
7358 elsiocb->vport = vport; 7365 elsiocb->vport = vport;
@@ -7396,7 +7403,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
7396 rjt_exp = LSEXP_NOTHING_MORE; 7403 rjt_exp = LSEXP_NOTHING_MORE;
7397 break; 7404 break;
7398 } 7405 }
7399 shost = lpfc_shost_from_vport(vport);
7400 if (vport->port_state < LPFC_DISC_AUTH) { 7406 if (vport->port_state < LPFC_DISC_AUTH) {
7401 if (!(phba->pport->fc_flag & FC_PT2PT) || 7407 if (!(phba->pport->fc_flag & FC_PT2PT) ||
7402 (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { 7408 (phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 0dfa56604c91..88af258147d0 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -106,6 +106,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
106 struct lpfc_rport_data *rdata; 106 struct lpfc_rport_data *rdata;
107 struct lpfc_nodelist * ndlp; 107 struct lpfc_nodelist * ndlp;
108 struct lpfc_vport *vport; 108 struct lpfc_vport *vport;
109 struct Scsi_Host *shost;
109 struct lpfc_hba *phba; 110 struct lpfc_hba *phba;
110 struct lpfc_work_evt *evtp; 111 struct lpfc_work_evt *evtp;
111 int put_node; 112 int put_node;
@@ -146,49 +147,32 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
146 if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) 147 if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
147 return; 148 return;
148 149
149 if (ndlp->nlp_type & NLP_FABRIC) { 150 if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn))
150 151 lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
151 /* If the WWPN of the rport and ndlp don't match, ignore it */ 152 "6789 rport name %llx != node port name %llx",
152 if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn)) { 153 rport->port_name,
153 lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, 154 wwn_to_u64(ndlp->nlp_portname.u.wwn));
154 "6789 rport name %lx != node port name %lx",
155 (unsigned long)rport->port_name,
156 (unsigned long)wwn_to_u64(
157 ndlp->nlp_portname.u.wwn));
158 put_node = rdata->pnode != NULL;
159 put_rport = ndlp->rport != NULL;
160 rdata->pnode = NULL;
161 ndlp->rport = NULL;
162 if (put_node)
163 lpfc_nlp_put(ndlp);
164 if (put_rport)
165 put_device(&rport->dev);
166 return;
167 }
168
169 put_node = rdata->pnode != NULL;
170 put_rport = ndlp->rport != NULL;
171 rdata->pnode = NULL;
172 ndlp->rport = NULL;
173 if (put_node)
174 lpfc_nlp_put(ndlp);
175 if (put_rport)
176 put_device(&rport->dev);
177 return;
178 }
179 155
180 evtp = &ndlp->dev_loss_evt; 156 evtp = &ndlp->dev_loss_evt;
181 157
182 if (!list_empty(&evtp->evt_listp)) 158 if (!list_empty(&evtp->evt_listp)) {
159 lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
160 "6790 rport name %llx dev_loss_evt pending",
161 rport->port_name);
183 return; 162 return;
163 }
184 164
185 evtp->evt_arg1 = lpfc_nlp_get(ndlp); 165 shost = lpfc_shost_from_vport(vport);
186 ndlp->nlp_add_flag |= NLP_IN_DEV_LOSS; 166 spin_lock_irq(shost->host_lock);
167 ndlp->nlp_flag |= NLP_IN_DEV_LOSS;
168 spin_unlock_irq(shost->host_lock);
187 169
188 spin_lock_irq(&phba->hbalock);
189 /* We need to hold the node by incrementing the reference 170 /* We need to hold the node by incrementing the reference
190 * count until this queued work is done 171 * count until this queued work is done
191 */ 172 */
173 evtp->evt_arg1 = lpfc_nlp_get(ndlp);
174
175 spin_lock_irq(&phba->hbalock);
192 if (evtp->evt_arg1) { 176 if (evtp->evt_arg1) {
193 evtp->evt = LPFC_EVT_DEV_LOSS; 177 evtp->evt = LPFC_EVT_DEV_LOSS;
194 list_add_tail(&evtp->evt_listp, &phba->work_list); 178 list_add_tail(&evtp->evt_listp, &phba->work_list);
@@ -216,22 +200,24 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
216 struct fc_rport *rport; 200 struct fc_rport *rport;
217 struct lpfc_vport *vport; 201 struct lpfc_vport *vport;
218 struct lpfc_hba *phba; 202 struct lpfc_hba *phba;
203 struct Scsi_Host *shost;
219 uint8_t *name; 204 uint8_t *name;
220 int put_node; 205 int put_node;
221 int put_rport;
222 int warn_on = 0; 206 int warn_on = 0;
223 int fcf_inuse = 0; 207 int fcf_inuse = 0;
224 208
225 rport = ndlp->rport; 209 rport = ndlp->rport;
210 vport = ndlp->vport;
211 shost = lpfc_shost_from_vport(vport);
226 212
227 if (!rport) { 213 spin_lock_irq(shost->host_lock);
228 ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS; 214 ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS;
215 spin_unlock_irq(shost->host_lock);
216
217 if (!rport)
229 return fcf_inuse; 218 return fcf_inuse;
230 }
231 219
232 rdata = rport->dd_data;
233 name = (uint8_t *) &ndlp->nlp_portname; 220 name = (uint8_t *) &ndlp->nlp_portname;
234 vport = ndlp->vport;
235 phba = vport->phba; 221 phba = vport->phba;
236 222
237 if (phba->sli_rev == LPFC_SLI_REV4) 223 if (phba->sli_rev == LPFC_SLI_REV4)
@@ -245,6 +231,13 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
245 "3182 dev_loss_tmo_handler x%06x, rport %p flg x%x\n", 231 "3182 dev_loss_tmo_handler x%06x, rport %p flg x%x\n",
246 ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); 232 ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag);
247 233
234 /*
235 * lpfc_nlp_remove if reached with dangling rport drops the
236 * reference. To make sure that does not happen clear rport
237 * pointer in ndlp before lpfc_nlp_put.
238 */
239 rdata = rport->dd_data;
240
248 /* Don't defer this if we are in the process of deleting the vport 241 /* Don't defer this if we are in the process of deleting the vport
249 * or unloading the driver. The unload will cleanup the node 242 * or unloading the driver. The unload will cleanup the node
250 * appropriately we just need to cleanup the ndlp rport info here. 243 * appropriately we just need to cleanup the ndlp rport info here.
@@ -257,14 +250,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
257 ndlp->nlp_sid, 0, LPFC_CTX_TGT); 250 ndlp->nlp_sid, 0, LPFC_CTX_TGT);
258 } 251 }
259 put_node = rdata->pnode != NULL; 252 put_node = rdata->pnode != NULL;
260 put_rport = ndlp->rport != NULL;
261 rdata->pnode = NULL; 253 rdata->pnode = NULL;
262 ndlp->rport = NULL; 254 ndlp->rport = NULL;
263 ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
264 if (put_node) 255 if (put_node)
265 lpfc_nlp_put(ndlp); 256 lpfc_nlp_put(ndlp);
266 if (put_rport) 257 put_device(&rport->dev);
267 put_device(&rport->dev); 258
268 return fcf_inuse; 259 return fcf_inuse;
269 } 260 }
270 261
@@ -276,28 +267,21 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
276 *name, *(name+1), *(name+2), *(name+3), 267 *name, *(name+1), *(name+2), *(name+3),
277 *(name+4), *(name+5), *(name+6), *(name+7), 268 *(name+4), *(name+5), *(name+6), *(name+7),
278 ndlp->nlp_DID); 269 ndlp->nlp_DID);
279 ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
280 return fcf_inuse; 270 return fcf_inuse;
281 } 271 }
282 272
283 if (ndlp->nlp_type & NLP_FABRIC) { 273 put_node = rdata->pnode != NULL;
284 /* We will clean up these Nodes in linkup */ 274 rdata->pnode = NULL;
285 put_node = rdata->pnode != NULL; 275 ndlp->rport = NULL;
286 put_rport = ndlp->rport != NULL; 276 if (put_node)
287 rdata->pnode = NULL; 277 lpfc_nlp_put(ndlp);
288 ndlp->rport = NULL; 278 put_device(&rport->dev);
289 ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS; 279
290 if (put_node) 280 if (ndlp->nlp_type & NLP_FABRIC)
291 lpfc_nlp_put(ndlp);
292 if (put_rport)
293 put_device(&rport->dev);
294 return fcf_inuse; 281 return fcf_inuse;
295 }
296 282
297 if (ndlp->nlp_sid != NLP_NO_SID) { 283 if (ndlp->nlp_sid != NLP_NO_SID) {
298 warn_on = 1; 284 warn_on = 1;
299 /* flush the target */
300 ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
301 lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], 285 lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
302 ndlp->nlp_sid, 0, LPFC_CTX_TGT); 286 ndlp->nlp_sid, 0, LPFC_CTX_TGT);
303 } 287 }
@@ -322,16 +306,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
322 ndlp->nlp_state, ndlp->nlp_rpi); 306 ndlp->nlp_state, ndlp->nlp_rpi);
323 } 307 }
324 308
325 put_node = rdata->pnode != NULL;
326 put_rport = ndlp->rport != NULL;
327 rdata->pnode = NULL;
328 ndlp->rport = NULL;
329 ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
330 if (put_node)
331 lpfc_nlp_put(ndlp);
332 if (put_rport)
333 put_device(&rport->dev);
334
335 if (!(vport->load_flag & FC_UNLOADING) && 309 if (!(vport->load_flag & FC_UNLOADING) &&
336 !(ndlp->nlp_flag & NLP_DELAY_TMO) && 310 !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
337 !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && 311 !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
@@ -3919,9 +3893,17 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
3919 * registered port, drop the reference that we took the last time we 3893 * registered port, drop the reference that we took the last time we
3920 * registered the port. 3894 * registered the port.
3921 */ 3895 */
3922 if (ndlp->rport && ndlp->rport->dd_data && 3896 rport = ndlp->rport;
3923 ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) 3897 if (rport) {
3924 lpfc_nlp_put(ndlp); 3898 rdata = rport->dd_data;
3899 /* break the link before dropping the ref */
3900 ndlp->rport = NULL;
3901 if (rdata && rdata->pnode == ndlp)
3902 lpfc_nlp_put(ndlp);
3903 rdata->pnode = NULL;
3904 /* drop reference for earlier registeration */
3905 put_device(&rport->dev);
3906 }
3925 3907
3926 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, 3908 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
3927 "rport add: did:x%x flg:x%x type x%x", 3909 "rport add: did:x%x flg:x%x type x%x",
@@ -4762,6 +4744,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
4762{ 4744{
4763 struct lpfc_hba *phba = vport->phba; 4745 struct lpfc_hba *phba = vport->phba;
4764 struct lpfc_rport_data *rdata; 4746 struct lpfc_rport_data *rdata;
4747 struct fc_rport *rport;
4765 LPFC_MBOXQ_t *mbox; 4748 LPFC_MBOXQ_t *mbox;
4766 int rc; 4749 int rc;
4767 4750
@@ -4799,14 +4782,24 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
4799 lpfc_cleanup_node(vport, ndlp); 4782 lpfc_cleanup_node(vport, ndlp);
4800 4783
4801 /* 4784 /*
4802 * We can get here with a non-NULL ndlp->rport because when we 4785 * ndlp->rport must be set to NULL before it reaches here
4803 * unregister a rport we don't break the rport/node linkage. So if we 4786 * i.e. break rport/node link before doing lpfc_nlp_put for
4804 * do, make sure we don't leaving any dangling pointers behind. 4787 * registered rport and then drop the reference of rport.
4805 */ 4788 */
4806 if (ndlp->rport) { 4789 if (ndlp->rport) {
4807 rdata = ndlp->rport->dd_data; 4790 /*
4791 * extra lpfc_nlp_put dropped the reference of ndlp
4792 * for registered rport so need to cleanup rport
4793 */
4794 lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
4795 "0940 removed node x%p DID x%x "
4796 " rport not null %p\n",
4797 ndlp, ndlp->nlp_DID, ndlp->rport);
4798 rport = ndlp->rport;
4799 rdata = rport->dd_data;
4808 rdata->pnode = NULL; 4800 rdata->pnode = NULL;
4809 ndlp->rport = NULL; 4801 ndlp->rport = NULL;
4802 put_device(&rport->dev);
4810 } 4803 }
4811} 4804}
4812 4805