From aa5c8df398266a141fb5ff0e77cbc7904a3e0648 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Mon, 4 Apr 2011 09:43:31 +0200 Subject: [S390] qdio: fix init sequence Reorder the initialization sequence of the qdio module to avoid writing to an uninitialized debug feature entry. Also reorder the exit function to restore a consistent cleanup path. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 479c665..c532ba9 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1649,26 +1649,26 @@ static int __init init_QDIO(void) { int rc; - rc = qdio_setup_init(); + rc = qdio_debug_init(); if (rc) return rc; + rc = qdio_setup_init(); + if (rc) + goto out_debug; rc = tiqdio_allocate_memory(); if (rc) goto out_cache; - rc = qdio_debug_init(); - if (rc) - goto out_ti; rc = tiqdio_register_thinints(); if (rc) - goto out_debug; + goto out_ti; return 0; -out_debug: - qdio_debug_exit(); out_ti: tiqdio_free_memory(); out_cache: qdio_setup_exit(); +out_debug: + qdio_debug_exit(); return rc; } @@ -1676,8 +1676,8 @@ static void __exit exit_QDIO(void) { tiqdio_unregister_thinints(); tiqdio_free_memory(); - qdio_debug_exit(); qdio_setup_exit(); + qdio_debug_exit(); } module_init(init_QDIO); -- cgit v1.1 From a2fc8485f838ccd2ce5db690f81ac086489a9e7e Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 4 Apr 2011 09:43:32 +0200 Subject: [S390] cio: prevent purging of CCW devices in the online state The cio_ignore purge function is intended to only remove CCW devices which are in the offline state. There is a time frame after the purge function finished where a CCW device is scheduled for removal but still accessible. When the device is set online during this time frame, it may first appear online before it is then removed. Fix this by preventing that CCW devices can be set online while there is work (such as removal triggered by the purge function) for it pending. Also ensure that the purge function does not schedule devices for removal which are in the process of being set online. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index df14c51..8e04c00 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -541,15 +541,24 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, int force, ret; unsigned long i; - if (!dev_fsm_final_state(cdev) && - cdev->private->state != DEV_STATE_DISCONNECTED) - return -EAGAIN; + /* Prevent conflict between multiple on-/offline processing requests. */ if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) return -EAGAIN; + /* Prevent conflict between internal I/Os and on-/offline processing. */ + if (!dev_fsm_final_state(cdev) && + cdev->private->state != DEV_STATE_DISCONNECTED) { + ret = -EAGAIN; + goto out_onoff; + } + /* Prevent conflict between pending work and on-/offline processing.*/ + if (work_pending(&cdev->private->todo_work)) { + ret = -EAGAIN; + goto out_onoff; + } if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) { - atomic_set(&cdev->private->onoff, 0); - return -EINVAL; + ret = -EINVAL; + goto out_onoff; } if (!strncmp(buf, "force\n", count)) { force = 1; @@ -574,6 +583,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, out: if (cdev->drv) module_put(cdev->drv->driver.owner); +out_onoff: atomic_set(&cdev->private->onoff, 0); return (ret < 0) ? ret : count; } @@ -1311,10 +1321,12 @@ static int purge_fn(struct device *dev, void *data) spin_lock_irq(cdev->ccwlock); if (is_blacklisted(id->ssid, id->devno) && - (cdev->private->state == DEV_STATE_OFFLINE)) { + (cdev->private->state == DEV_STATE_OFFLINE) && + (atomic_cmpxchg(&cdev->private->onoff, 0, 1) == 0)) { CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid, id->devno); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); + atomic_set(&cdev->private->onoff, 0); } spin_unlock_irq(cdev->ccwlock); /* Abort loop in case of pending signal. */ -- cgit v1.1