[S390] cio: fix ccwgroup online vs. ungroup race condition
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>
Thu, 25 Dec 2008 12:39:04 +0000 (13:39 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 25 Dec 2008 12:39:06 +0000 (13:39 +0100)
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>
drivers/s390/cio/ccwgroup.c

index 17fa009d9959788783e7c821b6b04575df45b4f5..918e6fce2573fcd9fe18e61a41c6d26fd3872c56 100644 (file)
@@ -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;
 }