mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-04 10:12:16 +09:00
s390/cio: allow to reset channel measurement block
commit0f5d050ceaupstream. Prior to commit1bc6664bdfa call to enable_cmf for a device for which channel measurement was already enabled resulted in a reset of the measurement data. What looked like bugs at the time (a 2nd allocation was triggered but failed, reset was called regardless of previous failures, and errors have not been reported to userspace) was actually something at least one userspace tool depended on. Restore that behavior in a sane way. Fixes:1bc6664bdf("s390/cio: use device_lock during cmb activation") Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
144941bd99
commit
e990e8ba92
@@ -753,6 +753,17 @@ static void reset_cmb(struct ccw_device *cdev)
|
||||
cmf_generic_reset(cdev);
|
||||
}
|
||||
|
||||
static int cmf_enabled(struct ccw_device *cdev)
|
||||
{
|
||||
int enabled;
|
||||
|
||||
spin_lock_irq(cdev->ccwlock);
|
||||
enabled = !!cdev->private->cmb;
|
||||
spin_unlock_irq(cdev->ccwlock);
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static struct attribute_group cmf_attr_group;
|
||||
|
||||
static struct cmb_operations cmbops_basic = {
|
||||
@@ -1153,13 +1164,8 @@ static ssize_t cmb_enable_show(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct ccw_device *cdev = to_ccwdev(dev);
|
||||
int enabled;
|
||||
|
||||
spin_lock_irq(cdev->ccwlock);
|
||||
enabled = !!cdev->private->cmb;
|
||||
spin_unlock_irq(cdev->ccwlock);
|
||||
|
||||
return sprintf(buf, "%d\n", enabled);
|
||||
return sprintf(buf, "%d\n", cmf_enabled(cdev));
|
||||
}
|
||||
|
||||
static ssize_t cmb_enable_store(struct device *dev,
|
||||
@@ -1199,15 +1205,20 @@ int ccw_set_cmf(struct ccw_device *cdev, int enable)
|
||||
* @cdev: The ccw device to be enabled
|
||||
*
|
||||
* Returns %0 for success or a negative error value.
|
||||
*
|
||||
* Note: If this is called on a device for which channel measurement is already
|
||||
* enabled a reset of the measurement data is triggered.
|
||||
* Context:
|
||||
* non-atomic
|
||||
*/
|
||||
int enable_cmf(struct ccw_device *cdev)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
device_lock(&cdev->dev);
|
||||
if (cmf_enabled(cdev)) {
|
||||
cmbops->reset(cdev);
|
||||
goto out_unlock;
|
||||
}
|
||||
get_device(&cdev->dev);
|
||||
ret = cmbops->alloc(cdev);
|
||||
if (ret)
|
||||
@@ -1226,7 +1237,7 @@ int enable_cmf(struct ccw_device *cdev)
|
||||
out:
|
||||
if (ret)
|
||||
put_device(&cdev->dev);
|
||||
|
||||
out_unlock:
|
||||
device_unlock(&cdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user