aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_rport.c
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2009-10-21 19:28:30 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:00:37 -0500
commitb4a9c7ede96e90f7b1ec009ce7256059295e76df (patch)
tree19b6322ba27e296a9350921c2e1511fb7c303694 /drivers/scsi/libfc/fc_rport.c
parent4b53662bd594941e5e5e540baaaff6a3e66d062c (diff)
[SCSI] libfc: fix free of fc_rport_priv with timer pending
Timer crashes were caused by freeing a struct fc_rport_priv with a timer pending, causing the timer facility list to be corrupted. This was during FC uplink flap tests with a lot of targets. After discovery, we were doing an PLOGI on an rdata that was in DELETE state but not yet removed from the lookup list. This moved the rdata from DELETE state to PLOGI state. If the PLOGI exchange allocation failed and needed to be retried, the timer scheduling could race with the free being done by fc_rport_work(). When fc_rport_login() is called on a rport in DELETE state, move it to a new state RESTART. In fc_rport_work, when handling a LOGO, STOPPED or FAILED event, look for restart state. In the RESTART case, don't take the rdata off the list and after the transport remote port is deleted and exchanges are reset, re-login to the remote port. Note that the new RESTART state also corrects a problem we had when re-discovering a port that had moved to DELETE state. In that case, a new rdata was created, but the old rdata would do an exchange manager reset affecting the FC_ID for both the new rdata and old rdata. With the new state, the new port isn't logged into until after any old exchanges are reset. Signed-off-by: Joe Eykholt <jeykholt@cisco.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r--drivers/scsi/libfc/fc_rport.c69
1 files changed, 50 insertions, 19 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 49abb839a223..324e156b5d07 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -86,6 +86,7 @@ static const char *fc_rport_state_names[] = {
86 [RPORT_ST_LOGO] = "LOGO", 86 [RPORT_ST_LOGO] = "LOGO",
87 [RPORT_ST_ADISC] = "ADISC", 87 [RPORT_ST_ADISC] = "ADISC",
88 [RPORT_ST_DELETE] = "Delete", 88 [RPORT_ST_DELETE] = "Delete",
89 [RPORT_ST_RESTART] = "Restart",
89}; 90};
90 91
91/** 92/**
@@ -99,8 +100,7 @@ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
99 struct fc_rport_priv *rdata; 100 struct fc_rport_priv *rdata;
100 101
101 list_for_each_entry(rdata, &lport->disc.rports, peers) 102 list_for_each_entry(rdata, &lport->disc.rports, peers)
102 if (rdata->ids.port_id == port_id && 103 if (rdata->ids.port_id == port_id)
103 rdata->rp_state != RPORT_ST_DELETE)
104 return rdata; 104 return rdata;
105 return NULL; 105 return NULL;
106} 106}
@@ -235,6 +235,7 @@ static void fc_rport_work(struct work_struct *work)
235 struct fc_rport_operations *rport_ops; 235 struct fc_rport_operations *rport_ops;
236 struct fc_rport_identifiers ids; 236 struct fc_rport_identifiers ids;
237 struct fc_rport *rport; 237 struct fc_rport *rport;
238 int restart = 0;
238 239
239 mutex_lock(&rdata->rp_mutex); 240 mutex_lock(&rdata->rp_mutex);
240 event = rdata->event; 241 event = rdata->event;
@@ -287,8 +288,19 @@ static void fc_rport_work(struct work_struct *work)
287 mutex_unlock(&rdata->rp_mutex); 288 mutex_unlock(&rdata->rp_mutex);
288 289
289 if (port_id != FC_FID_DIR_SERV) { 290 if (port_id != FC_FID_DIR_SERV) {
291 /*
292 * We must drop rp_mutex before taking disc_mutex.
293 * Re-evaluate state to allow for restart.
294 * A transition to RESTART state must only happen
295 * while disc_mutex is held and rdata is on the list.
296 */
290 mutex_lock(&lport->disc.disc_mutex); 297 mutex_lock(&lport->disc.disc_mutex);
291 list_del(&rdata->peers); 298 mutex_lock(&rdata->rp_mutex);
299 if (rdata->rp_state == RPORT_ST_RESTART)
300 restart = 1;
301 else
302 list_del(&rdata->peers);
303 mutex_unlock(&rdata->rp_mutex);
292 mutex_unlock(&lport->disc.disc_mutex); 304 mutex_unlock(&lport->disc.disc_mutex);
293 } 305 }
294 306
@@ -312,7 +324,13 @@ static void fc_rport_work(struct work_struct *work)
312 mutex_unlock(&rdata->rp_mutex); 324 mutex_unlock(&rdata->rp_mutex);
313 fc_remote_port_delete(rport); 325 fc_remote_port_delete(rport);
314 } 326 }
315 kref_put(&rdata->kref, lport->tt.rport_destroy); 327 if (restart) {
328 mutex_lock(&rdata->rp_mutex);
329 FC_RPORT_DBG(rdata, "work restart\n");
330 fc_rport_enter_plogi(rdata);
331 mutex_unlock(&rdata->rp_mutex);
332 } else
333 kref_put(&rdata->kref, lport->tt.rport_destroy);
316 break; 334 break;
317 335
318 default: 336 default:
@@ -342,6 +360,12 @@ int fc_rport_login(struct fc_rport_priv *rdata)
342 FC_RPORT_DBG(rdata, "ADISC port\n"); 360 FC_RPORT_DBG(rdata, "ADISC port\n");
343 fc_rport_enter_adisc(rdata); 361 fc_rport_enter_adisc(rdata);
344 break; 362 break;
363 case RPORT_ST_RESTART:
364 break;
365 case RPORT_ST_DELETE:
366 FC_RPORT_DBG(rdata, "Restart deleted port\n");
367 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
368 break;
345 default: 369 default:
346 FC_RPORT_DBG(rdata, "Login to port\n"); 370 FC_RPORT_DBG(rdata, "Login to port\n");
347 fc_rport_enter_plogi(rdata); 371 fc_rport_enter_plogi(rdata);
@@ -397,20 +421,21 @@ int fc_rport_logoff(struct fc_rport_priv *rdata)
397 421
398 if (rdata->rp_state == RPORT_ST_DELETE) { 422 if (rdata->rp_state == RPORT_ST_DELETE) {
399 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); 423 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
400 mutex_unlock(&rdata->rp_mutex);
401 goto out; 424 goto out;
402 } 425 }
403 426
404 fc_rport_enter_logo(rdata); 427 if (rdata->rp_state == RPORT_ST_RESTART)
428 FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
429 else
430 fc_rport_enter_logo(rdata);
405 431
406 /* 432 /*
407 * Change the state to Delete so that we discard 433 * Change the state to Delete so that we discard
408 * the response. 434 * the response.
409 */ 435 */
410 fc_rport_enter_delete(rdata, RPORT_EV_STOP); 436 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
411 mutex_unlock(&rdata->rp_mutex);
412
413out: 437out:
438 mutex_unlock(&rdata->rp_mutex);
414 return 0; 439 return 0;
415} 440}
416 441
@@ -466,6 +491,7 @@ static void fc_rport_timeout(struct work_struct *work)
466 case RPORT_ST_READY: 491 case RPORT_ST_READY:
467 case RPORT_ST_INIT: 492 case RPORT_ST_INIT:
468 case RPORT_ST_DELETE: 493 case RPORT_ST_DELETE:
494 case RPORT_ST_RESTART:
469 break; 495 break;
470 } 496 }
471 497
@@ -499,6 +525,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
499 fc_rport_enter_logo(rdata); 525 fc_rport_enter_logo(rdata);
500 break; 526 break;
501 case RPORT_ST_DELETE: 527 case RPORT_ST_DELETE:
528 case RPORT_ST_RESTART:
502 case RPORT_ST_READY: 529 case RPORT_ST_READY:
503 case RPORT_ST_INIT: 530 case RPORT_ST_INIT:
504 break; 531 break;
@@ -1248,6 +1275,7 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
1248 } 1275 }
1249 break; 1276 break;
1250 case RPORT_ST_PRLI: 1277 case RPORT_ST_PRLI:
1278 case RPORT_ST_RTV:
1251 case RPORT_ST_READY: 1279 case RPORT_ST_READY:
1252 case RPORT_ST_ADISC: 1280 case RPORT_ST_ADISC:
1253 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " 1281 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
@@ -1255,11 +1283,14 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
1255 /* XXX TBD - should reset */ 1283 /* XXX TBD - should reset */
1256 break; 1284 break;
1257 case RPORT_ST_DELETE: 1285 case RPORT_ST_DELETE:
1258 default: 1286 case RPORT_ST_LOGO:
1259 FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n", 1287 case RPORT_ST_RESTART:
1260 rdata->rp_state); 1288 FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
1261 fc_frame_free(rx_fp); 1289 fc_rport_state(rdata));
1262 goto out; 1290 mutex_unlock(&rdata->rp_mutex);
1291 rjt_data.reason = ELS_RJT_BUSY;
1292 rjt_data.explan = ELS_EXPL_NONE;
1293 goto reject;
1263 } 1294 }
1264 1295
1265 /* 1296 /*
@@ -1510,14 +1541,14 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
1510 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", 1541 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1511 fc_rport_state(rdata)); 1542 fc_rport_state(rdata));
1512 1543
1544 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
1545
1513 /* 1546 /*
1514 * If the remote port was created due to discovery, 1547 * If the remote port was created due to discovery, set state
1515 * log back in. It may have seen a stale RSCN about us. 1548 * to log back in. It may have seen a stale RSCN about us.
1516 */ 1549 */
1517 if (rdata->rp_state != RPORT_ST_DELETE && rdata->disc_id) 1550 if (rdata->disc_id)
1518 fc_rport_enter_plogi(rdata); 1551 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
1519 else
1520 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
1521 mutex_unlock(&rdata->rp_mutex); 1552 mutex_unlock(&rdata->rp_mutex);
1522 } else 1553 } else
1523 FC_RPORT_ID_DBG(lport, sid, 1554 FC_RPORT_ID_DBG(lport, sid,