Browse Source

[S390] dasd: fix refcounting.

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>
Stefan Haberland 15 years ago
parent
commit
589c74d507
2 changed files with 25 additions and 12 deletions
  1. 15 9
      drivers/s390/block/dasd.c
  2. 10 3
      drivers/s390/block/dasd_devmap.c

+ 15 - 9
drivers/s390/block/dasd.c

@@ -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;
 }

+ 10 - 3
drivers/s390/block/dasd_devmap.c

@@ -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;
 }