diff options
author | Horst Hummel <horst.hummel@de.ibm.com> | 2005-09-03 18:57:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:06:26 -0400 |
commit | c6eb7b7703ac4b3401b74f411c8c51ded214bf19 (patch) | |
tree | 1cb3563cb83f80347dbc3e4bd30c4635d401e87a /drivers/s390/block | |
parent | 942eaabd5d77522223a311ed9bddaaa3cefde27d (diff) |
[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/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 19 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 8 | ||||
-rw-r--r-- | drivers/s390/block/dasd_genhd.c | 10 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 17 | ||||
-rw-r--r-- | drivers/s390/block/dasd_proc.c | 8 |
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 @@ | |||
7 | * Bugreports.to..: <Linux390@de.ibm.com> | 7 | * Bugreports.to..: <Linux390@de.ibm.com> |
8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 | 8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 |
9 | * | 9 | * |
10 | * $Revision: 1.165 $ | 10 | * $Revision: 1.167 $ |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/config.h> | 13 | #include <linux/config.h> |
@@ -1131,17 +1131,13 @@ __dasd_process_blk_queue(struct dasd_device * device) | |||
1131 | request_queue_t *queue; | 1131 | request_queue_t *queue; |
1132 | struct request *req; | 1132 | struct request *req; |
1133 | struct dasd_ccw_req *cqr; | 1133 | struct dasd_ccw_req *cqr; |
1134 | int nr_queued, feature_ro; | 1134 | int nr_queued; |
1135 | 1135 | ||
1136 | queue = device->request_queue; | 1136 | queue = device->request_queue; |
1137 | /* No queue ? Then there is nothing to do. */ | 1137 | /* No queue ? Then there is nothing to do. */ |
1138 | if (queue == NULL) | 1138 | if (queue == NULL) |
1139 | return; | 1139 | return; |
1140 | 1140 | ||
1141 | feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); | ||
1142 | if (feature_ro < 0) /* no devmap */ | ||
1143 | return; | ||
1144 | |||
1145 | /* | 1141 | /* |
1146 | * We requeue request from the block device queue to the ccw | 1142 | * We requeue request from the block device queue to the ccw |
1147 | * queue only in two states. In state DASD_STATE_READY the | 1143 | * queue only in two states. In state DASD_STATE_READY the |
@@ -1162,7 +1158,8 @@ __dasd_process_blk_queue(struct dasd_device * device) | |||
1162 | nr_queued < DASD_CHANQ_MAX_SIZE) { | 1158 | nr_queued < DASD_CHANQ_MAX_SIZE) { |
1163 | req = elv_next_request(queue); | 1159 | req = elv_next_request(queue); |
1164 | 1160 | ||
1165 | if (feature_ro && rq_data_dir(req) == WRITE) { | 1161 | if (device->features & DASD_FEATURE_READONLY && |
1162 | rq_data_dir(req) == WRITE) { | ||
1166 | DBF_DEV_EVENT(DBF_ERR, device, | 1163 | DBF_DEV_EVENT(DBF_ERR, device, |
1167 | "Rejecting write request %p", | 1164 | "Rejecting write request %p", |
1168 | req); | 1165 | req); |
@@ -1814,17 +1811,13 @@ dasd_generic_set_online (struct ccw_device *cdev, | |||
1814 | 1811 | ||
1815 | { | 1812 | { |
1816 | struct dasd_device *device; | 1813 | struct dasd_device *device; |
1817 | int feature_diag, rc; | 1814 | int rc; |
1818 | 1815 | ||
1819 | device = dasd_create_device(cdev); | 1816 | device = dasd_create_device(cdev); |
1820 | if (IS_ERR(device)) | 1817 | if (IS_ERR(device)) |
1821 | return PTR_ERR(device); | 1818 | return PTR_ERR(device); |
1822 | 1819 | ||
1823 | feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG); | 1820 | if (device->features & DASD_FEATURE_USEDIAG) { |
1824 | if (feature_diag < 0) | ||
1825 | return feature_diag; | ||
1826 | |||
1827 | if (feature_diag) { | ||
1828 | if (!dasd_diag_discipline_pointer) { | 1821 | if (!dasd_diag_discipline_pointer) { |
1829 | printk (KERN_WARNING | 1822 | printk (KERN_WARNING |
1830 | "dasd_generic couldn't online device %s " | 1823 | "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 @@ | |||
11 | * functions may not be called from interrupt context. In particular | 11 | * functions may not be called from interrupt context. In particular |
12 | * dasd_get_device is a no-no from interrupt context. | 12 | * dasd_get_device is a no-no from interrupt context. |
13 | * | 13 | * |
14 | * $Revision: 1.40 $ | 14 | * $Revision: 1.43 $ |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/config.h> | 17 | #include <linux/config.h> |
@@ -513,6 +513,7 @@ dasd_create_device(struct ccw_device *cdev) | |||
513 | if (!devmap->device) { | 513 | if (!devmap->device) { |
514 | devmap->device = device; | 514 | devmap->device = device; |
515 | device->devindex = devmap->devindex; | 515 | device->devindex = devmap->devindex; |
516 | device->features = devmap->features; | ||
516 | get_device(&cdev->dev); | 517 | get_device(&cdev->dev); |
517 | device->cdev = cdev; | 518 | device->cdev = cdev; |
518 | rc = 0; | 519 | rc = 0; |
@@ -643,6 +644,8 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf | |||
643 | devmap->features |= DASD_FEATURE_READONLY; | 644 | devmap->features |= DASD_FEATURE_READONLY; |
644 | else | 645 | else |
645 | devmap->features &= ~DASD_FEATURE_READONLY; | 646 | devmap->features &= ~DASD_FEATURE_READONLY; |
647 | if (devmap->device) | ||
648 | devmap->device->features = devmap->features; | ||
646 | if (devmap->device && devmap->device->gdp) | 649 | if (devmap->device && devmap->device->gdp) |
647 | set_disk_ro(devmap->device->gdp, ro_flag); | 650 | set_disk_ro(devmap->device->gdp, ro_flag); |
648 | spin_unlock(&dasd_devmap_lock); | 651 | spin_unlock(&dasd_devmap_lock); |
@@ -758,7 +761,8 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) | |||
758 | devmap->features |= feature; | 761 | devmap->features |= feature; |
759 | else | 762 | else |
760 | devmap->features &= ~feature; | 763 | devmap->features &= ~feature; |
761 | 764 | if (devmap->device) | |
765 | devmap->device->features = devmap->features; | ||
762 | spin_unlock(&dasd_devmap_lock); | 766 | spin_unlock(&dasd_devmap_lock); |
763 | return 0; | 767 | return 0; |
764 | } | 768 | } |
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 @@ | |||
9 | * | 9 | * |
10 | * gendisk related functions for the dasd driver. | 10 | * gendisk related functions for the dasd driver. |
11 | * | 11 | * |
12 | * $Revision: 1.50 $ | 12 | * $Revision: 1.51 $ |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/config.h> | 15 | #include <linux/config.h> |
@@ -31,16 +31,12 @@ int | |||
31 | dasd_gendisk_alloc(struct dasd_device *device) | 31 | dasd_gendisk_alloc(struct dasd_device *device) |
32 | { | 32 | { |
33 | struct gendisk *gdp; | 33 | struct gendisk *gdp; |
34 | int len, feature_ro; | 34 | int len; |
35 | 35 | ||
36 | /* Make sure the minor for this device exists. */ | 36 | /* Make sure the minor for this device exists. */ |
37 | if (device->devindex >= DASD_PER_MAJOR) | 37 | if (device->devindex >= DASD_PER_MAJOR) |
38 | return -EBUSY; | 38 | return -EBUSY; |
39 | 39 | ||
40 | feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); | ||
41 | if (feature_ro < 0) | ||
42 | return feature_ro; | ||
43 | |||
44 | gdp = alloc_disk(1 << DASD_PARTN_BITS); | 40 | gdp = alloc_disk(1 << DASD_PARTN_BITS); |
45 | if (!gdp) | 41 | if (!gdp) |
46 | return -ENOMEM; | 42 | return -ENOMEM; |
@@ -75,7 +71,7 @@ dasd_gendisk_alloc(struct dasd_device *device) | |||
75 | 71 | ||
76 | sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); | 72 | sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); |
77 | 73 | ||
78 | if (feature_ro) | 74 | if (device->features & DASD_FEATURE_READONLY) |
79 | set_disk_ro(gdp, 1); | 75 | set_disk_ro(gdp, 1); |
80 | gdp->private_data = device; | 76 | gdp->private_data = device; |
81 | gdp->queue = device->request_queue; | 77 | 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 @@ | |||
6 | * Bugreports.to..: <Linux390@de.ibm.com> | 6 | * Bugreports.to..: <Linux390@de.ibm.com> |
7 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 7 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 |
8 | * | 8 | * |
9 | * $Revision: 1.64 $ | 9 | * $Revision: 1.65 $ |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef DASD_INT_H | 12 | #ifndef DASD_INT_H |
@@ -286,6 +286,7 @@ struct dasd_device { | |||
286 | unsigned int bp_block; /* bytes per block */ | 286 | unsigned int bp_block; /* bytes per block */ |
287 | unsigned int s2b_shift; /* log2 (bp_block/512) */ | 287 | unsigned int s2b_shift; /* log2 (bp_block/512) */ |
288 | unsigned long flags; /* per device flags */ | 288 | unsigned long flags; /* per device flags */ |
289 | unsigned short features; /* copy of devmap-features (read-only!) */ | ||
289 | 290 | ||
290 | /* Device discipline stuff. */ | 291 | /* Device discipline stuff. */ |
291 | struct dasd_discipline *discipline; | 292 | 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 @@ | |||
7 | * Bugreports.to..: <Linux390@de.ibm.com> | 7 | * Bugreports.to..: <Linux390@de.ibm.com> |
8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 | 8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 |
9 | * | 9 | * |
10 | * $Revision: 1.45 $ | 10 | * $Revision: 1.47 $ |
11 | * | 11 | * |
12 | * i/o controls for the dasd driver. | 12 | * i/o controls for the dasd driver. |
13 | */ | 13 | */ |
@@ -296,7 +296,6 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args) | |||
296 | { | 296 | { |
297 | struct dasd_device *device; | 297 | struct dasd_device *device; |
298 | struct format_data_t fdata; | 298 | struct format_data_t fdata; |
299 | int feature_ro; | ||
300 | 299 | ||
301 | if (!capable(CAP_SYS_ADMIN)) | 300 | if (!capable(CAP_SYS_ADMIN)) |
302 | return -EACCES; | 301 | return -EACCES; |
@@ -308,10 +307,7 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args) | |||
308 | if (device == NULL) | 307 | if (device == NULL) |
309 | return -ENODEV; | 308 | return -ENODEV; |
310 | 309 | ||
311 | feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); | 310 | if (device->features & DASD_FEATURE_READONLY) |
312 | if (feature_ro < 0) | ||
313 | return feature_ro; | ||
314 | if (feature_ro) | ||
315 | return -EROFS; | 311 | return -EROFS; |
316 | if (copy_from_user(&fdata, (void __user *) args, | 312 | if (copy_from_user(&fdata, (void __user *) args, |
317 | sizeof (struct format_data_t))) | 313 | sizeof (struct format_data_t))) |
@@ -384,7 +380,7 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) | |||
384 | struct dasd_device *device; | 380 | struct dasd_device *device; |
385 | struct dasd_information2_t *dasd_info; | 381 | struct dasd_information2_t *dasd_info; |
386 | unsigned long flags; | 382 | unsigned long flags; |
387 | int rc, feature_ro; | 383 | int rc; |
388 | struct ccw_device *cdev; | 384 | struct ccw_device *cdev; |
389 | 385 | ||
390 | device = bdev->bd_disk->private_data; | 386 | device = bdev->bd_disk->private_data; |
@@ -394,10 +390,6 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) | |||
394 | if (!device->discipline->fill_info) | 390 | if (!device->discipline->fill_info) |
395 | return -EINVAL; | 391 | return -EINVAL; |
396 | 392 | ||
397 | feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); | ||
398 | if (feature_ro < 0) | ||
399 | return feature_ro; | ||
400 | |||
401 | dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL); | 393 | dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL); |
402 | if (dasd_info == NULL) | 394 | if (dasd_info == NULL) |
403 | return -ENOMEM; | 395 | return -ENOMEM; |
@@ -427,7 +419,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) | |||
427 | (dasd_check_blocksize(device->bp_block))) | 419 | (dasd_check_blocksize(device->bp_block))) |
428 | dasd_info->format = DASD_FORMAT_NONE; | 420 | dasd_info->format = DASD_FORMAT_NONE; |
429 | 421 | ||
430 | dasd_info->features |= feature_ro; | 422 | dasd_info->features |= |
423 | ((device->features & DASD_FEATURE_READONLY) != 0); | ||
431 | 424 | ||
432 | if (device->discipline) | 425 | if (device->discipline) |
433 | memcpy(dasd_info->type, device->discipline->name, 4); | 426 | 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 @@ | |||
9 | * | 9 | * |
10 | * /proc interface for the dasd driver. | 10 | * /proc interface for the dasd driver. |
11 | * | 11 | * |
12 | * $Revision: 1.32 $ | 12 | * $Revision: 1.33 $ |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/config.h> | 15 | #include <linux/config.h> |
@@ -55,7 +55,6 @@ dasd_devices_show(struct seq_file *m, void *v) | |||
55 | { | 55 | { |
56 | struct dasd_device *device; | 56 | struct dasd_device *device; |
57 | char *substr; | 57 | char *substr; |
58 | int feature; | ||
59 | 58 | ||
60 | device = dasd_device_from_devindex((unsigned long) v - 1); | 59 | device = dasd_device_from_devindex((unsigned long) v - 1); |
61 | if (IS_ERR(device)) | 60 | if (IS_ERR(device)) |
@@ -79,10 +78,7 @@ dasd_devices_show(struct seq_file *m, void *v) | |||
79 | else | 78 | else |
80 | seq_printf(m, " is ????????"); | 79 | seq_printf(m, " is ????????"); |
81 | /* Print devices features. */ | 80 | /* Print devices features. */ |
82 | feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY); | 81 | substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " "; |
83 | if (feature < 0) | ||
84 | return 0; | ||
85 | substr = feature ? "(ro)" : " "; | ||
86 | seq_printf(m, "%4s: ", substr); | 82 | seq_printf(m, "%4s: ", substr); |
87 | /* Print device status information. */ | 83 | /* Print device status information. */ |
88 | switch ((device != NULL) ? device->state : -1) { | 84 | switch ((device != NULL) ? device->state : -1) { |