aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r--drivers/s390/cio/device.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index df14c51f6532..8e04c00cf0ad 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,
541 int force, ret; 541 int force, ret;
542 unsigned long i; 542 unsigned long i;
543 543
544 if (!dev_fsm_final_state(cdev) && 544 /* Prevent conflict between multiple on-/offline processing requests. */
545 cdev->private->state != DEV_STATE_DISCONNECTED)
546 return -EAGAIN;
547 if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) 545 if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
548 return -EAGAIN; 546 return -EAGAIN;
547 /* Prevent conflict between internal I/Os and on-/offline processing. */
548 if (!dev_fsm_final_state(cdev) &&
549 cdev->private->state != DEV_STATE_DISCONNECTED) {
550 ret = -EAGAIN;
551 goto out_onoff;
552 }
553 /* Prevent conflict between pending work and on-/offline processing.*/
554 if (work_pending(&cdev->private->todo_work)) {
555 ret = -EAGAIN;
556 goto out_onoff;
557 }
549 558
550 if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) { 559 if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) {
551 atomic_set(&cdev->private->onoff, 0); 560 ret = -EINVAL;
552 return -EINVAL; 561 goto out_onoff;
553 } 562 }
554 if (!strncmp(buf, "force\n", count)) { 563 if (!strncmp(buf, "force\n", count)) {
555 force = 1; 564 force = 1;
@@ -574,6 +583,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
574out: 583out:
575 if (cdev->drv) 584 if (cdev->drv)
576 module_put(cdev->drv->driver.owner); 585 module_put(cdev->drv->driver.owner);
586out_onoff:
577 atomic_set(&cdev->private->onoff, 0); 587 atomic_set(&cdev->private->onoff, 0);
578 return (ret < 0) ? ret : count; 588 return (ret < 0) ? ret : count;
579} 589}
@@ -1311,10 +1321,12 @@ static int purge_fn(struct device *dev, void *data)
1311 1321
1312 spin_lock_irq(cdev->ccwlock); 1322 spin_lock_irq(cdev->ccwlock);
1313 if (is_blacklisted(id->ssid, id->devno) && 1323 if (is_blacklisted(id->ssid, id->devno) &&
1314 (cdev->private->state == DEV_STATE_OFFLINE)) { 1324 (cdev->private->state == DEV_STATE_OFFLINE) &&
1325 (atomic_cmpxchg(&cdev->private->onoff, 0, 1) == 0)) {
1315 CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid, 1326 CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid,
1316 id->devno); 1327 id->devno);
1317 ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); 1328 ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
1329 atomic_set(&cdev->private->onoff, 0);
1318 } 1330 }
1319 spin_unlock_irq(cdev->ccwlock); 1331 spin_unlock_irq(cdev->ccwlock);
1320 /* Abort loop in case of pending signal. */ 1332 /* Abort loop in case of pending signal. */