[PATCH 4.4 105/132] s390/dasd: fix list corruption of lcu list
From: Greg Kroah-Hartman
Date: Mon Dec 28 2020 - 07:57:42 EST
From: Stefan Haberland <sth@xxxxxxxxxxxxx>
commit 53a7f655834c7c335bf683f248208d4fbe4b47bc upstream.
In dasd_alias_disconnect_device_from_lcu the device is removed from any
list on the LCU. Afterwards the LCU is removed from the lcu list if it
does not contain devices any longer.
The lcu->lock protects the lcu from parallel updates. But to cancel all
workers and wait for completion the lcu->lock has to be unlocked.
If two devices are removed in parallel and both are removed from the LCU
the first device that takes the lcu->lock again will delete the LCU because
it is already empty but the second device also tries to free the LCU which
leads to a list corruption of the lcu list.
Fix by removing the device right before the lcu is checked without
unlocking the lcu->lock in between.
Fixes: 8e09f21574ea ("[S390] dasd: add hyper PAV support to DASD device driver, part 1")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Stefan Haberland <sth@xxxxxxxxxxxxx>
Reviewed-by: Jan Hoeppner <hoeppner@xxxxxxxxxxxxx>
Signed-off-by: Jens Axboe <axboe@xxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/s390/block/dasd_alias.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -258,7 +258,6 @@ void dasd_alias_disconnect_device_from_l
return;
device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&lcu->lock, flags);
- list_del_init(&device->alias_list);
/* make sure that the workers don't use this device */
if (device == lcu->suc_data.device) {
spin_unlock_irqrestore(&lcu->lock, flags);
@@ -285,6 +284,7 @@ void dasd_alias_disconnect_device_from_l
spin_lock_irqsave(&aliastree.lock, flags);
spin_lock(&lcu->lock);
+ list_del_init(&device->alias_list);
if (list_empty(&lcu->grouplist) &&
list_empty(&lcu->active_devices) &&
list_empty(&lcu->inactive_devices)) {