lkml.org 
[lkml]   [2019]   [May]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 144/276] USB: core: Dont unbind interfaces following device reset failure
    Date
    [ Upstream commit 381419fa720060ba48b7bbc483be787d5b1dca6f ]

    The SCSI core does not like to have devices or hosts unregistered
    while error recovery is in progress. Trying to do so can lead to
    self-deadlock: Part of the removal code tries to obtain a lock already
    held by the error handler.

    This can cause problems for the usb-storage and uas drivers, because
    their error handler routines perform a USB reset, and if the reset
    fails then the USB core automatically goes on to unbind all drivers
    from the device's interfaces -- all while still in the context of the
    SCSI error handler.

    As it turns out, practically all the scenarios leading to a USB reset
    failure end up causing a device disconnect (the main error pathway in
    usb_reset_and_verify_device(), at the end of the routine, calls
    hub_port_logical_disconnect() before returning). As a result, the
    hub_wq thread will soon become aware of the problem and will unbind
    all the device's drivers in its own context, not in the
    error-handler's context.

    This means that usb_reset_device() does not need to call
    usb_unbind_and_rebind_marked_interfaces() in cases where
    usb_reset_and_verify_device() has returned an error, because hub_wq
    will take care of everything anyway.

    This particular problem was observed in somewhat artificial
    circumstances, by using usbfs to tell a hub to power-down a port
    connected to a USB-3 mass storage device using the UAS protocol. With
    the port turned off, the currently executing command timed out and the
    error handler started running. The USB reset naturally failed,
    because the hub port was off, and the error handler deadlocked as
    described above. Not carrying out the call to
    usb_unbind_and_rebind_marked_interfaces() fixes this issue.

    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Reported-by: Kento Kobayashi <Kento.A.Kobayashi@sony.com>
    Tested-by: Kento Kobayashi <Kento.A.Kobayashi@sony.com>
    CC: Bart Van Assche <bvanassche@acm.org>
    CC: Martin K. Petersen <martin.petersen@oracle.com>
    CC: Jacky Cao <Jacky.Cao@sony.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/usb/core/hub.c | 5 ++++-
    1 file changed, 4 insertions(+), 1 deletion(-)

    diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
    index bbcfa63d0233b..eb24ec0e160d4 100644
    --- a/drivers/usb/core/hub.c
    +++ b/drivers/usb/core/hub.c
    @@ -5823,7 +5823,10 @@ int usb_reset_device(struct usb_device *udev)
    cintf->needs_binding = 1;
    }
    }
    - usb_unbind_and_rebind_marked_interfaces(udev);
    +
    + /* If the reset failed, hub_wq will unbind drivers later */
    + if (ret == 0)
    + usb_unbind_and_rebind_marked_interfaces(udev);
    }

    usb_autosuspend_device(udev);
    --
    2.20.1


    \
     
     \ /
      Last update: 2019-05-30 06:09    [W:4.403 / U:0.032 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site