Skip to content

Commit

Permalink
[S390] cio: prevent purging of CCW devices in the online state
Browse files Browse the repository at this point in the history
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 <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Peter Oberparleiter authored and Martin Schwidefsky committed Apr 4, 2011
1 parent aa5c8df commit a2fc848
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions drivers/s390/cio/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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. */
Expand Down

0 comments on commit a2fc848

Please sign in to comment.