]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Gerald Schaefer <geraldsc@de.ibm.com> |
2 | Subject: cio: ccwgroup online vs. ungroup race condition | |
3 | References: bnc#445100,LTC#50092 | |
4 | ||
5 | Symptom: Kernel oops when a ccwgroup ungroup operation is triggered while | |
6 | online operation is still in progress. | |
7 | Problem: Atomicity of ungroup operation is not guaranteed because of | |
8 | missing locking. | |
9 | Solution: Introduce locking to ungroup operation. | |
10 | ||
11 | Acked-by: John Jolly <jjolly@suse.de> | |
12 | ||
13 | --- | |
14 | drivers/s390/cio/ccwgroup.c | 18 +++++++++++++----- | |
15 | 1 file changed, 13 insertions(+), 5 deletions(-) | |
16 | ||
17 | Index: linux-sles11/drivers/s390/cio/ccwgroup.c | |
18 | =================================================================== | |
19 | --- linux-sles11.orig/drivers/s390/cio/ccwgroup.c | |
20 | +++ linux-sles11/drivers/s390/cio/ccwgroup.c | |
21 | @@ -89,15 +89,23 @@ ccwgroup_ungroup_store(struct device *de | |
22 | ||
23 | gdev = to_ccwgroupdev(dev); | |
24 | ||
25 | - if (gdev->state != CCWGROUP_OFFLINE) | |
26 | - return -EINVAL; | |
27 | - | |
28 | + /* Prevent concurrent online/offline processing and ungrouping. */ | |
29 | + if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) | |
30 | + return -EAGAIN; | |
31 | + if (gdev->state != CCWGROUP_OFFLINE) { | |
32 | + rc = -EINVAL; | |
33 | + goto out; | |
34 | + } | |
35 | /* Note that we cannot unregister the device from one of its | |
36 | * attribute methods, so we have to use this roundabout approach. | |
37 | */ | |
38 | rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); | |
39 | - if (rc) | |
40 | - count = rc; | |
41 | +out: | |
42 | + if (rc) { | |
43 | + /* Release onoff "lock" when ungrouping failed. */ | |
44 | + atomic_set(&gdev->onoff, 0); | |
45 | + return rc; | |
46 | + } | |
47 | return count; | |
48 | } | |
49 |