• Hans de Goede's avatar
    uas: pre_reset and suspend: Fix a few races · f9dc024a
    Hans de Goede authored
    The purpose of uas_pre_reset is to:
    
    1) Stop any new commands from being submitted while an externally triggered
       usb-device-reset is running
    2) Wait for any pending commands to finish before allowing the usb-device-reset
       to continue
    
    The purpose of uas_suspend is to:
    2) Wait for any pending commands to finish before suspending
    
    This commit fixes races in both paths:
    
    1) For 1) we use scsi_block_requests, but the scsi midlayer calls queuecommand
       without holding any locks, so a queuecommand may already past the midlayer
       scsi_block_requests checks when we call it, add a check to uas_queuecommand
       to fix this
    
    2) For 2) we were waiting for all sense-urbs to complete, there are 2 problems
       with this approach:
    a) data-urbs may complete after the sense urb, so we need to check for those
       too
    b) if a sense-urb completes with a iu id of READ/WRITE_READY a command is not
       yet done. We submit a new sense-urb immediately in this case, but that
       submit may fail (in which case it will get retried by uas_do_work), if this
       happens the sense_urbs anchor may become empty while the cmnd is not yet
       done
    
    Also unblock requests on timeout, to avoid things getting stuck in that case.
    Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    f9dc024a
uas.c 31.9 KB