diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2008-12-25 07:39:04 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:39:06 -0500 |
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 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 | |||
91 | 91 | ||
92 | gdev = to_ccwgroupdev(dev); | 92 | gdev = to_ccwgroupdev(dev); |
93 | 93 | ||
94 | if (gdev->state != CCWGROUP_OFFLINE) | 94 | /* Prevent concurrent online/offline processing and ungrouping. */ |
95 | return -EINVAL; | 95 | if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) |
96 | 96 | return -EAGAIN; | |
97 | if (gdev->state != CCWGROUP_OFFLINE) { | ||
98 | rc = -EINVAL; | ||
99 | goto out; | ||
100 | } | ||
97 | /* Note that we cannot unregister the device from one of its | 101 | /* Note that we cannot unregister the device from one of its |
98 | * attribute methods, so we have to use this roundabout approach. | 102 | * attribute methods, so we have to use this roundabout approach. |
99 | */ | 103 | */ |
100 | rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); | 104 | rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); |
101 | if (rc) | 105 | out: |
102 | count = rc; | 106 | if (rc) { |
107 | /* Release onoff "lock" when ungrouping failed. */ | ||
108 | atomic_set(&gdev->onoff, 0); | ||
109 | return rc; | ||
110 | } | ||
103 | return count; | 111 | return count; |
104 | } | 112 | } |
105 | 113 | ||