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 <mrana@codeaurora.org>
This commit is contained in:
parent
28ddcdd099
commit
2c9b669728
1 changed files with 3 additions and 0 deletions
|
@ -2254,11 +2254,13 @@ void composite_suspend(struct usb_gadget *gadget)
|
||||||
{
|
{
|
||||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||||
struct usb_function *f;
|
struct usb_function *f;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* REVISIT: should we have config level
|
/* REVISIT: should we have config level
|
||||||
* suspend/resume callbacks?
|
* suspend/resume callbacks?
|
||||||
*/
|
*/
|
||||||
DBG(cdev, "suspend\n");
|
DBG(cdev, "suspend\n");
|
||||||
|
spin_lock_irqsave(&cdev->lock, flags);
|
||||||
if (cdev->config) {
|
if (cdev->config) {
|
||||||
list_for_each_entry(f, &cdev->config->functions, list) {
|
list_for_each_entry(f, &cdev->config->functions, list) {
|
||||||
if (f->suspend)
|
if (f->suspend)
|
||||||
|
@ -2269,6 +2271,7 @@ void composite_suspend(struct usb_gadget *gadget)
|
||||||
cdev->driver->suspend(cdev);
|
cdev->driver->suspend(cdev);
|
||||||
|
|
||||||
cdev->suspended = 1;
|
cdev->suspended = 1;
|
||||||
|
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||||
|
|
||||||
usb_gadget_vbus_draw(gadget, 2);
|
usb_gadget_vbus_draw(gadget, 2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue