diff options
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r-- | drivers/s390/block/dasd.c | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 5905936c7c6..56df3c5ed38 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -20,6 +20,7 @@ #include <linux/buffer_head.h> #include <linux/hdreg.h> #include <linux/async.h> +#include <linux/mutex.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -112,6 +113,7 @@ struct dasd_device *dasd_alloc_device(void) INIT_WORK(&device->restore_device, do_restore_device); device->state = DASD_STATE_NEW; device->target = DASD_STATE_NEW; + mutex_init(&device->state_mutex); return device; } @@ -484,10 +486,8 @@ static void dasd_change_state(struct dasd_device *device) if (rc) device->target = device->state; - if (device->state == device->target) { + if (device->state == device->target) wake_up(&dasd_init_waitq); - dasd_put_device(device); - } /* let user-space know that the device status changed */ kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); @@ -502,7 +502,9 @@ static void dasd_change_state(struct dasd_device *device) static void do_kick_device(struct work_struct *work) { struct dasd_device *device = container_of(work, struct dasd_device, kick_work); + mutex_lock(&device->state_mutex); dasd_change_state(device); + mutex_unlock(&device->state_mutex); dasd_schedule_device_bh(device); dasd_put_device(device); } @@ -539,18 +541,19 @@ void dasd_restore_device(struct dasd_device *device) void dasd_set_target_state(struct dasd_device *device, int target) { dasd_get_device(device); + mutex_lock(&device->state_mutex); /* If we are in probeonly mode stop at DASD_STATE_READY. */ if (dasd_probeonly && target > DASD_STATE_READY) target = DASD_STATE_READY; if (device->target != target) { - if (device->state == target) { + if (device->state == target) wake_up(&dasd_init_waitq); - dasd_put_device(device); - } device->target = target; } if (device->state != device->target) dasd_change_state(device); + mutex_unlock(&device->state_mutex); + dasd_put_device(device); } /* @@ -1692,7 +1695,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) cqr, rc); } else { cqr->stopclk = get_clock(); - rc = 1; } break; default: /* already finished or clear pending - do nothing */ @@ -2170,9 +2172,13 @@ static void dasd_flush_request_queue(struct dasd_block *block) static int dasd_open(struct block_device *bdev, fmode_t mode) { struct dasd_block *block = bdev->bd_disk->private_data; - struct dasd_device *base = block->base; + struct dasd_device *base; int rc; + if (!block) + return -ENODEV; + + base = block->base; atomic_inc(&block->open_count); if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { rc = -ENODEV; |