summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorVijayavardhan Vennapusa <vvreddy@codeaurora.org>2017-05-04 17:25:01 +0530
committerVijayavardhan Vennapusa <vvreddy@codeaurora.org>2017-05-10 11:30:23 +0530
commitb100f8c33941acb2717fc6822463995935fdb403 (patch)
tree4ab2d4cad565b7b31955fb730b5daa790271839e /drivers/usb/gadget
parent406ab7d2d4f3a72f3ef1dd10f894e6c88ee3ac01 (diff)
USB: f_qdss: Fix crash issue during connect_work
If it happens that usb_qdss_close() gets called before completion of qdss_connect_work(), there is a chance that endless request being accessed in connect_work(), which will be freed in usb_qdss_close(). Fix that issue by having proper check for endless request under spinlock protection. Change-Id: Ied14137e01bf685547c093b907484b4dee583fda Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/function/f_qdss.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 88db253aeef4..777acb489875 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -474,6 +474,7 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
{
struct f_qdss *qdss;
int status;
+ unsigned long flags;
qdss = container_of(work, struct f_qdss, disconnect_w);
pr_debug("usb_qdss_disconnect_work\n");
@@ -496,6 +497,14 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
status = set_qdss_data_connection(qdss, 0);
if (status)
pr_err("qdss_disconnect error");
+
+ spin_lock_irqsave(&qdss->lock, flags);
+ if (qdss->endless_req) {
+ usb_ep_free_request(qdss->port.data,
+ qdss->endless_req);
+ qdss->endless_req = NULL;
+ }
+ spin_unlock_irqrestore(&qdss->lock, flags);
}
/*
@@ -528,6 +537,8 @@ static void usb_qdss_connect_work(struct work_struct *work)
{
struct f_qdss *qdss;
int status;
+ struct usb_request *req = NULL;
+ unsigned long flags;
qdss = container_of(work, struct f_qdss, connect_w);
@@ -548,8 +559,13 @@ static void usb_qdss_connect_work(struct work_struct *work)
if (qdss->ch.notify)
qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT,
NULL, &qdss->ch);
+ spin_lock_irqsave(&qdss->lock, flags);
+ req = qdss->endless_req;
+ spin_unlock_irqrestore(&qdss->lock, flags);
+ if (!req)
+ return;
- status = usb_ep_queue(qdss->port.data, qdss->endless_req, GFP_ATOMIC);
+ status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC);
if (status)
pr_err("%s: usb_ep_queue error (%d)\n", __func__, status);
}
@@ -849,9 +865,11 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
return;
}
- usb_ep_dequeue(qdss->port.data, qdss->endless_req);
- usb_ep_free_request(qdss->port.data, qdss->endless_req);
- qdss->endless_req = NULL;
+ if (qdss->endless_req) {
+ usb_ep_dequeue(qdss->port.data, qdss->endless_req);
+ usb_ep_free_request(qdss->port.data, qdss->endless_req);
+ qdss->endless_req = NULL;
+ }
gadget = qdss->gadget;
ch->app_conn = 0;
spin_unlock_irqrestore(&qdss_lock, flags);