summary refs log tree commit diff
path: root/drivers/s390
diff options
context:
space:
mode:
authorHorst Hummel <horst.hummel@de.ibm.com>2005-09-03 15:57:58 -0700
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 00:06:26 -0700
commitc6eb7b7703ac4b3401b74f411c8c51ded214bf19 (patch)
tree1cb3563cb83f80347dbc3e4bd30c4635d401e87a /drivers/s390
parent942eaabd5d77522223a311ed9bddaaa3cefde27d (diff)
downloadlinux-c6eb7b7703ac4b3401b74f411c8c51ded214bf19.tar.gz
[PATCH] s390: deadlock in dasd_devmap
Reintroduce a read-only copy of the devmap features in the device struct.
This is necessary to solve a deadlock on the dasd_devmap_lock which is
acquired by dasd_get_features called from the dasd tasklet.  The current
implementation of devmap doesn't allow to call any devmap function from
interrupt or softirq context.

Signed-off-by: Horst Hummel <horst.hummel@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c19
-rw-r--r--drivers/s390/block/dasd_devmap.c8
-rw-r--r--drivers/s390/block/dasd_genhd.c10
-rw-r--r--drivers/s390/block/dasd_int.h3
-rw-r--r--drivers/s390/block/dasd_ioctl.c17
-rw-r--r--drivers/s390/block/dasd_proc.c8
6 files changed, 24 insertions, 41 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index d5f53980749b..8fc891a9d47f 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.165 $
+ * $Revision: 1.167 $
  */
 
 #include <linux/config.h>
@@ -1131,17 +1131,13 @@ __dasd_process_blk_queue(struct dasd_device * device)
 	request_queue_t *queue;
 	struct request *req;
 	struct dasd_ccw_req *cqr;
-	int nr_queued, feature_ro;
+	int nr_queued;
 
 	queue = device->request_queue;
 	/* No queue ? Then there is nothing to do. */
 	if (queue == NULL)
 		return;
 
-	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-	if (feature_ro < 0) 	/* no devmap */
-		return;
-
 	/*
 	 * We requeue request from the block device queue to the ccw
 	 * queue only in two states. In state DASD_STATE_READY the
@@ -1162,7 +1158,8 @@ __dasd_process_blk_queue(struct dasd_device * device)
 		nr_queued < DASD_CHANQ_MAX_SIZE) {
 		req = elv_next_request(queue);
 
-		if (feature_ro && rq_data_dir(req) == WRITE) {
+		if (device->features & DASD_FEATURE_READONLY &&
+		    rq_data_dir(req) == WRITE) {
 			DBF_DEV_EVENT(DBF_ERR, device,
 				      "Rejecting write request %p",
 				      req);
@@ -1814,17 +1811,13 @@ dasd_generic_set_online (struct ccw_device *cdev,
 
 {
 	struct dasd_device *device;
-	int feature_diag, rc;
+	int rc;
 
 	device = dasd_create_device(cdev);
 	if (IS_ERR(device))
 		return PTR_ERR(device);
 
-	feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG);
-	if (feature_diag < 0)
-		return feature_diag;
-
-	if (feature_diag) {
+	if (device->features & DASD_FEATURE_USEDIAG) {
 	  	if (!dasd_diag_discipline_pointer) {
 		        printk (KERN_WARNING
 				"dasd_generic couldn't online device %s "
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index d948566bb24a..bda896d9d788 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -11,7 +11,7 @@
  * functions may not be called from interrupt context. In particular
  * dasd_get_device is a no-no from interrupt context.
  *
- * $Revision: 1.40 $
+ * $Revision: 1.43 $
  */
 
 #include <linux/config.h>
@@ -513,6 +513,7 @@ dasd_create_device(struct ccw_device *cdev)
 	if (!devmap->device) {
 		devmap->device = device;
 		device->devindex = devmap->devindex;
+		device->features = devmap->features;
 		get_device(&cdev->dev);
 		device->cdev = cdev;
 		rc = 0;
@@ -643,6 +644,8 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf
 		devmap->features |= DASD_FEATURE_READONLY;
 	else
 		devmap->features &= ~DASD_FEATURE_READONLY;
+	if (devmap->device)
+		devmap->device->features = devmap->features;
 	if (devmap->device && devmap->device->gdp)
 		set_disk_ro(devmap->device->gdp, ro_flag);
 	spin_unlock(&dasd_devmap_lock);
@@ -758,7 +761,8 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
 		devmap->features |= feature;
 	else
 		devmap->features &= ~feature;
-
+	if (devmap->device)
+		devmap->device->features = devmap->features;
 	spin_unlock(&dasd_devmap_lock);
 	return 0;
 }
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 96c49349701f..a601c9a33541 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -9,7 +9,7 @@
  *
  * gendisk related functions for the dasd driver.
  *
