aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael Reed <mdr@sgi.com>2009-10-09 15:15:59 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-10-29 13:03:28 -0400
commit8798a694da59486e4a3ff0abeec183202fb34c20 (patch)
tree2410f1f70f7724e41f700c1ec4086f2567208730 /drivers
parentad63082626f99651d261ccd8698ce4e997362f7e (diff)
[SCSI] scsi_transport_fc: remove invalid BUG_ON
I was doing some large lun count testing with 2.6.31 and hit a BUG_ON() in fc_timeout_deleted_rport(), and it seems like it should have been just a matter of time before someone did. It seems invalid to set port_state under lock, then expect it to remain set after releasing the lock. Another thread called fc_remote_port_add() when the lock was released, changing the port_state. This patch removes the BUG_ON and moves the test of the port_state to inside the host_lock. It's been running for several weeks now with no ill effect. Signed-off-by: Michael Reed <mdr@sgi.com> Acked-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/scsi_transport_fc.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index a67fed10598a..f436e033adaf 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2384,6 +2384,7 @@ fc_rport_final_delete(struct work_struct *work)
2384 struct Scsi_Host *shost = rport_to_shost(rport); 2384 struct Scsi_Host *shost = rport_to_shost(rport);
2385 struct fc_internal *i = to_fc_internal(shost->transportt); 2385 struct fc_internal *i = to_fc_internal(shost->transportt);
2386 unsigned long flags; 2386 unsigned long flags;
2387 int do_callback = 0;
2387 2388
2388 /* 2389 /*
2389 * if a scan is pending, flush the SCSI Host work_q so that 2390 * if a scan is pending, flush the SCSI Host work_q so that
@@ -2422,8 +2423,15 @@ fc_rport_final_delete(struct work_struct *work)
2422 * Avoid this call if we already called it when we preserved the 2423 * Avoid this call if we already called it when we preserved the
2423 * rport for the binding. 2424 * rport for the binding.
2424 */ 2425 */
2426 spin_lock_irqsave(shost->host_lock, flags);
2425 if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) && 2427 if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) &&
2426 (i->f->dev_loss_tmo_callbk)) 2428 (i->f->dev_loss_tmo_callbk)) {
2429 rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
2430 do_callback = 1;
2431 }
2432 spin_unlock_irqrestore(shost->host_lock, flags);
2433
2434 if (do_callback)
2427 i->f->dev_loss_tmo_callbk(rport); 2435 i->f->dev_loss_tmo_callbk(rport);
2428 2436
2429 fc_bsg_remove(rport->rqst_q); 2437 fc_bsg_remove(rport->rqst_q);
@@ -2970,6 +2978,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
2970 struct fc_internal *i = to_fc_internal(shost->transportt); 2978 struct fc_internal *i = to_fc_internal(shost->transportt);
2971 struct fc_host_attrs *fc_host = shost_to_fc_host(shost); 2979 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
2972 unsigned long flags; 2980 unsigned long flags;
2981 int do_callback = 0;
2973 2982
2974 spin_lock_irqsave(shost->host_lock, flags); 2983 spin_lock_irqsave(shost->host_lock, flags);
2975 2984
@@ -3035,7 +3044,6 @@ fc_timeout_deleted_rport(struct work_struct *work)
3035 rport->roles = FC_PORT_ROLE_UNKNOWN; 3044 rport->roles = FC_PORT_ROLE_UNKNOWN;
3036 rport->port_state = FC_PORTSTATE_NOTPRESENT; 3045 rport->port_state = FC_PORTSTATE_NOTPRESENT;
3037 rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; 3046 rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT;
3038 rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
3039 3047
3040 /* 3048 /*
3041 * Pre-emptively kill I/O rather than waiting for the work queue 3049 * Pre-emptively kill I/O rather than waiting for the work queue
@@ -3045,32 +3053,40 @@ fc_timeout_deleted_rport(struct work_struct *work)
3045 spin_unlock_irqrestore(shost->host_lock, flags); 3053 spin_unlock_irqrestore(shost->host_lock, flags);
3046 fc_terminate_rport_io(rport); 3054 fc_terminate_rport_io(rport);
3047 3055
3048 BUG_ON(rport->port_state != FC_PORTSTATE_NOTPRESENT); 3056 spin_lock_irqsave(shost->host_lock, flags);
3049 3057
3050 /* remove the identifiers that aren't used in the consisting binding */ 3058 if (rport->port_state == FC_PORTSTATE_NOTPRESENT) { /* still missing */
3051 switch (fc_host->tgtid_bind_type) { 3059
3052 case FC_TGTID_BIND_BY_WWPN: 3060 /* remove the identifiers that aren't used in the consisting binding */
3053 rport->node_name = -1; 3061 switch (fc_host->tgtid_bind_type) {
3054 rport->port_id = -1; 3062 case FC_TGTID_BIND_BY_WWPN:
3055 break; 3063 rport->node_name = -1;
3056 case FC_TGTID_BIND_BY_WWNN: 3064 rport->port_id = -1;
3057 rport->port_name = -1; 3065 break;
3058 rport->port_id = -1; 3066 case FC_TGTID_BIND_BY_WWNN:
3059 break; 3067 rport->port_name = -1;
3060 case FC_TGTID_BIND_BY_ID: 3068 rport->port_id = -1;
3061 rport->node_name = -1; 3069 break;
3062 rport->port_name = -1; 3070 case FC_TGTID_BIND_BY_ID:
3063 break; 3071 rport->node_name = -1;
3064 case FC_TGTID_BIND_NONE: /* to keep compiler happy */ 3072 rport->port_name = -1;
3065 break; 3073 break;
3074 case FC_TGTID_BIND_NONE: /* to keep compiler happy */
3075 break;
3076 }
3077
3078 /*
3079 * As this only occurs if the remote port (scsi target)
3080 * went away and didn't come back - we'll remove
3081 * all attached scsi devices.
3082 */
3083 rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
3084 fc_queue_work(shost, &rport->stgt_delete_work);
3085
3086 do_callback = 1;
3066 } 3087 }
3067 3088
3068 /* 3089 spin_unlock_irqrestore(shost->host_lock, flags);
3069 * As this only occurs if the remote port (scsi target)
3070 * went away and didn't come back - we'll remove
3071 * all attached scsi devices.
3072 */
3073 fc_queue_work(shost, &rport->stgt_delete_work);
3074 3090
3075 /* 3091 /*
3076 * Notify the driver that the rport is now dead. The LLDD will 3092 * Notify the driver that the rport is now dead. The LLDD will
@@ -3078,7 +3094,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
3078 * 3094 *
3079 * Note: we set the CALLBK_DONE flag above to correspond 3095 * Note: we set the CALLBK_DONE flag above to correspond
3080 */ 3096 */
3081 if (i->f->dev_loss_tmo_callbk) 3097 if (do_callback && i->f->dev_loss_tmo_callbk)
3082 i->f->dev_loss_tmo_callbk(rport); 3098 i->f->dev_loss_tmo_callbk(rport);
3083} 3099}
3084 3100