diff options
author | Gal Rosen <galr@storwize.com> | 2010-01-21 03:15:32 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-04-01 19:01:32 -0400 |
commit | ae56fa68db2da81677393b9a3b777b96ac683cbb (patch) | |
tree | 5e6f388b8e3fa4d4dd2a71d77bbef2d3f5e6fb44 | |
parent | 82df18799be6189a905651888ea471ef11e01807 (diff) |
SCSI: scsi_transport_fc: Fix synchronization issue while deleting vport
commit 0d9dc7c8b9b7fa0f53647423b41056ee1beed735 upstream.
The issue occur while deleting 60 virtual ports through the sys
interface /sys/class/fc_vports/vport-X/vport_delete. It happen while in
a mistake each request sent twice for the same vport. This interface is
asynchronous, entering the delete request into a work queue, allowing
more than one request to enter to the delete work queue. The result is a
NULL pointer. The first request already delete the vport, while the
second request got a pointer to the vport before the device destroyed.
Re-create vport later cause system freeze.
Solution: Check vport flags before entering the request to the work queue.
[jejb: fixed int<->long problem on spinlock flags variable]
Signed-off-by: Gal Rosen <galr@storwize.com>
Acked-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 24 |
1 files changed, 12 insertions, 12 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 653f22a8deb9..bb8fd5b00955 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -1216,6 +1216,15 @@ store_fc_vport_delete(struct device *dev, struct device_attribute *attr, | |||
1216 | { | 1216 | { |
1217 | struct fc_vport *vport = transport_class_to_vport(dev); | 1217 | struct fc_vport *vport = transport_class_to_vport(dev); |
1218 | struct Scsi_Host *shost = vport_to_shost(vport); | 1218 | struct Scsi_Host *shost = vport_to_shost(vport); |
1219 | unsigned long flags; | ||
1220 | |||
1221 | spin_lock_irqsave(shost->host_lock, flags); | ||
1222 | if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) { | ||
1223 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1224 | return -EBUSY; | ||
1225 | } | ||
1226 | vport->flags |= FC_VPORT_DELETING; | ||
1227 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1219 | 1228 | ||
1220 | fc_queue_work(shost, &vport->vport_delete_work); | 1229 | fc_queue_work(shost, &vport->vport_delete_work); |
1221 | return count; | 1230 | return count; |
@@ -1805,6 +1814,9 @@ store_fc_host_vport_delete(struct device *dev, struct device_attribute *attr, | |||
1805 | list_for_each_entry(vport, &fc_host->vports, peers) { | 1814 | list_for_each_entry(vport, &fc_host->vports, peers) { |
1806 | if ((vport->channel == 0) && | 1815 | if ((vport->channel == 0) && |
1807 | (vport->port_name == wwpn) && (vport->node_name == wwnn)) { | 1816 | (vport->port_name == wwpn) && (vport->node_name == wwnn)) { |
1817 | if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) | ||
1818 | break; | ||
1819 | vport->flags |= FC_VPORT_DELETING; | ||
1808 | match = 1; | 1820 | match = 1; |
1809 | break; | 1821 | break; |
1810 | } | 1822 | } |
@@ -3354,18 +3366,6 @@ fc_vport_terminate(struct fc_vport *vport) | |||
3354 | unsigned long flags; | 3366 | unsigned long flags; |
3355 | int stat; | 3367 | int stat; |
3356 | 3368 | ||
3357 | spin_lock_irqsave(shost->host_lock, flags); | ||
3358 | if (vport->flags & FC_VPORT_CREATING) { | ||
3359 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3360 | return -EBUSY; | ||
3361 | } | ||
3362 | if (vport->flags & (FC_VPORT_DEL)) { | ||
3363 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3364 | return -EALREADY; | ||
3365 | } | ||
3366 | vport->flags |= FC_VPORT_DELETING; | ||
3367 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3368 | |||
3369 | if (i->f->vport_delete) | 3369 | if (i->f->vport_delete) |
3370 | stat = i->f->vport_delete(vport); | 3370 | stat = i->f->vport_delete(vport); |
3371 | else | 3371 | else |