lkml.org 
[lkml]   [2020]   [Nov]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.9 105/255] scsi: scsi_dh_alua: Avoid crash during alua_bus_detach()
    Date
    From: Hannes Reinecke <hare@suse.de>

    [ Upstream commit 5faf50e9e9fdc2117c61ff7e20da49cd6a29e0ca ]

    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>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/scsi/device_handler/scsi_dh_alua.c | 9 +++++----
    1 file changed, 5 insertions(+), 4 deletions(-)

    diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
    index f32da0ca529e0..308bda2e9c000 100644
    --- a/drivers/scsi/device_handler/scsi_dh_alua.c
    +++ b/drivers/scsi/device_handler/scsi_dh_alua.c
    @@ -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);
    }

    --
    2.27.0


    \
     
     \ /
      Last update: 2020-11-17 15:10    [W:4.063 / U:0.112 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site