summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Haberland <sth@linux.ibm.com>2020-12-17 16:59:07 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-12-29 13:45:03 +0100
commit61b66e8171b53e92d19447760bfc7b5f20f49bd4 (patch)
tree3731d0a02a5daf5271efa69c34d6b931e74d3fb7
parentc72f447c921438fa70a1bdb5a6e7da36813cb6cf (diff)
downloadlinux-stable-61b66e8171b53e92d19447760bfc7b5f20f49bd4.tar.gz
linux-stable-61b66e8171b53e92d19447760bfc7b5f20f49bd4.tar.bz2
linux-stable-61b66e8171b53e92d19447760bfc7b5f20f49bd4.zip
s390/dasd: fix list corruption of lcu list
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@vger.kernel.org Signed-off-by: Stefan Haberland <sth@linux.ibm.com> Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com> Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/s390/block/dasd_alias.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 7490dd34002a..0569c15fddfe 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -255,7 +255,6 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
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);
@@ -282,6 +281,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
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)) {