[SCSI] zfcp: restore refcount check on port_remove

Upstream commit f3450c7b91
"[SCSI] zfcp: Replace local reference counting with common kref"
accidentally dropped a reference count check before tearing down
zfcp_ports that are potentially in use by zfcp_units.
Even remote ports in use can be removed causing
unreachable garbage objects zfcp_ports with zfcp_units.
Thus units won't come back even after a manual port_rescan.
The kref of zfcp_port->dev.kobj is already used by the driver core.
We cannot re-use it to track the number of zfcp_units.
Re-introduce our own counter for units per port
and check on port_remove.

Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: <stable@vger.kernel.org> #2.6.33+
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Bu işleme şunda yer alıyor:
Steffen Maier
2012-09-04 15:23:34 +02:00
işlemeyi yapan: James Bottomley
ebeveyn ca579c9f13
işleme d99b601b63
5 değiştirilmiş dosya ile 45 ekleme ve 12 silme

Dosyayı Görüntüle

@@ -104,7 +104,7 @@ static void zfcp_unit_release(struct device *dev)
{
struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
put_device(&unit->port->dev);
atomic_dec(&unit->port->units);
kfree(unit);
}
@@ -119,16 +119,27 @@ static void zfcp_unit_release(struct device *dev)
int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
{
struct zfcp_unit *unit;
int retval = 0;
mutex_lock(&zfcp_sysfs_port_units_mutex);
if (atomic_read(&port->units) == -1) {
/* port is already gone */
retval = -ENODEV;
goto out;
}
unit = zfcp_unit_find(port, fcp_lun);
if (unit) {
put_device(&unit->dev);
return -EEXIST;
retval = -EEXIST;
goto out;
}
unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
if (!unit)
return -ENOMEM;
if (!unit) {
retval = -ENOMEM;
goto out;
}
unit->port = port;
unit->fcp_lun = fcp_lun;
@@ -139,28 +150,33 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
if (dev_set_name(&unit->dev, "0x%016llx",
(unsigned long long) fcp_lun)) {
kfree(unit);
return -ENOMEM;
retval = -ENOMEM;
goto out;
}
get_device(&port->dev);
if (device_register(&unit->dev)) {
put_device(&unit->dev);
return -ENOMEM;
retval = -ENOMEM;
goto out;
}
if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) {
device_unregister(&unit->dev);
return -EINVAL;
retval = -EINVAL;
goto out;
}
atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */
write_lock_irq(&port->unit_list_lock);
list_add_tail(&unit->list, &port->unit_list);
write_unlock_irq(&port->unit_list_lock);
zfcp_unit_scsi_scan(unit);
return 0;
out:
mutex_unlock(&zfcp_sysfs_port_units_mutex);
return retval;
}
/**