]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
usb: dwc2: gadget: Fix kill_all_requests race
authorJohn Keeping <john@metanate.com>
Mon, 5 Aug 2019 16:01:21 +0000 (17:01 +0100)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Fri, 9 Aug 2019 05:28:29 +0000 (08:28 +0300)
When a gadget is disabled, kill_all_requests() can be called
simultaneously from both a user process via dwc2_hsotg_pullup() and from
the interrupt handler if the hardware detects disconnection.

Since we drop the lock in dwc2_hsotg_complete_request() in order to call
the completion handler, this means that the list is modified
concurrently and leads to an infinite loop in kill_all_requests().

Replace the foreach loop with a while-not-empty loop in order to remove
the danger of this concurrent modification.

Note: I observed this with threadirqs, I'm not sure if it can be
triggered without threaded interrupts.

Signed-off-by: John Keeping <john@metanate.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/dwc2/gadget.c

index bff48a8a19848695c73af2ab63dfd5a574f12924..6be10e496e10579198fcd683bdb66de34f058850 100644 (file)
@@ -3224,14 +3224,15 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
                              struct dwc2_hsotg_ep *ep,
                              int result)
 {
-       struct dwc2_hsotg_req *req, *treq;
        unsigned int size;
 
        ep->req = NULL;
 
-       list_for_each_entry_safe(req, treq, &ep->queue, queue)
-               dwc2_hsotg_complete_request(hsotg, ep, req,
-                                           result);
+       while (!list_empty(&ep->queue)) {
+               struct dwc2_hsotg_req *req = get_ep_head(ep);
+
+               dwc2_hsotg_complete_request(hsotg, ep, req, result);
+       }
 
        if (!hsotg->dedicated_fifos)
                return;