diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2015-09-15 13:11:42 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-10-14 14:32:02 +0200 |
commit | 1bc6664bdfb949bc69a08113801e7d6acbf6bc3f (patch) | |
tree | 5426526ca602c9394d3501cf15cf61fa5acc2695 /drivers/s390/cio/cmf.c | |
parent | 279b8f9a0f3ea3399764047d487dfdd8f7bc9795 (diff) |
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/cio/cmf.c')
-rw-r--r-- | drivers/s390/cio/cmf.c | 49 |
1 files changed, 37 insertions, 12 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; } |