Prev: [048/156] gigaset: correct range checking off by one error
Next: [050/156] perf: Make the install relative to DESTDIR if specified
From: Greg KH on 30 Mar 2010 19:50 2.6.33-stable review patch. If anyone has any objections, please let us know. ------------------ From: Gal Rosen <galr(a)storwize.com> 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(a)storwize.com> Acked-by: James Smart <james.smart(a)emulex.com> Signed-off-by: James Bottomley <James.Bottomley(a)suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh(a)suse.de> --- drivers/scsi/scsi_transport_fc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) --- 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 fc_vport *vport = transport_class_to_vport(dev); struct Scsi_Host *shost = vport_to_shost(vport); + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) { + spin_unlock_irqrestore(shost->host_lock, flags); + return -EBUSY; + } + vport->flags |= FC_VPORT_DELETING; + spin_unlock_irqrestore(shost->host_lock, flags); fc_queue_work(shost, &vport->vport_delete_work); return count; @@ -1805,6 +1814,9 @@ store_fc_host_vport_delete(struct device list_for_each_entry(vport, &fc_host->vports, peers) { if ((vport->channel == 0) && (vport->port_name == wwpn) && (vport->node_name == wwnn)) { + if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) + break; + vport->flags |= FC_VPORT_DELETING; match = 1; break; } @@ -3354,18 +3366,6 @@ fc_vport_terminate(struct fc_vport *vpor unsigned long flags; int stat; - spin_lock_irqsave(shost->host_lock, flags); - if (vport->flags & FC_VPORT_CREATING) { - spin_unlock_irqrestore(shost->host_lock, flags); - return -EBUSY; - } - if (vport->flags & (FC_VPORT_DEL)) { - spin_unlock_irqrestore(shost->host_lock, flags); - return -EALREADY; - } - vport->flags |= FC_VPORT_DELETING; - spin_unlock_irqrestore(shost->host_lock, flags); - if (i->f->vport_delete) stat = i->f->vport_delete(vport); else -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo(a)vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ |