Commit db7ba071 authored by Stefan Haberland's avatar Stefan Haberland Committed by Jens Axboe

s390/dasd: fix Oops in dasd_alias_get_start_dev due to missing pavgroup

Fix Oops in dasd_alias_get_start_dev() function caused by the pavgroup
pointer being NULL.

The pavgroup pointer is checked on the entrance of the function but
without the lcu->lock being held. Therefore there is a race window
between dasd_alias_get_start_dev() and _lcu_update() which sets
pavgroup to NULL with the lcu->lock held.

Fix by checking the pavgroup pointer with lcu->lock held.

Cc: <stable@vger.kernel.org> # 2.6.25+
Fixes: 8e09f215 ("[S390] dasd: add hyper PAV support to DASD device driver, part 1")
Signed-off-by: default avatarStefan Haberland <sth@linux.ibm.com>
Reviewed-by: default avatarJan Hoeppner <hoeppner@linux.ibm.com>
Link: https://lore.kernel.org/r/20220919154931.4123002-2-sth@linux.ibm.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent c4fa3684
...@@ -675,12 +675,12 @@ int dasd_alias_remove_device(struct dasd_device *device) ...@@ -675,12 +675,12 @@ int dasd_alias_remove_device(struct dasd_device *device)
struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device) struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
{ {
struct dasd_eckd_private *alias_priv, *private = base_device->private; struct dasd_eckd_private *alias_priv, *private = base_device->private;
struct alias_pav_group *group = private->pavgroup;
struct alias_lcu *lcu = private->lcu; struct alias_lcu *lcu = private->lcu;
struct dasd_device *alias_device; struct dasd_device *alias_device;
struct alias_pav_group *group;
unsigned long flags; unsigned long flags;
if (!group || !lcu) if (!lcu)
return NULL; return NULL;
if (lcu->pav == NO_PAV || if (lcu->pav == NO_PAV ||
lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING)) lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))
...@@ -697,6 +697,11 @@ struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device) ...@@ -697,6 +697,11 @@ struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
} }
spin_lock_irqsave(&lcu->lock, flags); spin_lock_irqsave(&lcu->lock, flags);
group = private->pavgroup;
if (!group) {
spin_unlock_irqrestore(&lcu->lock, flags);
return NULL;
}
alias_device = group->next; alias_device = group->next;
if (!alias_device) { if (!alias_device) {
if (list_empty(&group->aliaslist)) { if (list_empty(&group->aliaslist)) {
......
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