summaryrefslogtreecommitdiff
path: root/drivers/s390/cio/ccwgroup.c
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2008-12-25 13:39:04 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-12-25 13:39:06 +0100
commitc619d4223eaa063dd15ce44235b04487235f8cb7 (patch)
tree3ffc818d3681b467b362f854977a546e12b41d49 /drivers/s390/cio/ccwgroup.c
parent111e95a4cae01d6dadbbd1d8ab28dcd10fa5619c (diff)
[S390] cio: fix ccwgroup online vs. ungroup race condition
Ensure atomicity of ungroup operation to prevent concurrent ungroup and online processing which may lead to use-after-release situations. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/ccwgroup.c')
-rw-r--r--drivers/s390/cio/ccwgroup.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 17fa009d9959..918e6fce2573 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -91,15 +91,23 @@ ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const
gdev = to_ccwgroupdev(dev);
- if (gdev->state != CCWGROUP_OFFLINE)
- return -EINVAL;
-
+ /* Prevent concurrent online/offline processing and ungrouping. */
+ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0)
+ return -EAGAIN;
+ if (gdev->state != CCWGROUP_OFFLINE) {
+ rc = -EINVAL;
+ goto out;
+ }
/* Note that we cannot unregister the device from one of its
* attribute methods, so we have to use this roundabout approach.
*/
rc = device_schedule_callback(dev, ccwgroup_ungroup_callback);
- if (rc)
- count = rc;
+out:
+ if (rc) {
+ /* Release onoff "lock" when ungrouping failed. */
+ atomic_set(&gdev->onoff, 0);
+ return rc;
+ }
return count;
}