mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-12 07:37:31 -04:00
usb: f_qdss: Avoid wait_for_completion if qdss_disable is called
Commit 3741fb2cfb ("coresight: byte-cntr: Free USB requests when
disconnected") introduced a regression which leads qdss_disable &
qdss_close paths to race between them.
If qdss_disable path is processing, it would queue disconnect_work
which will notify the bypass notifier of USB_DISCONNECT and it will
call free_req. Within same time frame if qdss_close is called,
it will try to go ahead dequeue the request and wait_for_completion.
But since free_req got called, it will free the qreq instance which
wait_for_completion uses resulting in kernel panic.
Fix this by checking for ep_dequeue status if dequeue was success
then only wait_for_completion. Also taking the list operation under
qdss->lock in order to avoid any races between qdss_write as well.
Change-Id: I7bf9eab4296a509f5b459fa7768987c4a1f1287f
Signed-off-by: Udipto Goswami <ugoswami@codeaurora.org>
This commit is contained in:
parent
9ddceddf30
commit
25a232e420
1 changed files with 7 additions and 3 deletions
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* f_qdss.c -- QDSS function Driver
|
||||
*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
|
|
@ -899,16 +899,20 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
|
|||
qdss_log("channel:%s\n", ch->name);
|
||||
qdss = ch->priv_usb;
|
||||
qdss->qdss_close = true;
|
||||
spin_lock(&qdss->lock);
|
||||
while (!list_empty(&qdss->queued_data_pool)) {
|
||||
qreq = list_first_entry(&qdss->queued_data_pool,
|
||||
struct qdss_req, list);
|
||||
spin_unlock(&qdss->lock);
|
||||
spin_unlock_irqrestore(&channel_lock, flags);
|
||||
qdss_log("dequeue req:%pK\n", qreq->usb_req);
|
||||
usb_ep_dequeue(qdss->port.data, qreq->usb_req);
|
||||
wait_for_completion(&qreq->write_done);
|
||||
if (!usb_ep_dequeue(qdss->port.data, qreq->usb_req))
|
||||
wait_for_completion(&qreq->write_done);
|
||||
spin_lock_irqsave(&channel_lock, flags);
|
||||
spin_lock(&qdss->lock);
|
||||
}
|
||||
|
||||
spin_unlock(&qdss->lock);
|
||||
spin_unlock_irqrestore(&channel_lock, flags);
|
||||
usb_qdss_free_req(ch);
|
||||
spin_lock_irqsave(&channel_lock, flags);
|
||||
|
|
|
|||
Loading…
Reference in a new issue