[S390] ccwgroup: add locking around drvdata access
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Wed, 26 May 2010 21:27:07 +0000 (23:27 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Wed, 26 May 2010 21:27:09 +0000 (23:27 +0200)
Several processes may concurrently try to create a group device
from the same ccw_device(s). Add locking arround the drvdata
access to prevent race conditions.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/ccwgroup.c

index 5f97ea2ee6b19f8b6ca80ac7e70239ab2f1dca7e..97b25d68e3e72c74c53994abf7cc140795774525 100644 (file)
@@ -123,8 +123,10 @@ ccwgroup_release (struct device *dev)
 
        for (i = 0; i < gdev->count; i++) {
                if (gdev->cdev[i]) {
+                       spin_lock_irq(gdev->cdev[i]->ccwlock);
                        if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
                                dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+                       spin_unlock_irq(gdev->cdev[i]->ccwlock);
                        put_device(&gdev->cdev[i]->dev);
                }
        }
@@ -262,11 +264,14 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
                        goto error;
                }
                /* Don't allow a device to belong to more than one group. */
+               spin_lock_irq(gdev->cdev[i]->ccwlock);
                if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
+                       spin_unlock_irq(gdev->cdev[i]->ccwlock);
                        rc = -EINVAL;
                        goto error;
                }
                dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
+               spin_unlock_irq(gdev->cdev[i]->ccwlock);
        }
        /* Check for sufficient number of bus ids. */
        if (i < num_devices && !curr_buf) {
@@ -303,8 +308,10 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
 error:
        for (i = 0; i < num_devices; i++)
                if (gdev->cdev[i]) {
+                       spin_lock_irq(gdev->cdev[i]->ccwlock);
                        if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
                                dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+                       spin_unlock_irq(gdev->cdev[i]->ccwlock);
                        put_device(&gdev->cdev[i]->dev);
                        gdev->cdev[i] = NULL;
                }