summary refs log tree commit diff
path: root/drivers/s390/block/dasd_devmap.c
diff options
context:
space:
mode:
authorJan Höppner <hoeppner@linux.vnet.ibm.com>2016-10-12 12:51:04 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-10-28 10:09:04 +0200
commit9de67725c80cb8a7b34b1932e196d2ed61a08879 (patch)
tree3a29c6b57286e62cd550542abcddde4c8fde34bc /drivers/s390/block/dasd_devmap.c
parent0f57c97f241b4fc18251fb2b1c499e9f71e93c78 (diff)
downloadlinux-9de67725c80cb8a7b34b1932e196d2ed61a08879.tar.gz
s390/dasd: Fix locking issue when changing EER attribute
The reference to a device in question may get lost when the extended
error reporting (EER) attribute is being enabled/disabled while the
device is set offline at the same time. This is due to missing
refcounting and incorrect locking. Fix this by the following:

- In dasd_eer_store() get the device directly and handle the refcount
  accordingly.
- Move the lock in dasd_eer_enable() up so we can ensure safe
  processing.
- Check if the device is being set offline and return with -EBUSY if so.
- While at it, change the return code from -EPERM to -EMEDIUMTYPE as
  suggested by a FIXME, since that is what we're actually checking.

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd_devmap.c')
-rw-r--r--drivers/s390/block/dasd_devmap.c27
1 files changed, 13 insertions, 14 deletions
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 221d8c8e63d5..c1979ecce821 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -1167,26 +1167,25 @@ static ssize_t
 dasd_eer_store(struct device *dev, struct device_attribute *attr,
 	       const char *buf, size_t count)
 {
-	struct dasd_devmap *devmap;
+	struct dasd_device *device;
 	unsigned int val;
-	int rc;
+	int rc = 0;
 
-	devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
-	if (IS_ERR(devmap))
-		return PTR_ERR(devmap);
-	if (!devmap->device)
-		return -ENODEV;
+	device = dasd_device_from_cdev(to_ccwdev(dev));
+	if (IS_ERR(device))
+		return PTR_ERR(device);
 
 	if (kstrtouint(buf, 0, &val) || val > 1)
 		return -EINVAL;
 
-	if (val) {
-		rc = dasd_eer_enable(devmap->device);
-		if (rc)
-			return rc;
-	} else
-		dasd_eer_disable(devmap->device);
-	return count;
+	if (val)
+		rc = dasd_eer_enable(device);
+	else
+		dasd_eer_disable(device);
+
+	dasd_put_device(device);
+
+	return rc ? : count;
 }
 
 static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);