Skip to content

Commit d99b601

Browse files
steffen-maierJames Bottomley
authored and
James Bottomley
committed
[SCSI] zfcp: restore refcount check on port_remove
Upstream commit f3450c7 "[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>
1 parent ca579c9 commit d99b601

File tree

5 files changed

+45
-12
lines changed

5 files changed

+45
-12
lines changed

drivers/s390/scsi/zfcp_aux.c

+1
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
519519

520520
rwlock_init(&port->unit_list_lock);
521521
INIT_LIST_HEAD(&port->unit_list);
522+
atomic_set(&port->units, 0);
522523

523524
INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);
524525
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);

drivers/s390/scsi/zfcp_def.h

+1
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ struct zfcp_port {
205205
struct zfcp_adapter *adapter; /* adapter used to access port */
206206
struct list_head unit_list; /* head of logical unit list */
207207
rwlock_t unit_list_lock; /* unit list lock */
208+
atomic_t units; /* zfcp_unit count */
208209
atomic_t status; /* status of this remote port */
209210
u64 wwnn; /* WWNN if known */
210211
u64 wwpn; /* WWPN */

drivers/s390/scsi/zfcp_ext.h

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);
159159
extern struct attribute_group zfcp_sysfs_unit_attrs;
160160
extern struct attribute_group zfcp_sysfs_adapter_attrs;
161161
extern struct attribute_group zfcp_sysfs_port_attrs;
162+
extern struct mutex zfcp_sysfs_port_units_mutex;
162163
extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
163164
extern struct device_attribute *zfcp_sysfs_shost_attrs[];
164165

drivers/s390/scsi/zfcp_sysfs.c

+16-2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
227227
static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
228228
zfcp_sysfs_port_rescan_store);
229229

230+
DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
231+
230232
static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
231233
struct device_attribute *attr,
232234
const char *buf, size_t count)
@@ -249,6 +251,16 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
249251
else
250252
retval = 0;
251253

254+
mutex_lock(&zfcp_sysfs_port_units_mutex);
255+
if (atomic_read(&port->units) > 0) {
256+
retval = -EBUSY;
257+
mutex_unlock(&zfcp_sysfs_port_units_mutex);
258+
goto out;
259+
}
260+
/* port is about to be removed, so no more unit_add */
261+
atomic_set(&port->units, -1);
262+
mutex_unlock(&zfcp_sysfs_port_units_mutex);
263+
252264
write_lock_irq(&adapter->port_list_lock);
253265
list_del(&port->list);
254266
write_unlock_irq(&adapter->port_list_lock);
@@ -289,12 +301,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
289301
{
290302
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
291303
u64 fcp_lun;
304+
int retval;
292305

293306
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
294307
return -EINVAL;
295308

296-
if (zfcp_unit_add(port, fcp_lun))
297-
return -EINVAL;
309+
retval = zfcp_unit_add(port, fcp_lun);
310+
if (retval)
311+
return retval;
298312

299313
return count;
300314
}

drivers/s390/scsi/zfcp_unit.c

+26-10
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static void zfcp_unit_release(struct device *dev)
104104
{
105105
struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
106106

107-
put_device(&unit->port->dev);
107+
atomic_dec(&unit->port->units);
108108
kfree(unit);
109109
}
110110

@@ -119,16 +119,27 @@ static void zfcp_unit_release(struct device *dev)
119119
int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
120120
{
121121
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+
}
122130

123131
unit = zfcp_unit_find(port, fcp_lun);
124132
if (unit) {
125133
put_device(&unit->dev);
126-
return -EEXIST;
134+
retval = -EEXIST;
135+
goto out;
127136
}
128137

129138
unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
130-
if (!unit)
131-
return -ENOMEM;
139+
if (!unit) {
140+
retval = -ENOMEM;
141+
goto out;
142+
}
132143

133144
unit->port = port;
134145
unit->fcp_lun = fcp_lun;
@@ -139,28 +150,33 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
139150
if (dev_set_name(&unit->dev, "0x%016llx",
140151
(unsigned long long) fcp_lun)) {
141152
kfree(unit);
142-
return -ENOMEM;
153+
retval = -ENOMEM;
154+
goto out;
143155
}
144156

145-
get_device(&port->dev);
146-
147157
if (device_register(&unit->dev)) {
148158
put_device(&unit->dev);
149-
return -ENOMEM;
159+
retval = -ENOMEM;
160+
goto out;
150161
}
151162

152163
if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) {
153164
device_unregister(&unit->dev);
154-
return -EINVAL;
165+
retval = -EINVAL;
166+
goto out;
155167
}
156168

169+
atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */
170+
157171
write_lock_irq(&port->unit_list_lock);
158172
list_add_tail(&unit->list, &port->unit_list);
159173
write_unlock_irq(&port->unit_list_lock);
160174

161175
zfcp_unit_scsi_scan(unit);
162176

163-
return 0;
177+
out:
178+
mutex_unlock(&zfcp_sysfs_port_units_mutex);
179+
return retval;
164180
}
165181

166182
/**

0 commit comments

Comments
 (0)