[SCSI] zfcp: invalid usage after free of port resources
authorSwen Schillig <swen@vnet.ibm.com>
Tue, 18 Aug 2009 13:43:06 +0000 (15:43 +0200)
committerJames Bottomley <James.Bottomley@suse.de>
Sat, 5 Sep 2009 13:49:04 +0000 (08:49 -0500)
In certain error scenarios ports, rports are getting attached,
validated and removed from the systems environment. Depending on the
layer this occurs asynchronously. This patch fixes the few races
which existed and ensures all references and cross references are
cleared at the time they're invalid. In addition fc transports
actions are only scheduled when required.

Signed-off-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_scsi.c

index 2ccbd185a5fb8cc44c6698769b50427bb66a0fc0..fa2460b4229808a4343ba28cd9736ef4a6114a98 100644 (file)
@@ -672,12 +672,15 @@ err_out:
  */
 void zfcp_port_dequeue(struct zfcp_port *port)
 {
-       wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
        write_lock_irq(&zfcp_data.config_lock);
        list_del(&port->list);
        write_unlock_irq(&zfcp_data.config_lock);
-       if (port->rport)
+       if (port->rport) {
                port->rport->dd_data = NULL;
+               port->rport = NULL;
+       }
+       wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
+       cancel_work_sync(&port->rport_work); /* usually not necessary */
        zfcp_adapter_put(port->adapter);
        sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
        device_unregister(&port->sysfs_device);
index 6925a17846825109225e7530705505b5151cc477..54a7a7474aa569e542c3bfbf4a37eab29249baa6 100644 (file)
@@ -582,8 +582,10 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
        zfcp_port_get(port);
        port->rport_task = RPORT_DEL;
 
-       if (!queue_work(zfcp_data.work_queue, &port->rport_work))
-               zfcp_port_put(port);
+       if (port->rport && queue_work(zfcp_data.work_queue, &port->rport_work))
+               return;
+
+       zfcp_port_put(port);
 }
 
 void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)