| From 5a345c20c17d87099224a4be12e69e5bd7023dca Mon Sep 17 00:00:00 2001 |
| From: Johan Hovold <jhovold@gmail.com> |
| Date: Mon, 26 May 2014 19:23:36 +0200 |
| Subject: USB: cdc-acm: fix write and suspend race |
| |
| From: Johan Hovold <jhovold@gmail.com> |
| |
| commit 5a345c20c17d87099224a4be12e69e5bd7023dca upstream. |
| |
| Fix race between write() and suspend() which could lead to writes being |
| dropped (or I/O while suspended) if the device is runtime suspended |
| while a write request is being processed. |
| |
| Specifically, suspend() releases the write_lock after determining the |
| device is idle but before incrementing the susp_count, thus leaving a |
| window where a concurrent write() can submit an urb. |
| |
| Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices |
| that support remote wakeup") |
| |
| Signed-off-by: Johan Hovold <jhovold@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/class/cdc-acm.c | 15 ++++++--------- |
| 1 file changed, 6 insertions(+), 9 deletions(-) |
| |
| --- a/drivers/usb/class/cdc-acm.c |
| +++ b/drivers/usb/class/cdc-acm.c |
| @@ -1441,18 +1441,15 @@ static int acm_suspend(struct usb_interf |
| struct acm *acm = usb_get_intfdata(intf); |
| int cnt; |
| |
| + spin_lock_irq(&acm->read_lock); |
| + spin_lock(&acm->write_lock); |
| if (PMSG_IS_AUTO(message)) { |
| - int b; |
| - |
| - spin_lock_irq(&acm->write_lock); |
| - b = acm->transmitting; |
| - spin_unlock_irq(&acm->write_lock); |
| - if (b) |
| + if (acm->transmitting) { |
| + spin_unlock(&acm->write_lock); |
| + spin_unlock_irq(&acm->read_lock); |
| return -EBUSY; |
| + } |
| } |
| - |
| - spin_lock_irq(&acm->read_lock); |
| - spin_lock(&acm->write_lock); |
| cnt = acm->susp_count++; |
| spin_unlock(&acm->write_lock); |
| spin_unlock_irq(&acm->read_lock); |