Commit 53a7f655 authored by Stefan Haberland's avatar Stefan Haberland Committed by Jens Axboe

s390/dasd: fix list corruption of lcu list

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: 8e09f215 ("[S390] dasd: add hyper PAV support to DASD device driver, part 1")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarStefan Haberland <sth@linux.ibm.com>
Reviewed-by: default avatarJan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 0ede91f8
...@@ -256,7 +256,6 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) ...@@ -256,7 +256,6 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
return; return;
device->discipline->get_uid(device, &uid); device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&lcu->lock, flags); spin_lock_irqsave(&lcu->lock, flags);
list_del_init(&device->alias_list);
/* make sure that the workers don't use this device */ /* make sure that the workers don't use this device */
if (device == lcu->suc_data.device) { if (device == lcu->suc_data.device) {
spin_unlock_irqrestore(&lcu->lock, flags); spin_unlock_irqrestore(&lcu->lock, flags);
...@@ -283,6 +282,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) ...@@ -283,6 +282,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
spin_lock_irqsave(&aliastree.lock, flags); spin_lock_irqsave(&aliastree.lock, flags);
spin_lock(&lcu->lock); spin_lock(&lcu->lock);
list_del_init(&device->alias_list);
if (list_empty(&lcu->grouplist) && if (list_empty(&lcu->grouplist) &&
list_empty(&lcu->active_devices) && list_empty(&lcu->active_devices) &&
list_empty(&lcu->inactive_devices)) { list_empty(&lcu->inactive_devices)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment