Skip to content

Commit 2d8527f

Browse files
oberparAlexander Gordeev
authored andcommitted
s390/cio: fix race condition during online processing
A race condition exists in ccw_device_set_online() that can cause the online process to fail, leaving the affected device in an inconsistent state. As a result, subsequent attempts to set that device online fail with return code ENODEV. The problem occurs when a path verification request arrives after a wait for final device state completed, but before the result state is evaluated. Fix this by ensuring that the CCW-device lock is held between determining final state and checking result state. Note that since: commit 2297791 ("s390/cio: dont unregister subchannel from child-drivers") path verification requests are much more likely to occur during boot, resulting in an increased chance of this race condition occurring. Fixes: 2297791 ("s390/cio: dont unregister subchannel from child-drivers") Reviewed-by: Alexandra Winter <[email protected]> Reviewed-by: Vineeth Vijayan <[email protected]> Signed-off-by: Peter Oberparleiter <[email protected]> Signed-off-by: Alexander Gordeev <[email protected]>
1 parent 607638f commit 2d8527f

File tree

1 file changed

+8
-5
lines changed

1 file changed

+8
-5
lines changed

drivers/s390/cio/device.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,8 @@ int ccw_device_set_online(struct ccw_device *cdev)
363363

364364
spin_lock_irq(cdev->ccwlock);
365365
ret = ccw_device_online(cdev);
366-
spin_unlock_irq(cdev->ccwlock);
367-
if (ret == 0)
368-
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
369-
else {
366+
if (ret) {
367+
spin_unlock_irq(cdev->ccwlock);
370368
CIO_MSG_EVENT(0, "ccw_device_online returned %d, "
371369
"device 0.%x.%04x\n",
372370
ret, cdev->private->dev_id.ssid,
@@ -375,7 +373,12 @@ int ccw_device_set_online(struct ccw_device *cdev)
375373
put_device(&cdev->dev);
376374
return ret;
377375
}
378-
spin_lock_irq(cdev->ccwlock);
376+
/* Wait until a final state is reached */
377+
while (!dev_fsm_final_state(cdev)) {
378+
spin_unlock_irq(cdev->ccwlock);
379+
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
380+
spin_lock_irq(cdev->ccwlock);
381+
}
379382
/* Check if online processing was successful */
380383
if ((cdev->private->state != DEV_STATE_ONLINE) &&
381384
(cdev->private->state != DEV_STATE_W4SENSE)) {

0 commit comments

Comments
 (0)