From 2c9b669728b17a1bd9ac8cf2d7e78501da9a8b10 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Mon, 5 Oct 2015 19:08:47 -0700 Subject: [PATCH] usb: gadget: composite: Protect cdev in composite_suspend() With USB cable disconnect case, there is race happening when composite_suspend() is being pre-empted just after getting reference to cdev structure (suspend flow) and cdev->config set to NULL as part of reset_config() (disconnect flow). This results into composite_suspend() using bad value with cdev->config which is resulting in some cases multiple time calling f->suspend(). Fix this issue by protecting cdev in composite_suspend() API. CRs-Fixed: 916718 Change-Id: Id0b2a254f64621fcbc19c0556265e9b7b32f1382 Signed-off-by: Mayank Rana --- drivers/usb/gadget/composite.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 474b6ac1b5fb..b8c8e1daca7d 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2254,11 +2254,13 @@ void composite_suspend(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; + unsigned long flags; /* REVISIT: should we have config level * suspend/resume callbacks? */ DBG(cdev, "suspend\n"); + spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) { list_for_each_entry(f, &cdev->config->functions, list) { if (f->suspend) @@ -2269,6 +2271,7 @@ void composite_suspend(struct usb_gadget *gadget) cdev->driver->suspend(cdev); cdev->suspended = 1; + spin_unlock_irqrestore(&cdev->lock, flags); usb_gadget_vbus_draw(gadget, 2); }