s390/cio: fix unlocked access of online member
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Mon, 16 Dec 2013 09:51:54 +0000 (10:51 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 16 Dec 2013 13:38:01 +0000 (14:38 +0100)
Make sure that access to the online member of a ccw device is
guarded by the ccwlock.

Reported-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/device.c

index e4a7ab2bb629f76358896e1389072c391fe3504c..4a0734fcc83c819b55cd8e6832ca89971b03f3a0 100644 (file)
@@ -333,9 +333,9 @@ int ccw_device_set_offline(struct ccw_device *cdev)
                if (ret != 0)
                        return ret;
        }
-       cdev->online = 0;
        spin_lock_irq(cdev->ccwlock);
        sch = to_subchannel(cdev->dev.parent);
+       cdev->online = 0;
        /* Wait until a final state or DISCONNECTED is reached */
        while (!dev_fsm_final_state(cdev) &&
               cdev->private->state != DEV_STATE_DISCONNECTED) {
@@ -446,7 +446,10 @@ int ccw_device_set_online(struct ccw_device *cdev)
                ret = cdev->drv->set_online(cdev);
        if (ret)
                goto rollback;
+
+       spin_lock_irq(cdev->ccwlock);
        cdev->online = 1;
+       spin_unlock_irq(cdev->ccwlock);
        return 0;
 
 rollback:
@@ -1745,8 +1748,7 @@ ccw_device_probe (struct device *dev)
        return 0;
 }
 
-static int
-ccw_device_remove (struct device *dev)
+static int ccw_device_remove(struct device *dev)
 {
        struct ccw_device *cdev = to_ccwdev(dev);
        struct ccw_driver *cdrv = cdev->drv;
@@ -1754,9 +1756,10 @@ ccw_device_remove (struct device *dev)
 
        if (cdrv->remove)
                cdrv->remove(cdev);
+
+       spin_lock_irq(cdev->ccwlock);
        if (cdev->online) {
                cdev->online = 0;
-               spin_lock_irq(cdev->ccwlock);
                ret = ccw_device_offline(cdev);
                spin_unlock_irq(cdev->ccwlock);
                if (ret == 0)
@@ -1769,10 +1772,12 @@ ccw_device_remove (struct device *dev)
                                      cdev->private->dev_id.devno);
                /* Give up reference obtained in ccw_device_set_online(). */
                put_device(&cdev->dev);
+               spin_lock_irq(cdev->ccwlock);
        }
        ccw_device_set_timeout(cdev, 0);
        cdev->drv = NULL;
        cdev->private->int_class = IRQIO_CIO;
+       spin_unlock_irq(cdev->ccwlock);
        return 0;
 }