瀏覽代碼

[PATCH] s390: dasd reference counting

When using the dasd diag discipline, the base discipline module (eckd or fba)
can be unloaded, even though the dasd driver requires both discipline modules
(base and diag) to work correctly.

Implement reference counting for both base and diag discipline modules in
order to fix this.

Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Peter Oberparleiter 19 年之前
父節點
當前提交
aa88861fc3
共有 2 個文件被更改,包括 21 次插入1 次删除
  1. 20 1
      drivers/s390/block/dasd.c
  2. 1 0
      drivers/s390/block/dasd_int.h

+ 20 - 1
drivers/s390/block/dasd.c

@@ -156,7 +156,12 @@ dasd_state_known_to_new(struct dasd_device * device)
 	/* disable extended error reporting for this device */
 	/* disable extended error reporting for this device */
 	dasd_disable_eer(device);
 	dasd_disable_eer(device);
 	/* Forget the discipline information. */
 	/* Forget the discipline information. */
+	if (device->discipline)
+		module_put(device->discipline->owner);
 	device->discipline = NULL;
 	device->discipline = NULL;
+	if (device->base_discipline)
+		module_put(device->base_discipline->owner);
+	device->base_discipline = NULL;
 	device->state = DASD_STATE_NEW;
 	device->state = DASD_STATE_NEW;
 
 
 	dasd_free_queue(device);
 	dasd_free_queue(device);
@@ -1880,9 +1885,10 @@ dasd_generic_remove (struct ccw_device *cdev)
  */
  */
 int
 int
 dasd_generic_set_online (struct ccw_device *cdev,
 dasd_generic_set_online (struct ccw_device *cdev,
-			 struct dasd_discipline *discipline)
+			 struct dasd_discipline *base_discipline)
 
 
 {
 {
+	struct dasd_discipline *discipline;
 	struct dasd_device *device;
 	struct dasd_device *device;
 	int rc;
 	int rc;
 
 
@@ -1890,6 +1896,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
 	if (IS_ERR(device))
 	if (IS_ERR(device))
 		return PTR_ERR(device);
 		return PTR_ERR(device);
 
 
+	discipline = base_discipline;
 	if (device->features & DASD_FEATURE_USEDIAG) {
 	if (device->features & DASD_FEATURE_USEDIAG) {
 	  	if (!dasd_diag_discipline_pointer) {
 	  	if (!dasd_diag_discipline_pointer) {
 		        printk (KERN_WARNING
 		        printk (KERN_WARNING
@@ -1901,6 +1908,16 @@ dasd_generic_set_online (struct ccw_device *cdev,
 		}
 		}
 		discipline = dasd_diag_discipline_pointer;
 		discipline = dasd_diag_discipline_pointer;
 	}
 	}
+	if (!try_module_get(base_discipline->owner)) {
+		dasd_delete_device(device);
+		return -EINVAL;
+	}
+	if (!try_module_get(discipline->owner)) {
+		module_put(base_discipline->owner);
+		dasd_delete_device(device);
+		return -EINVAL;
+	}
+	device->base_discipline = base_discipline;
 	device->discipline = discipline;
 	device->discipline = discipline;
 
 
 	rc = discipline->check_device(device);
 	rc = discipline->check_device(device);
@@ -1909,6 +1926,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
 			"dasd_generic couldn't online device %s "
 			"dasd_generic couldn't online device %s "
 			"with discipline %s rc=%i\n",
 			"with discipline %s rc=%i\n",
 			cdev->dev.bus_id, discipline->name, rc);
 			cdev->dev.bus_id, discipline->name, rc);
+		module_put(discipline->owner);
+		module_put(base_discipline->owner);
 		dasd_delete_device(device);
 		dasd_delete_device(device);
 		return rc;
 		return rc;
 	}
 	}

+ 1 - 0
drivers/s390/block/dasd_int.h

@@ -321,6 +321,7 @@ struct dasd_device {
 
 
 	/* Device discipline stuff. */
 	/* Device discipline stuff. */
 	struct dasd_discipline *discipline;
 	struct dasd_discipline *discipline;
+	struct dasd_discipline *base_discipline;
 	char *private;
 	char *private;
 
 
 	/* Device state and target state. */
 	/* Device state and target state. */