[SCSI] zfcp: restore refcount check on port_remove
[firefly-linux-kernel-4.4.55.git] / drivers / s390 / scsi / zfcp_unit.c
index 3f2bff0d3aa21fd9996cedc187c441bff167718e..1cd2b99ab256c06132dd85c0a7a3d4293e98cb87 100644 (file)
@@ -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;
 }
 
 /**