[S390] dasd: fix refcounting.
authorStefan Haberland <stefan.haberland@de.ibm.com>
Fri, 26 Feb 2010 21:37:47 +0000 (22:37 +0100)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Fri, 26 Feb 2010 21:37:32 +0000 (22:37 +0100)
The function dasd_device_from_cdev returns a reference to the dasd
device and increases the refcount by one. If an exception occurs,
the refcount was not decreased in all cases
e.g. in dasd_discipline_show.
Prevent the offline processing from hang by correcting two functions
to decrease the refcount even if an error occured.

Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c

index 56df3c5..302ca14 100644 (file)
@@ -1003,12 +1003,20 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
                return;
        }
 
-       device = (struct dasd_device *) cqr->startdev;
-       if (device == NULL ||
-           device != dasd_device_from_cdev_locked(cdev) ||
-           strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+       device = dasd_device_from_cdev_locked(cdev);
+       if (IS_ERR(device)) {
+               DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s",
+                               "unable to get device from cdev");
+               return;
+       }
+
+       if (!cqr->startdev ||
+           device != cqr->startdev ||
+           strncmp(cqr->startdev->discipline->ebcname,
+                   (char *) &cqr->magic, 4)) {
                DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s",
                                "invalid device in request");
+               dasd_put_device(device);
                return;
        }
 
@@ -2291,11 +2299,6 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
        if (ret)
                pr_warning("%s: Setting the DASD online failed with rc=%d\n",
                           dev_name(&cdev->dev), ret);
-       else {
-               struct dasd_device *device = dasd_device_from_cdev(cdev);
-               wait_event(dasd_init_waitq, _wait_for_device(device));
-               dasd_put_device(device);
-       }
 }
 
 /*
@@ -2430,6 +2433,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,
        } else
                pr_debug("dasd_generic device %s found\n",
                                dev_name(&cdev->dev));
+
+       wait_event(dasd_init_waitq, _wait_for_device(device));
+
        dasd_put_device(device);
        return rc;
 }
index 4cac5b5..d49766f 100644 (file)
@@ -874,12 +874,19 @@ dasd_discipline_show(struct device *dev, struct device_attribute *attr,
        ssize_t len;
 
        device = dasd_device_from_cdev(to_ccwdev(dev));
-       if (!IS_ERR(device) && device->discipline) {
+       if (IS_ERR(device))
+               goto out;
+       else if (!device->discipline) {
+               dasd_put_device(device);
+               goto out;
+       } else {
                len = snprintf(buf, PAGE_SIZE, "%s\n",
                               device->discipline->name);
                dasd_put_device(device);
-       } else
-               len = snprintf(buf, PAGE_SIZE, "none\n");
+               return len;
+       }
+out:
+       len = snprintf(buf, PAGE_SIZE, "none\n");
        return len;
 }