s390/cio: fix race condition during online processing
[ Upstream commit 2d8527f2f911fab84aec04df4788c0c23af3df48 ] 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: commit2297791c92
("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:2297791c92
("s390/cio: dont unregister subchannel from child-drivers") Reviewed-by: Alexandra Winter <wintera@linux.ibm.com> Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Родитель
498f7b8037
Коммит
3076b3c38a
|
@ -360,10 +360,8 @@ int ccw_device_set_online(struct ccw_device *cdev)
|
|||
|
||||
spin_lock_irq(cdev->ccwlock);
|
||||
ret = ccw_device_online(cdev);
|
||||
if (ret) {
|
||||
spin_unlock_irq(cdev->ccwlock);
|
||||
if (ret == 0)
|
||||
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
|
||||
else {
|
||||
CIO_MSG_EVENT(0, "ccw_device_online returned %d, "
|
||||
"device 0.%x.%04x\n",
|
||||
ret, cdev->private->dev_id.ssid,
|
||||
|
@ -372,7 +370,12 @@ int ccw_device_set_online(struct ccw_device *cdev)
|
|||
put_device(&cdev->dev);
|
||||
return ret;
|
||||
}
|
||||
/* Wait until a final state is reached */
|
||||
while (!dev_fsm_final_state(cdev)) {
|
||||
spin_unlock_irq(cdev->ccwlock);
|
||||
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
|
||||
spin_lock_irq(cdev->ccwlock);
|
||||
}
|
||||
/* Check if online processing was successful */
|
||||
if ((cdev->private->state != DEV_STATE_ONLINE) &&
|
||||
(cdev->private->state != DEV_STATE_W4SENSE)) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче