From 1bcc855e56fa963692db697ad038e5b1989af6a3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 27 Jun 2014 15:02:11 -0700 Subject: [PATCH] 3.4-stable patches added patches: usb-usb_wwan-fix-urb-leak-at-shutdown.patch usb-usb_wwan-fix-write-and-suspend-race.patch --- queue-3.4/series | 2 + ...an-fix-race-between-write-and-resume.patch | 12 ++- ...sb-usb_wwan-fix-urb-leak-at-shutdown.patch | 93 +++++++++++++++++++ ...-usb_wwan-fix-write-and-suspend-race.patch | 57 ++++++++++++ 4 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 queue-3.4/usb-usb_wwan-fix-urb-leak-at-shutdown.patch create mode 100644 queue-3.4/usb-usb_wwan-fix-write-and-suspend-race.patch diff --git a/queue-3.4/series b/queue-3.4/series index 08d28efe087..08b2f0ee6ef 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -17,3 +17,5 @@ ext4-fix-wrong-assert-in-ext4_mb_normalize_request.patch matroxfb-perform-a-dummy-read-of-m_status.patch usb-usb_wwan-fix-urb-leak-in-write-error-path.patch usb-usb_wwan-fix-race-between-write-and-resume.patch +usb-usb_wwan-fix-write-and-suspend-race.patch +usb-usb_wwan-fix-urb-leak-at-shutdown.patch diff --git a/queue-3.4/usb-usb_wwan-fix-race-between-write-and-resume.patch b/queue-3.4/usb-usb_wwan-fix-race-between-write-and-resume.patch index 467ef7dfd3a..fe444e37c68 100644 --- a/queue-3.4/usb-usb_wwan-fix-race-between-write-and-resume.patch +++ b/queue-3.4/usb-usb_wwan-fix-race-between-write-and-resume.patch @@ -27,11 +27,13 @@ Reviewed-by: David Cohen Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman -diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c -index 47ad7550c5a6..112693a4100b 100644 +--- + drivers/usb/serial/usb_wwan.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c -@@ -660,17 +660,15 @@ int usb_wwan_resume(struct usb_serial *serial) +@@ -731,17 +731,15 @@ int usb_wwan_resume(struct usb_serial *s } } @@ -43,7 +45,7 @@ index 47ad7550c5a6..112693a4100b 100644 /* skip closed ports */ - spin_lock_irq(&intfdata->susp_lock); -- if (!portdata || !portdata->opened) { +- if (!portdata->opened) { - spin_unlock_irq(&intfdata->susp_lock); + if (!portdata || !portdata->opened) continue; @@ -51,7 +53,7 @@ index 47ad7550c5a6..112693a4100b 100644 for (j = 0; j < N_IN_URB; j++) { urb = portdata->in_urbs[j]; -@@ -683,9 +681,7 @@ int usb_wwan_resume(struct usb_serial *serial) +@@ -754,9 +752,7 @@ int usb_wwan_resume(struct usb_serial *s } } play_delayed(port); diff --git a/queue-3.4/usb-usb_wwan-fix-urb-leak-at-shutdown.patch b/queue-3.4/usb-usb_wwan-fix-urb-leak-at-shutdown.patch new file mode 100644 index 00000000000..3014a05b9e2 --- /dev/null +++ b/queue-3.4/usb-usb_wwan-fix-urb-leak-at-shutdown.patch @@ -0,0 +1,93 @@ +From 79eed03e77d481b55d85d1cfe5a1636a0d3897fd Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 26 May 2014 19:23:16 +0200 +Subject: USB: usb_wwan: fix urb leak at shutdown + +From: Johan Hovold + +commit 79eed03e77d481b55d85d1cfe5a1636a0d3897fd upstream. + +The delayed-write queue was never emptied at shutdown (close), something +which could lead to leaked urbs if the port is closed before being +runtime resumed due to a write. + +When this happens the output buffer would not drain on close +(closing_wait timeout), and after consecutive opens, writes could be +corrupted with previously buffered data, transfered with reduced +throughput or completely blocked. + +Note that unbusy_queued_urb() was simply moved out of CONFIG_PM. + +Fixes: 383cedc3bb43 ("USB: serial: full autosuspend support for the +option driver") + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/usb_wwan.c | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +--- a/drivers/usb/serial/usb_wwan.c ++++ b/drivers/usb/serial/usb_wwan.c +@@ -434,12 +434,26 @@ int usb_wwan_open(struct tty_struct *tty + } + EXPORT_SYMBOL(usb_wwan_open); + ++static void unbusy_queued_urb(struct urb *urb, ++ struct usb_wwan_port_private *portdata) ++{ ++ int i; ++ ++ for (i = 0; i < N_OUT_URB; i++) { ++ if (urb == portdata->out_urbs[i]) { ++ clear_bit(i, &portdata->out_busy); ++ break; ++ } ++ } ++} ++ + void usb_wwan_close(struct usb_serial_port *port) + { + int i; + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata = port->serial->private; ++ struct urb *urb; + + dbg("%s", __func__); + portdata = usb_get_serial_port_data(port); +@@ -450,6 +464,14 @@ void usb_wwan_close(struct usb_serial_po + portdata->opened = 0; + spin_unlock_irq(&intfdata->susp_lock); + ++ for (;;) { ++ urb = usb_get_from_anchor(&portdata->delayed); ++ if (!urb) ++ break; ++ unbusy_queued_urb(urb, portdata); ++ usb_autopm_put_interface_async(serial->interface); ++ } ++ + for (i = 0; i < N_IN_URB; i++) + usb_kill_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) +@@ -667,18 +689,6 @@ int usb_wwan_suspend(struct usb_serial * + } + EXPORT_SYMBOL(usb_wwan_suspend); + +-static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) +-{ +- int i; +- +- for (i = 0; i < N_OUT_URB; i++) { +- if (urb == portdata->out_urbs[i]) { +- clear_bit(i, &portdata->out_busy); +- break; +- } +- } +-} +- + static void play_delayed(struct usb_serial_port *port) + { + struct usb_wwan_intf_private *data; diff --git a/queue-3.4/usb-usb_wwan-fix-write-and-suspend-race.patch b/queue-3.4/usb-usb_wwan-fix-write-and-suspend-race.patch new file mode 100644 index 00000000000..9d2ae884e38 --- /dev/null +++ b/queue-3.4/usb-usb_wwan-fix-write-and-suspend-race.patch @@ -0,0 +1,57 @@ +From 170fad9e22df0063eba0701adb966786d7a4ec5a Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 26 May 2014 19:23:15 +0200 +Subject: USB: usb_wwan: fix write and suspend race + +From: Johan Hovold + +commit 170fad9e22df0063eba0701adb966786d7a4ec5a 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 susp_lock after determining the +device is idle but before setting the suspended flag, thus leaving a +window where a concurrent write() can submit an urb. + +Fixes: 383cedc3bb43 ("USB: serial: full autosuspend support for the +option driver") + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/usb_wwan.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/drivers/usb/serial/usb_wwan.c ++++ b/drivers/usb/serial/usb_wwan.c +@@ -647,22 +647,20 @@ EXPORT_SYMBOL(usb_wwan_release); + int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) + { + struct usb_wwan_intf_private *intfdata = serial->private; +- int b; + + dbg("%s entered", __func__); + ++ spin_lock_irq(&intfdata->susp_lock); + if (PMSG_IS_AUTO(message)) { +- spin_lock_irq(&intfdata->susp_lock); +- b = intfdata->in_flight; +- spin_unlock_irq(&intfdata->susp_lock); +- +- if (b) ++ if (intfdata->in_flight) { ++ spin_unlock_irq(&intfdata->susp_lock); + return -EBUSY; ++ } + } + +- spin_lock_irq(&intfdata->susp_lock); + intfdata->suspended = 1; + spin_unlock_irq(&intfdata->susp_lock); ++ + stop_read_write_urbs(serial); + + return 0; -- 2.47.3