usb: gadget: function: printer: avoid spinlock recursion
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Wed, 13 Sep 2017 06:31:33 +0000 (15:31 +0900)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Wed, 20 Sep 2017 11:57:28 +0000 (14:57 +0300)
If usb_gadget_giveback_request() is called in usb_ep_queue(),
this printer_write() is possible to cause spinlock recursion. So,
this patch adds spin_unlock() before calls usb_ep_queue() to avoid it.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/gadget/function/f_printer.c

index 8df244fc9d80daa4c7caf0da729bae2ac66137a2..ea0da35a44e2e9f3f2c0e11921568da68b70fafd 100644 (file)
@@ -555,6 +555,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        size_t                  size;   /* Amount of data in a TX request. */
        size_t                  bytes_copied = 0;
        struct usb_request      *req;
+       int                     value;
 
        DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
 
@@ -634,7 +635,11 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                        return -EAGAIN;
                }
 
-               if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
+               /* here, we unlock, and only unlock, to avoid deadlock. */
+               spin_unlock(&dev->lock);
+               value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
+               spin_lock(&dev->lock);
+               if (value) {
                        list_add(&req->list, &dev->tx_reqs);
                        spin_unlock_irqrestore(&dev->lock, flags);
                        mutex_unlock(&dev->lock_printer_io);