aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2009-07-29 20:04:49 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-08-22 18:52:06 -0400
commit5f7ea3b7f81d5e5180647a071998b73a841bdba9 (patch)
tree29f974c9b6eb186e38f13fea8196c1107f2df738 /drivers/scsi/libfc
parent141940548c6919c22bf0573c68fd59d961e22475 (diff)
[SCSI] libfc: fc_rport_logoff should not drop the lock
fc_rport_logoff drops the rport lock in order to cancel work that may be pending. This is undesirable as the state can completely change, and the caller may not expect that the lock could've been dropped. If there is work pending, it will acquire the rdata mutex and so we're protected and can change the event from READY to DELETE. Queue the work only if there is no event already pending. There were a couple other cases where the state was set to DELETE and work queued, even though the state may have already been DELETE. Fix these using a common function fc_rport_enter_delete(). 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@HansenPartnership.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r--drivers/scsi/libfc/fc_rport.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index bf7364fc16c..a86df0b41ae 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -230,6 +230,7 @@ static void fc_rport_work(struct work_struct *work)
230 ids.port_name = rport->port_name; 230 ids.port_name = rport->port_name;
231 ids.node_name = rport->node_name; 231 ids.node_name = rport->node_name;
232 232
233 rdata->event = RPORT_EV_NONE;
233 mutex_unlock(&rdata->rp_mutex); 234 mutex_unlock(&rdata->rp_mutex);
234 235
235 new_rport = fc_remote_port_add(lport->host, 0, &ids); 236 new_rport = fc_remote_port_add(lport->host, 0, &ids);
@@ -311,6 +312,37 @@ int fc_rport_login(struct fc_rport *rport)
311} 312}
312 313
313/** 314/**
315 * fc_rport_enter_delete() - schedule a remote port to be deleted.
316 * @rport: Fibre Channel remote port
317 * @event: event to report as the reason for deletion
318 *
319 * Locking Note: Called with the rport lock held.
320 *
321 * Allow state change into DELETE only once.
322 *
323 * Call queue_work only if there's no event already pending.
324 * Set the new event so that the old pending event will not occur.
325 * Since we have the mutex, even if fc_rport_work() is already started,
326 * it'll see the new event.
327 */
328static void fc_rport_enter_delete(struct fc_rport *rport,
329 enum fc_rport_event event)
330{
331 struct fc_rport_libfc_priv *rdata = rport->dd_data;
332
333 if (rdata->rp_state == RPORT_ST_DELETE)
334 return;
335
336 FC_RPORT_DBG(rport, "Delete port\n");
337
338 fc_rport_state_enter(rport, RPORT_ST_DELETE);
339
340 if (rdata->event == RPORT_EV_NONE)
341 queue_work(rport_event_queue, &rdata->event_work);
342 rdata->event = event;
343}
344
345/**
314 * fc_rport_logoff() - Logoff and remove an rport 346 * fc_rport_logoff() - Logoff and remove an rport
315 * @rport: Fibre Channel remote port to be removed 347 * @rport: Fibre Channel remote port to be removed
316 * 348 *
@@ -338,17 +370,7 @@ int fc_rport_logoff(struct fc_rport *rport)
338 * Change the state to Delete so that we discard 370 * Change the state to Delete so that we discard
339 * the response. 371 * the response.
340 */ 372 */
341 fc_rport_state_enter(rport, RPORT_ST_DELETE); 373 fc_rport_enter_delete(rport, RPORT_EV_STOP);
342
343 mutex_unlock(&rdata->rp_mutex);
344
345 cancel_delayed_work_sync(&rdata->retry_work);
346
347 mutex_lock(&rdata->rp_mutex);
348
349 rdata->event = RPORT_EV_STOP;
350 queue_work(rport_event_queue, &rdata->event_work);
351
352 mutex_unlock(&rdata->rp_mutex); 374 mutex_unlock(&rdata->rp_mutex);
353 375
354out: 376out:
@@ -370,8 +392,9 @@ static void fc_rport_enter_ready(struct fc_rport *rport)
370 392
371 FC_RPORT_DBG(rport, "Port is Ready\n"); 393 FC_RPORT_DBG(rport, "Port is Ready\n");
372 394
395 if (rdata->event == RPORT_EV_NONE)
396 queue_work(rport_event_queue, &rdata->event_work);
373 rdata->event = RPORT_EV_CREATED; 397 rdata->event = RPORT_EV_CREATED;
374 queue_work(rport_event_queue, &rdata->event_work);
375} 398}
376 399
377/** 400/**
@@ -432,10 +455,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
432 case RPORT_ST_PLOGI: 455 case RPORT_ST_PLOGI:
433 case RPORT_ST_PRLI: 456 case RPORT_ST_PRLI:
434 case RPORT_ST_LOGO: 457 case RPORT_ST_LOGO:
435 rdata->event = RPORT_EV_FAILED; 458 fc_rport_enter_delete(rport, RPORT_EV_FAILED);
436 fc_rport_state_enter(rport, RPORT_ST_DELETE);
437 queue_work(rport_event_queue,
438 &rdata->event_work);
439 break; 459 break;
440 case RPORT_ST_RTV: 460 case RPORT_ST_RTV:
441 fc_rport_enter_ready(rport); 461 fc_rport_enter_ready(rport);
@@ -651,9 +671,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
651 671
652 } else { 672 } else {
653 FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n"); 673 FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n");
654 rdata->event = RPORT_EV_FAILED; 674 fc_rport_enter_delete(rport, RPORT_EV_FAILED);
655 fc_rport_state_enter(rport, RPORT_ST_DELETE);
656 queue_work(rport_event_queue, &rdata->event_work);
657 } 675 }
658 676
659out: 677out:
@@ -702,9 +720,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
702 fc_rport_enter_rtv(rport); 720 fc_rport_enter_rtv(rport);
703 } else { 721 } else {
704 FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n"); 722 FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n");
705 rdata->event = RPORT_EV_LOGO; 723 fc_rport_enter_delete(rport, RPORT_EV_LOGO);
706 fc_rport_state_enter(rport, RPORT_ST_DELETE);
707 queue_work(rport_event_queue, &rdata->event_work);
708 } 724 }
709 725
710out: 726out: