diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2008-12-25 13:39:04 +0100 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 13:39:06 +0100 |
commit | c619d4223eaa063dd15ce44235b04487235f8cb7 (patch) | |
tree | 3ffc818d3681b467b362f854977a546e12b41d49 /drivers/s390/cio/ccwgroup.c | |
parent | 111e95a4cae01d6dadbbd1d8ab28dcd10fa5619c (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.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 17fa009d995..918e6fce257 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; } |