| From a5a1b9514154437aa1ed35c291191f82fd3e941a Mon Sep 17 00:00:00 2001 |
| From: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Date: Tue, 3 Jan 2017 18:28:48 +0200 |
| Subject: xhci: Handle command completion and timeout race |
| |
| From: Mathias Nyman <mathias.nyman@linux.intel.com> |
| |
| commit a5a1b9514154437aa1ed35c291191f82fd3e941a upstream. |
| |
| If we get a command completion event at the same time as the command |
| timeout work starts on another cpu we might end up aborting the wrong |
| command. |
| |
| If the command completion takes the xhci lock before the timeout work, it |
| will handle the command, pick the next command, mark it as current_cmd, and |
| re-queue the timeout work. When the timeout work finally gets the lock |
| It will start aborting the wrong command. |
| |
| This case can be resolved by checking if the timeout work is pending inside |
| the timeout function itself. A new timeout work can only be pending if the |
| command completed and a new command was queued. |
| |
| If there are no more commands pending then command completion will set |
| the current_cmd to NULL, which is already handled in the timeout work. |
| |
| Reported-by: Baolin Wang <baolin.wang@linaro.org> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/host/xhci-ring.c | 6 +++++- |
| 1 file changed, 5 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/usb/host/xhci-ring.c |
| +++ b/drivers/usb/host/xhci-ring.c |
| @@ -1270,7 +1270,11 @@ void xhci_handle_command_timeout(unsigne |
| |
| spin_lock_irqsave(&xhci->lock, flags); |
| |
| - if (!xhci->current_cmd) { |
| + /* |
| + * If timeout work is pending, or current_cmd is NULL, it means we |
| + * raced with command completion. Command is handled so just return. |
| + */ |
| + if (!xhci->current_cmd || timer_pending(&xhci->cmd_timer)) { |
| spin_unlock_irqrestore(&xhci->lock, flags); |
| return; |
| } |