[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>
This commit is contained in:
committed by
Linus Torvalds
parent
942eaabd5d
commit
c6eb7b7703
@@ -7,7 +7,7 @@
|
|||||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||||
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
|
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
|
||||||
*
|
*
|
||||||
* $Revision: 1.165 $
|
* $Revision: 1.167 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
@@ -1131,17 +1131,13 @@ __dasd_process_blk_queue(struct dasd_device * device)
|
|||||||
request_queue_t *queue;
|
request_queue_t *queue;
|
||||||
struct request *req;
|
struct request *req;
|
||||||
struct dasd_ccw_req *cqr;
|
struct dasd_ccw_req *cqr;
|
||||||
int nr_queued, feature_ro;
|
int nr_queued;
|
||||||
|
|
||||||
queue = device->request_queue;
|
queue = device->request_queue;
|
||||||
/* No queue ? Then there is nothing to do. */
|
/* No queue ? Then there is nothing to do. */
|
||||||
if (queue == NULL)
|
if (queue == NULL)
|
||||||
return;
|
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
|
* We requeue request from the block device queue to the ccw
|
||||||
* queue only in two states. In state DASD_STATE_READY the
|
* 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) {
|
nr_queued < DASD_CHANQ_MAX_SIZE) {
|
||||||
req = elv_next_request(queue);
|
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,
|
DBF_DEV_EVENT(DBF_ERR, device,
|
||||||
"Rejecting write request %p",
|
"Rejecting write request %p",
|
||||||
req);
|
req);
|
||||||
@@ -1814,17 +1811,13 @@ dasd_generic_set_online (struct ccw_device *cdev,
|
|||||||
|
|
||||||
{
|
{
|
||||||
struct dasd_device *device;
|
struct dasd_device *device;
|
||||||
int feature_diag, rc;
|
int rc;
|
||||||
|
|
||||||
device = dasd_create_device(cdev);
|
device = dasd_create_device(cdev);
|
||||||
if (IS_ERR(device))
|
if (IS_ERR(device))
|
||||||
return PTR_ERR(device);
|
return PTR_ERR(device);
|
||||||
|
|
||||||
feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG);
|
if (device->features & DASD_FEATURE_USEDIAG) {
|
||||||
if (feature_diag < 0)
|
|
||||||
return feature_diag;
|
|
||||||
|
|
||||||
if (feature_diag) {
|
|
||||||
if (!dasd_diag_discipline_pointer) {
|
if (!dasd_diag_discipline_pointer) {
|
||||||
printk (KERN_WARNING
|
printk (KERN_WARNING
|
||||||
"dasd_generic couldn't online device %s "
|
"dasd_generic couldn't online device %s "
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
* functions may not be called from interrupt context. In particular
|
* functions may not be called from interrupt context. In particular
|
||||||
* dasd_get_device is a no-no from interrupt context.
|
* dasd_get_device is a no-no from interrupt context.
|
||||||
*
|
*
|
||||||
* $Revision: 1.40 $
|
* $Revision: 1.43 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
@@ -513,6 +513,7 @@ dasd_create_device(struct ccw_device *cdev)
|
|||||||
if (!devmap->device) {
|
if (!devmap->device) {
|
||||||
devmap->device = device;
|
devmap->device = device;
|
||||||
device->devindex = devmap->devindex;
|
device->devindex = devmap->devindex;
|
||||||
|
device->features = devmap->features;
|
||||||
get_device(&cdev->dev);
|
get_device(&cdev->dev);
|
||||||
device->cdev = cdev;
|
device->cdev = cdev;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
@@ -643,6 +644,8 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf
|
|||||||
devmap->features |= DASD_FEATURE_READONLY;
|
devmap->features |= DASD_FEATURE_READONLY;
|
||||||
else
|
else
|
||||||
devmap->features &= ~DASD_FEATURE_READONLY;
|
devmap->features &= ~DASD_FEATURE_READONLY;
|
||||||
|
if (devmap->device)
|
||||||
|
devmap->device->features = devmap->features;
|
||||||
if (devmap->device && devmap->device->gdp)
|
if (devmap->device && devmap->device->gdp)
|
||||||
set_disk_ro(devmap->device->gdp, ro_flag);
|
set_disk_ro(devmap->device->gdp, ro_flag);
|
||||||
spin_unlock(&dasd_devmap_lock);
|
spin_unlock(&dasd_devmap_lock);
|
||||||
@@ -758,7 +761,8 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
|
|||||||
devmap->features |= feature;
|
devmap->features |= feature;
|
||||||
else
|
else
|
||||||
devmap->features &= ~feature;
|
devmap->features &= ~feature;
|
||||||
|
if (devmap->device)
|
||||||
|
devmap->device->features = devmap->features;
|
||||||
spin_unlock(&dasd_devmap_lock);
|
spin_unlock(&dasd_devmap_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* gendisk related functions for the dasd driver.
|
* gendisk related functions for the dasd driver.
|
||||||
*
|
*
|
||||||
* $Revision: 1.50 $
|
* $Revision: 1.51 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
@@ -31,16 +31,12 @@ int
|
|||||||
dasd_gendisk_alloc(struct dasd_device *device)
|
dasd_gendisk_alloc(struct dasd_device *device)
|
||||||
{
|
{
|
||||||
struct gendisk *gdp;
|
struct gendisk *gdp;
|
||||||
int len, feature_ro;
|
int len;
|
||||||
|
|
||||||
/* Make sure the minor for this device exists. */
|
/* Make sure the minor for this device exists. */
|
||||||
if (device->devindex >= DASD_PER_MAJOR)
|
if (device->devindex >= DASD_PER_MAJOR)
|
||||||
return -EBUSY;
|
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);
|
gdp = alloc_disk(1 << DASD_PARTN_BITS);
|
||||||
if (!gdp)
|
if (!gdp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -75,7 +71,7 @@ dasd_gendisk_alloc(struct dasd_device *device)
|
|||||||
|
|
||||||
sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
|
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);
|
set_disk_ro(gdp, 1);
|
||||||
gdp->private_data = device;
|
gdp->private_data = device;
|
||||||
gdp->queue = device->request_queue;
|
gdp->queue = device->request_queue;
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||||
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
|
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
|
||||||
*
|
*
|
||||||
* $Revision: 1.64 $
|
* $Revision: 1.65 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef DASD_INT_H
|
#ifndef DASD_INT_H
|
||||||
@@ -286,6 +286,7 @@ struct dasd_device {
|
|||||||
unsigned int bp_block; /* bytes per block */
|
unsigned int bp_block; /* bytes per block */
|
||||||
unsigned int s2b_shift; /* log2 (bp_block/512) */
|
unsigned int s2b_shift; /* log2 (bp_block/512) */
|
||||||
unsigned long flags; /* per device flags */
|
unsigned long flags; /* per device flags */
|
||||||
|
unsigned short features; /* copy of devmap-features (read-only!) */
|
||||||
|
|
||||||
/* Device discipline stuff. */
|
/* Device discipline stuff. */
|
||||||
struct dasd_discipline *discipline;
|
struct dasd_discipline *discipline;
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||||
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
|
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
|
||||||
*
|
*
|
||||||
* $Revision: 1.45 $
|
* $Revision: 1.47 $
|
||||||
*
|
*
|
||||||
* i/o controls for the dasd driver.
|
* 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 dasd_device *device;
|
||||||
struct format_data_t fdata;
|
struct format_data_t fdata;
|
||||||
int feature_ro;
|
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
@@ -308,10 +307,7 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
|
|||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
|
if (device->features & DASD_FEATURE_READONLY)
|
||||||
if (feature_ro < 0)
|
|
||||||
return feature_ro;
|
|
||||||
if (feature_ro)
|
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
if (copy_from_user(&fdata, (void __user *) args,
|
if (copy_from_user(&fdata, (void __user *) args,
|
||||||
sizeof (struct format_data_t)))
|
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_device *device;
|
||||||
struct dasd_information2_t *dasd_info;
|
struct dasd_information2_t *dasd_info;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int rc, feature_ro;
|
int rc;
|
||||||
struct ccw_device *cdev;
|
struct ccw_device *cdev;
|
||||||
|
|
||||||
device = bdev->bd_disk->private_data;
|
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)
|
if (!device->discipline->fill_info)
|
||||||
return -EINVAL;
|
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);
|
dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
|
||||||
if (dasd_info == NULL)
|
if (dasd_info == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -427,7 +419,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
|
|||||||
(dasd_check_blocksize(device->bp_block)))
|
(dasd_check_blocksize(device->bp_block)))
|
||||||
dasd_info->format = DASD_FORMAT_NONE;
|
dasd_info->format = DASD_FORMAT_NONE;
|
||||||
|
|
||||||
dasd_info->features |= feature_ro;
|
dasd_info->features |=
|
||||||
|
((device->features & DASD_FEATURE_READONLY) != 0);
|
||||||
|
|
||||||
if (device->discipline)
|
if (device->discipline)
|
||||||
memcpy(dasd_info->type, device->discipline->name, 4);
|
memcpy(dasd_info->type, device->discipline->name, 4);
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* /proc interface for the dasd driver.
|
* /proc interface for the dasd driver.
|
||||||
*
|
*
|
||||||
* $Revision: 1.32 $
|
* $Revision: 1.33 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
@@ -55,7 +55,6 @@ dasd_devices_show(struct seq_file *m, void *v)
|
|||||||
{
|
{
|
||||||
struct dasd_device *device;
|
struct dasd_device *device;
|
||||||
char *substr;
|
char *substr;
|
||||||
int feature;
|
|
||||||
|
|
||||||
device = dasd_device_from_devindex((unsigned long) v - 1);
|
device = dasd_device_from_devindex((unsigned long) v - 1);
|
||||||
if (IS_ERR(device))
|
if (IS_ERR(device))
|
||||||
@@ -79,10 +78,7 @@ dasd_devices_show(struct seq_file *m, void *v)
|
|||||||
else
|
else
|
||||||
seq_printf(m, " is ????????");
|
seq_printf(m, " is ????????");
|
||||||
/* Print devices features. */
|
/* Print devices features. */
|
||||||
feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
|
substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
|
||||||
if (feature < 0)
|
|
||||||
return 0;
|
|
||||||
substr = feature ? "(ro)" : " ";
|
|
||||||
seq_printf(m, "%4s: ", substr);
|
seq_printf(m, "%4s: ", substr);
|
||||||
/* Print device status information. */
|
/* Print device status information. */
|
||||||
switch ((device != NULL) ? device->state : -1) {
|
switch ((device != NULL) ? device->state : -1) {
|
||||||
|
Reference in New Issue
Block a user