- * $Revision: 1.50 $
+ * $Revision: 1.51 $
  */
 
 #include <linux/config.h>
@@ -31,16 +31,12 @@ int
 dasd_gendisk_alloc(struct dasd_device *device)
 {
 	struct gendisk *gdp;
-	int len, feature_ro;
+	int len;
 
 	/* Make sure the minor for this device exists. */
 	if (device->devindex >= DASD_PER_MAJOR)
 		return -EBUSY;
 
-	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-	if (feature_ro < 0)
-		return feature_ro;
-
 	gdp = alloc_disk(1 << DASD_PARTN_BITS);
 	if (!gdp)
 		return -ENOMEM;
@@ -75,7 +71,7 @@ dasd_gendisk_alloc(struct dasd_device *device)
 
  	sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
 
-	if (feature_ro)
+	if (device->features & DASD_FEATURE_READONLY)
 		set_disk_ro(gdp, 1);
 	gdp->private_data = device;
 	gdp->queue = device->request_queue;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index a9f38b235981..9fab04f3056d 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.64 $
+ * $Revision: 1.65 $
  */
 
 #ifndef DASD_INT_H
@@ -286,6 +286,7 @@ struct dasd_device {
 	unsigned int bp_block;		/* bytes per block */
 	unsigned int s2b_shift;		/* log2 (bp_block/512) */
 	unsigned long flags;		/* per device flags */
+	unsigned short features;        /* copy of devmap-features (read-only!) */
 
 	/* Device discipline stuff. */
 	struct dasd_discipline *discipline;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 980c555aa538..789595b3fa09 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.45 $
+ * $Revision: 1.47 $
  *
  * i/o controls for the dasd driver.
  */
@@ -296,7 +296,6 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
 {
 	struct dasd_device *device;
 	struct format_data_t fdata;
-	int feature_ro;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -308,10 +307,7 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
 	if (device == NULL)
 		return -ENODEV;
 
-	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-	if (feature_ro < 0)
-		return feature_ro;
-	if (feature_ro)
+	if (device->features & DASD_FEATURE_READONLY)
 		return -EROFS;
 	if (copy_from_user(&fdata, (void __user *) args,
 			   sizeof (struct format_data_t)))
@@ -384,7 +380,7 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
 	struct dasd_device *device;
 	struct dasd_information2_t *dasd_info;
 	unsigned long flags;
-	int rc, feature_ro;
+	int rc;
 	struct ccw_device *cdev;
 
 	device = bdev->bd_disk->private_data;
@@ -394,10 +390,6 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
 	if (!device->discipline->fill_info)
 		return -EINVAL;
 
-	feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-	if (feature_ro < 0)
-		return feature_ro;
-
 	dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
 	if (dasd_info == NULL)
 		return -ENOMEM;
@@ -427,7 +419,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
 	    (dasd_check_blocksize(device->bp_block)))
 		dasd_info->format = DASD_FORMAT_NONE;
 
-	dasd_info->features |= feature_ro;
+	dasd_info->features |=
+		((device->features & DASD_FEATURE_READONLY) != 0);
 
 	if (device->discipline)
 		memcpy(dasd_info->type, device->discipline->name, 4);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 43c34f8c5e68..fff9020d4886 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -9,7 +9,7 @@
  *
  * /proc interface for the dasd driver.
  *
- * $Revision: 1.32 $
+ * $Revision: 1.33 $
  */
 
 #include <linux/config.h>
@@ -55,7 +55,6 @@ dasd_devices_show(struct seq_file *m, void *v)
 {
 	struct dasd_device *device;
 	char *substr;
-	int feature;
 
 	device = dasd_device_from_devindex((unsigned long) v - 1);
 	if (IS_ERR(device))
@@ -79,10 +78,7 @@ dasd_devices_show(struct seq_file *m, void *v)
 	else
 		seq_printf(m, " is ????????");
 	/* Print devices features. */
-	feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
-	if (feature < 0)
-		return 0;
-	substr = feature ? "(ro)" : " ";
+	substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
 	seq_printf(m, "%4s: ", substr);
 	/* Print device status information. */
 	switch ((device != NULL) ? device->state : -1) {