]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/s390/cio/ccwgroup.c
Merge branch 'agp-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[linux-2.6-omap-h63xx.git] / drivers / s390 / cio / ccwgroup.c
index 3ac2c2019f5e28ffae89e7c0d07f965be297f500..918e6fce2573fcd9fe18e61a41c6d26fd3872c56 100644 (file)
@@ -19,6 +19,8 @@
 #include <asm/ccwdev.h>
 #include <asm/ccwgroup.h>
 
+#define CCW_BUS_ID_SIZE                20
+
 /* In Linux 2.4, we had a channel device layer called "chandev"
  * that did all sorts of obscure stuff for networking devices.
  * This is another driver that serves as a replacement for just
@@ -89,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;
 }
 
@@ -172,7 +182,7 @@ static int __get_next_bus_id(const char **buf, char *bus_id)
                len = end - start + 1;
                end++;
        }
-       if (len < BUS_ID_SIZE) {
+       if (len < CCW_BUS_ID_SIZE) {
                strlcpy(bus_id, start, len);
                rc = 0;
        } else
@@ -181,7 +191,7 @@ static int __get_next_bus_id(const char **buf, char *bus_id)
        return rc;
 }
 
-static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
+static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE])
 {
        int cssid, ssid, devno;
 
@@ -213,7 +223,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
 {
        struct ccwgroup_device *gdev;
        int rc, i;
-       char tmp_bus_id[BUS_ID_SIZE];
+       char tmp_bus_id[CCW_BUS_ID_SIZE];
        const char *curr_buf;
 
        gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),