diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_unit.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_unit.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c index 3f2bff0d3aa2..1cd2b99ab256 100644 --- a/drivers/s390/scsi/zfcp_unit.c +++ b/drivers/s390/scsi/zfcp_unit.c | |||
@@ -104,7 +104,7 @@ static void zfcp_unit_release(struct device *dev) | |||
104 | { | 104 | { |
105 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); | 105 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); |
106 | 106 | ||
107 | put_device(&unit->port->dev); | 107 | atomic_dec(&unit->port->units); |
108 | kfree(unit); | 108 | kfree(unit); |
109 | } | 109 | } |
110 | 110 | ||
@@ -119,16 +119,27 @@ static void zfcp_unit_release(struct device *dev) | |||
119 | int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) | 119 | int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) |
120 | { | 120 | { |
121 | struct zfcp_unit *unit; | 121 | struct zfcp_unit *unit; |
122 | int retval = 0; | ||
123 | |||
124 | mutex_lock(&zfcp_sysfs_port_units_mutex); | ||
125 | if (atomic_read(&port->units) == -1) { | ||
126 | /* port is already gone */ | ||
127 | retval = -ENODEV; | ||
128 | goto out; | ||
129 | } | ||
122 | 130 | ||
123 | unit = zfcp_unit_find(port, fcp_lun); | 131 | unit = zfcp_unit_find(port, fcp_lun); |
124 | if (unit) { | 132 | if (unit) { |
125 | put_device(&unit->dev); | 133 | put_device(&unit->dev); |
126 | return -EEXIST; | 134 | retval = -EEXIST; |
135 | goto out; | ||
127 | } | 136 | } |
128 | 137 | ||
129 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); | 138 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); |
130 | if (!unit) | 139 | if (!unit) { |
131 | return -ENOMEM; | 140 | retval = -ENOMEM; |
141 | goto out; | ||
142 | } | ||
132 | 143 | ||
133 | unit->port = port; | 144 | unit->port = port; |
134 | unit->fcp_lun = fcp_lun; | 145 | unit->fcp_lun = fcp_lun; |
@@ -139,28 +150,33 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) | |||
139 | if (dev_set_name(&unit->dev, "0x%016llx", | 150 | if (dev_set_name(&unit->dev, "0x%016llx", |
140 | (unsigned long long) fcp_lun)) { | 151 | (unsigned long long) fcp_lun)) { |
141 | kfree(unit); | 152 | kfree(unit); |
142 | return -ENOMEM; | 153 | retval = -ENOMEM; |
154 | goto out; | ||
143 | } | 155 | } |
144 | 156 | ||
145 | get_device(&port->dev); | ||
146 | |||
147 | if (device_register(&unit->dev)) { | 157 | if (device_register(&unit->dev)) { |
148 | put_device(&unit->dev); | 158 | put_device(&unit->dev); |
149 | return -ENOMEM; | 159 | retval = -ENOMEM; |
160 | goto out; | ||
150 | } | 161 | } |
151 | 162 | ||
152 | if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { | 163 | if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { |
153 | device_unregister(&unit->dev); | 164 | device_unregister(&unit->dev); |
154 | return -EINVAL; | 165 | retval = -EINVAL; |
166 | goto out; | ||
155 | } | 167 | } |
156 | 168 | ||
169 | atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */ | ||
170 | |||
157 | write_lock_irq(&port->unit_list_lock); | 171 | write_lock_irq(&port->unit_list_lock); |
158 | list_add_tail(&unit->list, &port->unit_list); | 172 | list_add_tail(&unit->list, &port->unit_list); |
159 | write_unlock_irq(&port->unit_list_lock); | 173 | write_unlock_irq(&port->unit_list_lock); |
160 | 174 | ||
161 | zfcp_unit_scsi_scan(unit); | 175 | zfcp_unit_scsi_scan(unit); |
162 | 176 | ||
163 | return 0; | 177 | out: |
178 | mutex_unlock(&zfcp_sysfs_port_units_mutex); | ||
179 | return retval; | ||
164 | } | 180 | } |
165 | 181 | ||
166 | /** | 182 | /** |