mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 08:50:52 +07:00
scsi: scsi_dh_alua: Avoid crash during alua_bus_detach()
alua_bus_detach() might be running concurrently with alua_rtpg_work(), so we might trip over h->sdev == NULL and call BUG_ON(). The correct way of handling it is to not set h->sdev to NULL in alua_bus_detach(), and call rcu_synchronize() before the final delete to ensure that all concurrent threads have left the critical section. Then we can get rid of the BUG_ON() and replace it with a simple if condition. Link: https://lore.kernel.org/r/1600167537-12509-1-git-send-email-jitendra.khasdev@oracle.com Link: https://lore.kernel.org/r/20200924104559.26753-1-hare@suse.de Cc: Brian Bunker <brian@purestorage.com> Acked-by: Brian Bunker <brian@purestorage.com> Tested-by: Jitendra Khasdev <jitendra.khasdev@oracle.com> Reviewed-by: Jitendra Khasdev <jitendra.khasdev@oracle.com> Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
af61bc1e33
commit
5faf50e9e9
@ -658,8 +658,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(h,
|
||||
&tmp_pg->dh_list, node) {
|
||||
/* h->sdev should always be valid */
|
||||
BUG_ON(!h->sdev);
|
||||
if (!h->sdev)
|
||||
continue;
|
||||
h->sdev->access_state = desc[0];
|
||||
}
|
||||
rcu_read_unlock();
|
||||
@ -705,7 +705,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
|
||||
pg->expiry = 0;
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(h, &pg->dh_list, node) {
|
||||
BUG_ON(!h->sdev);
|
||||
if (!h->sdev)
|
||||
continue;
|
||||
h->sdev->access_state =
|
||||
(pg->state & SCSI_ACCESS_STATE_MASK);
|
||||
if (pg->pref)
|
||||
@ -1147,7 +1148,6 @@ static void alua_bus_detach(struct scsi_device *sdev)
|
||||
spin_lock(&h->pg_lock);
|
||||
pg = rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock));
|
||||
rcu_assign_pointer(h->pg, NULL);
|
||||
h->sdev = NULL;
|
||||
spin_unlock(&h->pg_lock);
|
||||
if (pg) {
|
||||
spin_lock_irq(&pg->lock);
|
||||
@ -1156,6 +1156,7 @@ static void alua_bus_detach(struct scsi_device *sdev)
|
||||
kref_put(&pg->kref, release_port_group);
|
||||
}
|
||||
sdev->handler_data = NULL;
|
||||
synchronize_rcu();
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user