summary refs log tree commit diff
path: root/drivers/s390
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2015-09-15 13:11:42 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-10-14 14:32:02 +0200
commit1bc6664bdfb949bc69a08113801e7d6acbf6bc3f (patch)
tree5426526ca602c9394d3501cf15cf61fa5acc2695 /drivers/s390
parent279b8f9a0f3ea3399764047d487dfdd8f7bc9795 (diff)
downloadlinux-1bc6664bdfb949bc69a08113801e7d6acbf6bc3f.tar.gz
s390/cio: use device_lock during cmb activation
Hold the device_lock during [de]activation of the channel measurement
block to synchronize concurrent usage of these functions.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/cmf.c49
-rw-r--r--drivers/s390/cio/device.c2
2 files changed, 38 insertions, 13 deletions
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 3543c486dcdc..5eeb62c3f33a 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1226,41 +1226,66 @@ int enable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
+	device_lock(&cdev->dev);
 	ret = cmbops->alloc(cdev);
-	cmbops->reset(cdev);
 	if (ret)
-		return ret;
+		goto out;
+	cmbops->reset(cdev);
+	ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group);
+	if (ret) {
+		cmbops->free(cdev);
+		goto out;
+	}
 	ret = cmbops->set(cdev, 2);
 	if (ret) {
+		sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);
 		cmbops->free(cdev);
-		return ret;
 	}
-	ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group);
-	if (!ret)
-		return 0;
-	cmbops->set(cdev, 0);  //FIXME: this can fail
-	cmbops->free(cdev);
+out:
+	device_unlock(&cdev->dev);
 	return ret;
 }
 
 /**
- * disable_cmf() - switch off the channel measurement for a specific device
+ * __disable_cmf() - switch off the channel measurement for a specific device
  *  @cdev:	The ccw device to be disabled
  *
  *  Returns %0 for success or a negative error value.
  *
  *  Context:
- *    non-atomic
+ *    non-atomic, device_lock() held.
  */
-int disable_cmf(struct ccw_device *cdev)
+int __disable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
 	ret = cmbops->set(cdev, 0);
 	if (ret)
 		return ret;
-	cmbops->free(cdev);
+
 	sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);
+	cmbops->free(cdev);
+
+	return ret;
+}
+
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ *  @cdev:	The ccw device to be disabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
+{
+	int ret;
+
+	device_lock(&cdev->dev);
+	ret = __disable_cmf(cdev);
+	device_unlock(&cdev->dev);
+
 	return ret;
 }
 
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index dfef5e63cb7b..20b92c703944 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1797,7 +1797,7 @@ static void ccw_device_shutdown(struct device *dev)
 	cdev = to_ccwdev(dev);
 	if (cdev->drv && cdev->drv->shutdown)
 		cdev->drv->shutdown(cdev);
-	disable_cmf(cdev);
+	__disable_cmf(cdev);
 }
 
 static int ccw_device_pm_prepare(struct device *dev)