diff options
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r-- | drivers/s390/block/dasd.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 5905936c7c6..9ab1ae40565 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; } @@ -321,8 +323,8 @@ static int dasd_state_ready_to_basic(struct dasd_device *device) device->state = DASD_STATE_READY; return rc; } - dasd_destroy_partitions(block); dasd_flush_request_queue(block); + dasd_destroy_partitions(block); block->blocks = 0; block->bp_block = 0; block->s2b_shift = 0; @@ -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); } /* @@ -1000,12 +1003,20 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, return; } - device = (struct dasd_device *) cqr->startdev; - if (device == NULL || - device != dasd_device_from_cdev_locked(cdev) || - strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { + device = dasd_device_from_cdev_locked(cdev); + if (IS_ERR(device)) { + DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s", + "unable to get device from cdev"); + return; + } + + if (!cqr->startdev || + device != cqr->startdev || + strncmp(cqr->startdev->discipline->ebcname, + (char *) &cqr->magic, 4)) { DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s", "invalid device in request"); + dasd_put_device(device); return; } @@ -1692,7 +1703,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 +2180,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; @@ -2285,11 +2299,6 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie) if (ret) pr_warning("%s: Setting the DASD online failed with rc=%d\n", dev_name(&cdev->dev), ret); - else { - struct dasd_device *device = dasd_device_from_cdev(cdev); - wait_event(dasd_init_waitq, _wait_for_device(device)); - dasd_put_device(device); - } } /* @@ -2424,6 +2433,9 @@ int dasd_generic_set_online(struct ccw_device *cdev, } else pr_debug("dasd_generic device %s found\n", dev_name(&cdev->dev)); + + wait_event(dasd_init_waitq, _wait_for_device(device)); + dasd_put_device(device); return rc; } |