From: Greg Kroah-Hartman Date: Fri, 26 Oct 2012 23:13:26 +0000 (-0700) Subject: 3.6-stable patches X-Git-Tag: v3.0.49~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3301129861539171b6e7d24c4cde815715fbae3e;p=thirdparty%2Fkernel%2Fstable-queue.git 3.6-stable patches added patches: usb-metro-usb-fix-io-after-disconnect.patch usb-metro-usb-fix-port-data-memory-leak.patch usb-mos7720-fix-port-data-memory-leak.patch usb-mos7840-fix-port-device-leak-in-error-path.patch usb-mos7840-fix-urb-leak-at-release.patch usb-mos7840-remove-invalid-disconnect-handling.patch usb-mos7840-remove-null-urb-submission.patch usb-quatech2-fix-close-and-disconnect-urb-handling.patch usb-quatech2-fix-io-after-disconnect.patch usb-quatech2-fix-memory-leak-in-error-path.patch usb-quatech2-fix-port-data-memory-leaks.patch usb-serial-fix-memory-leak-in-sierra_release.patch usb-sierra-fix-memory-leak-in-attach-error-path.patch usb-sierra-fix-memory-leak-in-probe-error-path.patch usb-sierra-fix-port-data-memory-leak.patch --- diff --git a/queue-3.6/series b/queue-3.6/series index b2f3018ab35..b6746574c6e 100644 --- a/queue-3.6/series +++ b/queue-3.6/series @@ -53,3 +53,18 @@ usb-whiteheat-fix-memory-leak-in-error-path.patch usb-whiteheat-fix-port-data-memory-leak.patch usb-opticon-fix-dma-from-stack.patch usb-opticon-fix-memory-leak-in-error-path.patch +usb-metro-usb-fix-port-data-memory-leak.patch +usb-metro-usb-fix-io-after-disconnect.patch +usb-mos7720-fix-port-data-memory-leak.patch +usb-quatech2-fix-memory-leak-in-error-path.patch +usb-quatech2-fix-port-data-memory-leaks.patch +usb-quatech2-fix-close-and-disconnect-urb-handling.patch +usb-quatech2-fix-io-after-disconnect.patch +usb-serial-fix-memory-leak-in-sierra_release.patch +usb-sierra-fix-memory-leak-in-attach-error-path.patch +usb-sierra-fix-memory-leak-in-probe-error-path.patch +usb-sierra-fix-port-data-memory-leak.patch +usb-mos7840-fix-urb-leak-at-release.patch +usb-mos7840-fix-port-device-leak-in-error-path.patch +usb-mos7840-remove-null-urb-submission.patch +usb-mos7840-remove-invalid-disconnect-handling.patch diff --git a/queue-3.6/usb-metro-usb-fix-io-after-disconnect.patch b/queue-3.6/usb-metro-usb-fix-io-after-disconnect.patch new file mode 100644 index 00000000000..9bbfdaf9408 --- /dev/null +++ b/queue-3.6/usb-metro-usb-fix-io-after-disconnect.patch @@ -0,0 +1,43 @@ +From 2ee44fbeac92c36e53779a57ee84cfee1affe418 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:00 +0200 +Subject: USB: metro-usb: fix io after disconnect + +From: Johan Hovold + +commit 2ee44fbeac92c36e53779a57ee84cfee1affe418 upstream. + +Make sure no control urb is submitted during close after a disconnect by +checking the disconnected flag. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/metro-usb.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/drivers/usb/serial/metro-usb.c ++++ b/drivers/usb/serial/metro-usb.c +@@ -188,16 +188,13 @@ static void metrousb_cleanup(struct usb_ + { + dev_dbg(&port->dev, "%s\n", __func__); + +- if (port->serial->dev) { +- /* Shutdown any interrupt in urbs. */ +- if (port->interrupt_in_urb) { +- usb_unlink_urb(port->interrupt_in_urb); +- usb_kill_urb(port->interrupt_in_urb); +- } ++ usb_unlink_urb(port->interrupt_in_urb); ++ usb_kill_urb(port->interrupt_in_urb); + +- /* Send deactivate cmd to device */ ++ mutex_lock(&port->serial->disc_mutex); ++ if (!port->serial->disconnected) + metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); +- } ++ mutex_unlock(&port->serial->disc_mutex); + } + + static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) diff --git a/queue-3.6/usb-metro-usb-fix-port-data-memory-leak.patch b/queue-3.6/usb-metro-usb-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..0a138b5f80a --- /dev/null +++ b/queue-3.6/usb-metro-usb-fix-port-data-memory-leak.patch @@ -0,0 +1,103 @@ +From 50dde8686eec41bf3d7cbec7a6f76c073ab01903 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:28:59 +0200 +Subject: USB: metro-usb: fix port-data memory leak + +From: Johan Hovold + +commit 50dde8686eec41bf3d7cbec7a6f76c073ab01903 upstream. + +Fix port-data memory leak by moving port data allocation and +deallocation to port_probe and port_remove. + +Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no +driver is bound) the port private data is no longer freed at release as +it is no longer accessible. + +Note that the call to metrousb_clean (close) in shutdown was redundant. + +Compile-only tested. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/metro-usb.c | 50 ++++++++++------------------------------- + 1 file changed, 13 insertions(+), 37 deletions(-) + +--- a/drivers/usb/serial/metro-usb.c ++++ b/drivers/usb/serial/metro-usb.c +@@ -280,51 +280,27 @@ static int metrousb_set_modem_ctrl(struc + return retval; + } + +-static void metrousb_shutdown(struct usb_serial *serial) ++static int metrousb_port_probe(struct usb_serial_port *port) + { +- int i = 0; ++ struct metrousb_private *metro_priv; + +- dev_dbg(&serial->dev->dev, "%s\n", __func__); ++ metro_priv = kzalloc(sizeof(*metro_priv), GFP_KERNEL); ++ if (!metro_priv) ++ return -ENOMEM; + +- /* Stop reading and writing on all ports. */ +- for (i = 0; i < serial->num_ports; ++i) { +- /* Close any open urbs. */ +- metrousb_cleanup(serial->port[i]); ++ spin_lock_init(&metro_priv->lock); + +- /* Free memory. */ +- kfree(usb_get_serial_port_data(serial->port[i])); +- usb_set_serial_port_data(serial->port[i], NULL); ++ usb_set_serial_port_data(port, metro_priv); + +- dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n", +- __func__, serial->port[i]->number); +- } ++ return 0; + } + +-static int metrousb_startup(struct usb_serial *serial) ++static int metrousb_port_remove(struct usb_serial_port *port) + { + struct metrousb_private *metro_priv; +- struct usb_serial_port *port; +- int i = 0; +- +- dev_dbg(&serial->dev->dev, "%s\n", __func__); + +- /* Loop through the serial ports setting up the private structures. +- * Currently we only use one port. */ +- for (i = 0; i < serial->num_ports; ++i) { +- port = serial->port[i]; +- +- /* Declare memory. */ +- metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL); +- if (!metro_priv) +- return -ENOMEM; +- +- /* Initialize memory. */ +- spin_lock_init(&metro_priv->lock); +- usb_set_serial_port_data(port, metro_priv); +- +- dev_dbg(&serial->dev->dev, "%s - port number=%d\n ", +- __func__, port->number); +- } ++ metro_priv = usb_get_serial_port_data(port); ++ kfree(metro_priv); + + return 0; + } +@@ -423,8 +399,8 @@ static struct usb_serial_driver metrousb + .close = metrousb_cleanup, + .read_int_callback = metrousb_read_int_callback, + .write_int_callback = metrousb_write_int_callback, +- .attach = metrousb_startup, +- .release = metrousb_shutdown, ++ .port_probe = metrousb_port_probe, ++ .port_remove = metrousb_port_remove, + .throttle = metrousb_throttle, + .unthrottle = metrousb_unthrottle, + .tiocmget = metrousb_tiocmget, diff --git a/queue-3.6/usb-mos7720-fix-port-data-memory-leak.patch b/queue-3.6/usb-mos7720-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..10c7274c5e0 --- /dev/null +++ b/queue-3.6/usb-mos7720-fix-port-data-memory-leak.patch @@ -0,0 +1,128 @@ +From 4230af572f95b3115bba1ee6fb95681f3851ab26 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:05 +0200 +Subject: USB: mos7720: fix port-data memory leak + +From: Johan Hovold + +commit 4230af572f95b3115bba1ee6fb95681f3851ab26 upstream. + +Fix port-data memory leak by moving port data allocation and +deallocation to port_probe and port_remove. + +Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no +driver is bound) the port private data is no longer freed at release as +it is no longer accessible. + +Note that this patch also fixes a second port-data memory leak in the +error path of attach, should parallel-port initialisation fail. + +Compile-only tested. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/mos7720.c | 62 ++++++++++++++++++++++--------------------- + 1 file changed, 32 insertions(+), 30 deletions(-) + +--- a/drivers/usb/serial/mos7720.c ++++ b/drivers/usb/serial/mos7720.c +@@ -2023,9 +2023,7 @@ static int mos7720_ioctl(struct tty_stru + + static int mos7720_startup(struct usb_serial *serial) + { +- struct moschip_port *mos7720_port; + struct usb_device *dev; +- int i; + char data; + u16 product; + int ret_val; +@@ -2063,29 +2061,6 @@ static int mos7720_startup(struct usb_se + serial->port[1]->interrupt_in_buffer = NULL; + } + +- +- /* set up serial port private structures */ +- for (i = 0; i < serial->num_ports; ++i) { +- mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); +- if (mos7720_port == NULL) { +- dev_err(&dev->dev, "%s - Out of memory\n", __func__); +- return -ENOMEM; +- } +- +- /* Initialize all port interrupt end point to port 0 int +- * endpoint. Our device has only one interrupt endpoint +- * common to all ports */ +- serial->port[i]->interrupt_in_endpointAddress = +- serial->port[0]->interrupt_in_endpointAddress; +- +- mos7720_port->port = serial->port[i]; +- usb_set_serial_port_data(serial->port[i], mos7720_port); +- +- dbg("port number is %d", serial->port[i]->number); +- dbg("serial number is %d", serial->minor); +- } +- +- + /* setting configuration feature to one */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ); +@@ -2113,8 +2088,6 @@ static int mos7720_startup(struct usb_se + + static void mos7720_release(struct usb_serial *serial) + { +- int i; +- + #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT + /* close the parallel port */ + +@@ -2153,9 +2126,36 @@ static void mos7720_release(struct usb_s + kref_put(&mos_parport->ref_count, destroy_mos_parport); + } + #endif +- /* free private structure allocated for serial port */ +- for (i = 0; i < serial->num_ports; ++i) +- kfree(usb_get_serial_port_data(serial->port[i])); ++} ++ ++static int mos7720_port_probe(struct usb_serial_port *port) ++{ ++ struct moschip_port *mos7720_port; ++ ++ mos7720_port = kzalloc(sizeof(*mos7720_port), GFP_KERNEL); ++ if (!mos7720_port) ++ return -ENOMEM; ++ ++ /* Initialize all port interrupt end point to port 0 int endpoint. ++ * Our device has only one interrupt endpoint common to all ports. ++ */ ++ port->interrupt_in_endpointAddress = ++ port->serial->port[0]->interrupt_in_endpointAddress; ++ mos7720_port->port = port; ++ ++ usb_set_serial_port_data(port, mos7720_port); ++ ++ return 0; ++} ++ ++static int mos7720_port_remove(struct usb_serial_port *port) ++{ ++ struct moschip_port *mos7720_port; ++ ++ mos7720_port = usb_get_serial_port_data(port); ++ kfree(mos7720_port); ++ ++ return 0; + } + + static struct usb_serial_driver moschip7720_2port_driver = { +@@ -2173,6 +2173,8 @@ static struct usb_serial_driver moschip7 + .probe = mos77xx_probe, + .attach = mos7720_startup, + .release = mos7720_release, ++ .port_probe = mos7720_port_probe, ++ .port_remove = mos7720_port_remove, + .ioctl = mos7720_ioctl, + .tiocmget = mos7720_tiocmget, + .tiocmset = mos7720_tiocmset, diff --git a/queue-3.6/usb-mos7840-fix-port-device-leak-in-error-path.patch b/queue-3.6/usb-mos7840-fix-port-device-leak-in-error-path.patch new file mode 100644 index 00000000000..72117128406 --- /dev/null +++ b/queue-3.6/usb-mos7840-fix-port-device-leak-in-error-path.patch @@ -0,0 +1,30 @@ +From 3eb55cc4ed88eee3b5230f66abcdbd2a91639eda Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 13:35:10 +0200 +Subject: USB: mos7840: fix port-device leak in error path + +From: Johan Hovold + +commit 3eb55cc4ed88eee3b5230f66abcdbd2a91639eda upstream. + +The driver set the usb-serial port pointers to NULL on errors in attach, +effectively preventing usb-serial core from decrementing the port ref +counters and releasing the port devices and associated data. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/mos7840.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/usb/serial/mos7840.c ++++ b/drivers/usb/serial/mos7840.c +@@ -2684,7 +2684,6 @@ error: + kfree(mos7840_port->ctrl_buf); + usb_free_urb(mos7840_port->control_urb); + kfree(mos7840_port); +- serial->port[i] = NULL; + } + return status; + } diff --git a/queue-3.6/usb-mos7840-fix-urb-leak-at-release.patch b/queue-3.6/usb-mos7840-fix-urb-leak-at-release.patch new file mode 100644 index 00000000000..4c3c541300d --- /dev/null +++ b/queue-3.6/usb-mos7840-fix-urb-leak-at-release.patch @@ -0,0 +1,28 @@ +From 65a4cdbb170e4ec1a7fa0e94936d47e24a17b0e8 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 13:35:09 +0200 +Subject: USB: mos7840: fix urb leak at release + +From: Johan Hovold + +commit 65a4cdbb170e4ec1a7fa0e94936d47e24a17b0e8 upstream. + +Make sure control urb is freed at release. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/mos7840.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/serial/mos7840.c ++++ b/drivers/usb/serial/mos7840.c +@@ -2754,6 +2754,7 @@ static void mos7840_release(struct usb_s + del_timer_sync(&mos7840_port->led_timer1); + del_timer_sync(&mos7840_port->led_timer2); + } ++ usb_free_urb(mos7840_port->control_urb); + kfree(mos7840_port->ctrl_buf); + kfree(mos7840_port->dr); + kfree(mos7840_port); diff --git a/queue-3.6/usb-mos7840-remove-invalid-disconnect-handling.patch b/queue-3.6/usb-mos7840-remove-invalid-disconnect-handling.patch new file mode 100644 index 00000000000..1237d134b80 --- /dev/null +++ b/queue-3.6/usb-mos7840-remove-invalid-disconnect-handling.patch @@ -0,0 +1,58 @@ +From e681b66f2e19fadbe8a7e2a17900978cb6bc921f Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 18:56:33 +0200 +Subject: USB: mos7840: remove invalid disconnect handling + +From: Johan Hovold + +commit e681b66f2e19fadbe8a7e2a17900978cb6bc921f upstream. + +Remove private zombie flag used to signal disconnect and to prevent +control urb from being submitted from interrupt urb completion handler. + +The control urb will not be re-submitted as both the control urb and the +interrupt urb is killed on disconnect. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/mos7840.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +--- a/drivers/usb/serial/mos7840.c ++++ b/drivers/usb/serial/mos7840.c +@@ -222,7 +222,6 @@ struct moschip_port { + __u8 shadowMCR; /* last MCR value received */ + char open; + char open_ports; +- char zombie; + wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ + wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ + int delta_msr_cond; +@@ -691,14 +690,7 @@ static void mos7840_interrupt_callback(s + wreg = MODEM_STATUS_REGISTER; + break; + } +- spin_lock(&mos7840_port->pool_lock); +- if (!mos7840_port->zombie) { +- rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); +- } else { +- spin_unlock(&mos7840_port->pool_lock); +- return; +- } +- spin_unlock(&mos7840_port->pool_lock); ++ rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); + } + } + } +@@ -2700,9 +2692,6 @@ static void mos7840_disconnect(struct us + mos7840_port = mos7840_get_port_private(serial->port[i]); + dbg ("mos7840_port %d = %p", i, mos7840_port); + if (mos7840_port) { +- spin_lock_irqsave(&mos7840_port->pool_lock, flags); +- mos7840_port->zombie = 1; +- spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); + usb_kill_urb(mos7840_port->control_urb); + } + } diff --git a/queue-3.6/usb-mos7840-remove-null-urb-submission.patch b/queue-3.6/usb-mos7840-remove-null-urb-submission.patch new file mode 100644 index 00000000000..0f9feb8c6f4 --- /dev/null +++ b/queue-3.6/usb-mos7840-remove-null-urb-submission.patch @@ -0,0 +1,65 @@ +From 28c3ae9a8cf45f439c9a0779ebd0256e2ae72813 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 18:56:32 +0200 +Subject: USB: mos7840: remove NULL-urb submission + +From: Johan Hovold + +commit 28c3ae9a8cf45f439c9a0779ebd0256e2ae72813 upstream. + +The private int_urb is never allocated so the submission from the +control completion handler will always fail. Remove this odd piece of +broken code. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/mos7840.c | 15 +-------------- + 1 file changed, 1 insertion(+), 14 deletions(-) + +--- a/drivers/usb/serial/mos7840.c ++++ b/drivers/usb/serial/mos7840.c +@@ -218,7 +218,6 @@ struct moschip_port { + int port_num; /*Actual port number in the device(1,2,etc) */ + struct urb *write_urb; /* write URB for this port */ + struct urb *read_urb; /* read URB for this port */ +- struct urb *int_urb; + __u8 shadowLCR; /* last LCR value received */ + __u8 shadowMCR; /* last MCR value received */ + char open; +@@ -493,7 +492,6 @@ static void mos7840_control_callback(str + unsigned char *data; + struct moschip_port *mos7840_port; + __u8 regval = 0x0; +- int result = 0; + int status = urb->status; + + mos7840_port = urb->context; +@@ -512,7 +510,7 @@ static void mos7840_control_callback(str + default: + dbg("%s - nonzero urb status received: %d", __func__, + status); +- goto exit; ++ return; + } + + dbg("%s urb buffer size is %d", __func__, urb->actual_length); +@@ -525,17 +523,6 @@ static void mos7840_control_callback(str + mos7840_handle_new_msr(mos7840_port, regval); + else if (mos7840_port->MsrLsr == 1) + mos7840_handle_new_lsr(mos7840_port, regval); +- +-exit: +- spin_lock(&mos7840_port->pool_lock); +- if (!mos7840_port->zombie) +- result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC); +- spin_unlock(&mos7840_port->pool_lock); +- if (result) { +- dev_err(&urb->dev->dev, +- "%s - Error %d submitting interrupt urb\n", +- __func__, result); +- } + } + + static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, diff --git a/queue-3.6/usb-quatech2-fix-close-and-disconnect-urb-handling.patch b/queue-3.6/usb-quatech2-fix-close-and-disconnect-urb-handling.patch new file mode 100644 index 00000000000..64cddcab942 --- /dev/null +++ b/queue-3.6/usb-quatech2-fix-close-and-disconnect-urb-handling.patch @@ -0,0 +1,42 @@ +From 8e512ab0b675da20e023439a5811e3f2554e6852 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:09 +0200 +Subject: USB: quatech2: fix close and disconnect urb handling + +From: Johan Hovold + +commit 8e512ab0b675da20e023439a5811e3f2554e6852 upstream. + +Kill urbs unconditionally at close and disconnect. + +Note that URB status is not valid outside of completion handler. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/quatech2.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/usb/serial/quatech2.c ++++ b/drivers/usb/serial/quatech2.c +@@ -425,8 +425,7 @@ static void qt2_close(struct usb_serial_ + port_priv->is_open = false; + + spin_lock_irqsave(&port_priv->urb_lock, flags); +- if (port_priv->write_urb->status == -EINPROGRESS) +- usb_kill_urb(port_priv->write_urb); ++ usb_kill_urb(port_priv->write_urb); + port_priv->urb_in_use = false; + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + +@@ -467,8 +466,7 @@ static void qt2_disconnect(struct usb_se + { + struct qt2_serial_private *serial_priv = usb_get_serial_data(serial); + +- if (serial_priv->read_urb->status == -EINPROGRESS) +- usb_kill_urb(serial_priv->read_urb); ++ usb_kill_urb(serial_priv->read_urb); + } + + static int get_serial_info(struct usb_serial_port *port, diff --git a/queue-3.6/usb-quatech2-fix-io-after-disconnect.patch b/queue-3.6/usb-quatech2-fix-io-after-disconnect.patch new file mode 100644 index 00000000000..3ca0a6f3b42 --- /dev/null +++ b/queue-3.6/usb-quatech2-fix-io-after-disconnect.patch @@ -0,0 +1,42 @@ +From 2f0295adf6438188c4cd0868f2b1976a2b034e1d Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:10 +0200 +Subject: USB: quatech2: fix io after disconnect + +From: Johan Hovold + +commit 2f0295adf6438188c4cd0868f2b1976a2b034e1d upstream. + +Make sure no control urb is submitted during close after a disconnect by +checking the disconnected flag. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/quatech2.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/usb/serial/quatech2.c ++++ b/drivers/usb/serial/quatech2.c +@@ -429,6 +429,12 @@ static void qt2_close(struct usb_serial_ + port_priv->urb_in_use = false; + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + ++ mutex_lock(&port->serial->disc_mutex); ++ if (port->serial->disconnected) { ++ mutex_unlock(&port->serial->disc_mutex); ++ return; ++ } ++ + /* flush the port transmit buffer */ + i = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), +@@ -460,6 +466,7 @@ static void qt2_close(struct usb_serial_ + dev_err(&port->dev, "%s - close port failed %i\n", + __func__, i); + ++ mutex_unlock(&port->serial->disc_mutex); + } + + static void qt2_disconnect(struct usb_serial *serial) diff --git a/queue-3.6/usb-quatech2-fix-memory-leak-in-error-path.patch b/queue-3.6/usb-quatech2-fix-memory-leak-in-error-path.patch new file mode 100644 index 00000000000..1e7be2735d6 --- /dev/null +++ b/queue-3.6/usb-quatech2-fix-memory-leak-in-error-path.patch @@ -0,0 +1,29 @@ +From b8a0055050b6294826171641b182c09f78f4cc63 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:07 +0200 +Subject: USB: quatech2: fix memory leak in error path + +From: Johan Hovold + +commit b8a0055050b6294826171641b182c09f78f4cc63 upstream. + +Fix memory leak in attach error path where the read urb was never freed. + +Signed-off-by: Johan Hovold +Cc: Bill Pemberton +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/quatech2.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/serial/quatech2.c ++++ b/drivers/usb/serial/quatech2.c +@@ -825,6 +825,7 @@ static int qt2_setup_urbs(struct usb_ser + if (status != 0) { + dev_err(&serial->dev->dev, + "%s - submit read urb failed %i\n", __func__, status); ++ usb_free_urb(serial_priv->read_urb); + return status; + } + diff --git a/queue-3.6/usb-quatech2-fix-port-data-memory-leaks.patch b/queue-3.6/usb-quatech2-fix-port-data-memory-leaks.patch new file mode 100644 index 00000000000..ada716e12c2 --- /dev/null +++ b/queue-3.6/usb-quatech2-fix-port-data-memory-leaks.patch @@ -0,0 +1,230 @@ +From 40d04738491d7ac1aa708ba434ff3480ec9e1b96 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:08 +0200 +Subject: USB: quatech2: fix port-data memory leaks + +From: Johan Hovold + +commit 40d04738491d7ac1aa708ba434ff3480ec9e1b96 upstream. + +Fix port-data memory leak by moving port data allocation and +deallocation to port_probe and port_remove. + +Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no +driver is bound) the port private data is no longer freed at release as +it is no longer accessible. + +Note that this also fixes memory leaks in the error path of attach where +the write urbs were not freed on errors. + +Make sure all interface-data deallocation is done in release by moving +the read urb deallocation from disconnect. + +Note that the write urb is killed during close so that the call in +disconnect was superfluous. + +Compile-only tested. + +Signed-off-by: Johan Hovold +Cc: Bill Pemberton +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/quatech2.c | 121 +++++++++++++++++------------------------- + 1 file changed, 51 insertions(+), 70 deletions(-) + +--- a/drivers/usb/serial/quatech2.c ++++ b/drivers/usb/serial/quatech2.c +@@ -145,12 +145,12 @@ static void qt2_read_bulk_callback(struc + + static void qt2_release(struct usb_serial *serial) + { +- int i; ++ struct qt2_serial_private *serial_priv; + +- kfree(usb_get_serial_data(serial)); ++ serial_priv = usb_get_serial_data(serial); + +- for (i = 0; i < serial->num_ports; i++) +- kfree(usb_get_serial_port_data(serial->port[i])); ++ usb_free_urb(serial_priv->read_urb); ++ kfree(serial_priv); + } + + static inline int calc_baud_divisor(int baudrate) +@@ -466,21 +466,9 @@ static void qt2_close(struct usb_serial_ + static void qt2_disconnect(struct usb_serial *serial) + { + struct qt2_serial_private *serial_priv = usb_get_serial_data(serial); +- struct qt2_port_private *port_priv; +- int i; + + if (serial_priv->read_urb->status == -EINPROGRESS) + usb_kill_urb(serial_priv->read_urb); +- +- usb_free_urb(serial_priv->read_urb); +- +- for (i = 0; i < serial->num_ports; i++) { +- port_priv = usb_get_serial_port_data(serial->port[i]); +- +- if (port_priv->write_urb->status == -EINPROGRESS) +- usb_kill_urb(port_priv->write_urb); +- usb_free_urb(port_priv->write_urb); +- } + } + + static int get_serial_info(struct usb_serial_port *port, +@@ -775,11 +763,9 @@ static void qt2_read_bulk_callback(struc + + static int qt2_setup_urbs(struct usb_serial *serial) + { +- struct usb_serial_port *port; + struct usb_serial_port *port0; + struct qt2_serial_private *serial_priv; +- struct qt2_port_private *port_priv; +- int pcount, status; ++ int status; + + port0 = serial->port[0]; + +@@ -797,30 +783,6 @@ static int qt2_setup_urbs(struct usb_ser + sizeof(serial_priv->read_buffer), + qt2_read_bulk_callback, serial); + +- /* setup write_urb for each port */ +- for (pcount = 0; pcount < serial->num_ports; pcount++) { +- +- port = serial->port[pcount]; +- port_priv = usb_get_serial_port_data(port); +- +- port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); +- if (!port_priv->write_urb) { +- dev_err(&serial->dev->dev, +- "failed to alloc write_urb for port %i\n", +- pcount); +- return -ENOMEM; +- } +- +- usb_fill_bulk_urb(port_priv->write_urb, +- serial->dev, +- usb_sndbulkpipe(serial->dev, +- port0-> +- bulk_out_endpointAddress), +- port_priv->write_buffer, +- sizeof(port_priv->write_buffer), +- qt2_write_bulk_callback, port); +- } +- + status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL); + if (status != 0) { + dev_err(&serial->dev->dev, +@@ -830,14 +792,12 @@ static int qt2_setup_urbs(struct usb_ser + } + + return 0; +- + } + + static int qt2_attach(struct usb_serial *serial) + { + struct qt2_serial_private *serial_priv; +- struct qt2_port_private *port_priv; +- int status, pcount; ++ int status; + + /* power on unit */ + status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), +@@ -857,26 +817,6 @@ static int qt2_attach(struct usb_serial + + usb_set_serial_data(serial, serial_priv); + +- for (pcount = 0; pcount < serial->num_ports; pcount++) { +- port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); +- if (!port_priv) { +- dev_err(&serial->dev->dev, +- "%s- kmalloc(%Zd) failed.\n", __func__, +- sizeof(*port_priv)); +- pcount--; +- status = -ENOMEM; +- goto attach_failed; +- } +- +- spin_lock_init(&port_priv->lock); +- spin_lock_init(&port_priv->urb_lock); +- init_waitqueue_head(&port_priv->delta_msr_wait); +- +- port_priv->port = serial->port[pcount]; +- +- usb_set_serial_port_data(serial->port[pcount], port_priv); +- } +- + status = qt2_setup_urbs(serial); + if (status != 0) + goto attach_failed; +@@ -884,14 +824,53 @@ static int qt2_attach(struct usb_serial + return 0; + + attach_failed: +- for (/* empty */; pcount >= 0; pcount--) { +- port_priv = usb_get_serial_port_data(serial->port[pcount]); +- kfree(port_priv); +- } + kfree(serial_priv); + return status; + } + ++static int qt2_port_probe(struct usb_serial_port *port) ++{ ++ struct usb_serial *serial = port->serial; ++ struct qt2_port_private *port_priv; ++ u8 bEndpointAddress; ++ ++ port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); ++ if (!port_priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&port_priv->lock); ++ spin_lock_init(&port_priv->urb_lock); ++ init_waitqueue_head(&port_priv->delta_msr_wait); ++ port_priv->port = port; ++ ++ port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!port_priv->write_urb) { ++ kfree(port_priv); ++ return -ENOMEM; ++ } ++ bEndpointAddress = serial->port[0]->bulk_out_endpointAddress; ++ usb_fill_bulk_urb(port_priv->write_urb, serial->dev, ++ usb_sndbulkpipe(serial->dev, bEndpointAddress), ++ port_priv->write_buffer, ++ sizeof(port_priv->write_buffer), ++ qt2_write_bulk_callback, port); ++ ++ usb_set_serial_port_data(port, port_priv); ++ ++ return 0; ++} ++ ++static int qt2_port_remove(struct usb_serial_port *port) ++{ ++ struct qt2_port_private *port_priv; ++ ++ port_priv = usb_get_serial_port_data(port); ++ usb_free_urb(port_priv->write_urb); ++ kfree(port_priv); ++ ++ return 0; ++} ++ + static int qt2_tiocmget(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; +@@ -1130,6 +1109,8 @@ static struct usb_serial_driver qt2_devi + .attach = qt2_attach, + .release = qt2_release, + .disconnect = qt2_disconnect, ++ .port_probe = qt2_port_probe, ++ .port_remove = qt2_port_remove, + .dtr_rts = qt2_dtr_rts, + .break_ctl = qt2_break_ctl, + .tiocmget = qt2_tiocmget, diff --git a/queue-3.6/usb-serial-fix-memory-leak-in-sierra_release.patch b/queue-3.6/usb-serial-fix-memory-leak-in-sierra_release.patch new file mode 100644 index 00000000000..034a4af085b --- /dev/null +++ b/queue-3.6/usb-serial-fix-memory-leak-in-sierra_release.patch @@ -0,0 +1,30 @@ +From f7bc5051667b74c3861f79eed98c60d5c3b883f7 Mon Sep 17 00:00:00 2001 +From: Lennart Sorensen +Date: Wed, 24 Oct 2012 10:23:09 -0400 +Subject: USB: serial: Fix memory leak in sierra_release() + +From: Lennart Sorensen + +commit f7bc5051667b74c3861f79eed98c60d5c3b883f7 upstream. + +I found a memory leak in sierra_release() (well sierra_probe() I guess) +that looses 8 bytes each time the driver releases a device. + +Signed-off-by: Len Sorensen +Acked-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/sierra.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/serial/sierra.c ++++ b/drivers/usb/serial/sierra.c +@@ -961,6 +961,7 @@ static void sierra_release(struct usb_se + continue; + kfree(portdata); + } ++ kfree(serial->private); + } + + #ifdef CONFIG_PM diff --git a/queue-3.6/usb-sierra-fix-memory-leak-in-attach-error-path.patch b/queue-3.6/usb-sierra-fix-memory-leak-in-attach-error-path.patch new file mode 100644 index 00000000000..e1e37f0cf12 --- /dev/null +++ b/queue-3.6/usb-sierra-fix-memory-leak-in-attach-error-path.patch @@ -0,0 +1,43 @@ +From 7e41f9bcdd2e813ea2a3c40db291d87ea06b559f Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:17 +0200 +Subject: USB: sierra: fix memory leak in attach error path + +From: Johan Hovold + +commit 7e41f9bcdd2e813ea2a3c40db291d87ea06b559f upstream. + +Make sure port private data is deallocated on errors in attach. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/sierra.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/usb/serial/sierra.c ++++ b/drivers/usb/serial/sierra.c +@@ -907,7 +907,7 @@ static int sierra_startup(struct usb_ser + dev_dbg(&port->dev, "%s: kmalloc for " + "sierra_port_private (%d) failed!\n", + __func__, i); +- return -ENOMEM; ++ goto err; + } + spin_lock_init(&portdata->lock); + init_usb_anchor(&portdata->active); +@@ -944,6 +944,13 @@ static int sierra_startup(struct usb_ser + } + + return 0; ++err: ++ for (--i; i >= 0; --i) { ++ portdata = usb_get_serial_port_data(serial->port[i]); ++ kfree(portdata); ++ } ++ ++ return -ENOMEM; + } + + static void sierra_release(struct usb_serial *serial) diff --git a/queue-3.6/usb-sierra-fix-memory-leak-in-probe-error-path.patch b/queue-3.6/usb-sierra-fix-memory-leak-in-probe-error-path.patch new file mode 100644 index 00000000000..15f618489a9 --- /dev/null +++ b/queue-3.6/usb-sierra-fix-memory-leak-in-probe-error-path.patch @@ -0,0 +1,70 @@ +From 084817d79399ab5ccab2f90a148b0369912a8369 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:18 +0200 +Subject: USB: sierra: fix memory leak in probe error path + +From: Johan Hovold + +commit 084817d79399ab5ccab2f90a148b0369912a8369 upstream. + +Move interface data allocation to attach so that it is deallocated on +errors in usb-serial probe. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/sierra.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/usb/serial/sierra.c ++++ b/drivers/usb/serial/sierra.c +@@ -162,7 +162,6 @@ static int sierra_probe(struct usb_seria + { + int result = 0; + struct usb_device *udev; +- struct sierra_intf_private *data; + u8 ifnum; + + udev = serial->dev; +@@ -189,11 +188,6 @@ static int sierra_probe(struct usb_seria + return -ENODEV; + } + +- data = serial->private = kzalloc(sizeof(struct sierra_intf_private), GFP_KERNEL); +- if (!data) +- return -ENOMEM; +- spin_lock_init(&data->susp_lock); +- + return result; + } + +@@ -887,11 +881,20 @@ static void sierra_dtr_rts(struct usb_se + static int sierra_startup(struct usb_serial *serial) + { + struct usb_serial_port *port; ++ struct sierra_intf_private *intfdata; + struct sierra_port_private *portdata; + struct sierra_iface_info *himemoryp = NULL; + int i; + u8 ifnum; + ++ intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL); ++ if (!intfdata) ++ return -ENOMEM; ++ ++ spin_lock_init(&intfdata->susp_lock); ++ ++ usb_set_serial_data(serial, intfdata); ++ + /* Set Device mode to D0 */ + sierra_set_power_state(serial->dev, 0x0000); + +@@ -949,6 +952,7 @@ err: + portdata = usb_get_serial_port_data(serial->port[i]); + kfree(portdata); + } ++ kfree(intfdata); + + return -ENOMEM; + } diff --git a/queue-3.6/usb-sierra-fix-port-data-memory-leak.patch b/queue-3.6/usb-sierra-fix-port-data-memory-leak.patch new file mode 100644 index 00000000000..5d5f91dbf83 --- /dev/null +++ b/queue-3.6/usb-sierra-fix-port-data-memory-leak.patch @@ -0,0 +1,188 @@ +From f525c05babc7938cc1d4236550fd8a659fb05960 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Oct 2012 10:29:19 +0200 +Subject: USB: sierra: fix port-data memory leak + +From: Johan Hovold + +commit f525c05babc7938cc1d4236550fd8a659fb05960 upstream. + +Fix port-data memory leak by moving port data allocation and +deallocation to port_probe and port_remove. + +Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no +driver is bound) the port private data is no longer freed at release as +it is no longer accessible. + +Note also that urb-count for multi-port interfaces has not been changed +even though the usb-serial port number is now determined from the port +and interface minor numbers. + +Compile-only tested. + +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/sierra.c | 127 ++++++++++++++++++++------------------------ + 1 file changed, 59 insertions(+), 68 deletions(-) + +--- a/drivers/usb/serial/sierra.c ++++ b/drivers/usb/serial/sierra.c +@@ -880,12 +880,7 @@ static void sierra_dtr_rts(struct usb_se + + static int sierra_startup(struct usb_serial *serial) + { +- struct usb_serial_port *port; + struct sierra_intf_private *intfdata; +- struct sierra_port_private *portdata; +- struct sierra_iface_info *himemoryp = NULL; +- int i; +- u8 ifnum; + + intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL); + if (!intfdata) +@@ -902,77 +897,71 @@ static int sierra_startup(struct usb_ser + if (nmea) + sierra_vsc_set_nmea(serial->dev, 1); + +- /* Now setup per port private data */ +- for (i = 0; i < serial->num_ports; i++) { +- port = serial->port[i]; +- portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); +- if (!portdata) { +- dev_dbg(&port->dev, "%s: kmalloc for " +- "sierra_port_private (%d) failed!\n", +- __func__, i); +- goto err; +- } +- spin_lock_init(&portdata->lock); +- init_usb_anchor(&portdata->active); +- init_usb_anchor(&portdata->delayed); +- ifnum = i; +- /* Assume low memory requirements */ +- portdata->num_out_urbs = N_OUT_URB; +- portdata->num_in_urbs = N_IN_URB; +- +- /* Determine actual memory requirements */ +- if (serial->num_ports == 1) { +- /* Get interface number for composite device */ +- ifnum = sierra_calc_interface(serial); +- himemoryp = +- (struct sierra_iface_info *)&typeB_interface_list; +- if (is_himemory(ifnum, himemoryp)) { +- portdata->num_out_urbs = N_OUT_URB_HM; +- portdata->num_in_urbs = N_IN_URB_HM; +- } +- } +- else { +- himemoryp = +- (struct sierra_iface_info *)&typeA_interface_list; +- if (is_himemory(i, himemoryp)) { +- portdata->num_out_urbs = N_OUT_URB_HM; +- portdata->num_in_urbs = N_IN_URB_HM; +- } +- } +- dev_dbg(&serial->dev->dev, +- "Memory usage (urbs) interface #%d, in=%d, out=%d\n", +- ifnum,portdata->num_in_urbs, portdata->num_out_urbs ); +- /* Set the port private data pointer */ +- usb_set_serial_port_data(port, portdata); +- } +- + return 0; +-err: +- for (--i; i >= 0; --i) { +- portdata = usb_get_serial_port_data(serial->port[i]); +- kfree(portdata); +- } +- kfree(intfdata); +- +- return -ENOMEM; + } + + static void sierra_release(struct usb_serial *serial) + { +- int i; +- struct usb_serial_port *port; ++ struct sierra_intf_private *intfdata; ++ ++ intfdata = usb_get_serial_data(serial); ++ kfree(intfdata); ++} ++ ++static int sierra_port_probe(struct usb_serial_port *port) ++{ ++ struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; ++ const struct sierra_iface_info *himemoryp; ++ u8 ifnum; + +- for (i = 0; i < serial->num_ports; ++i) { +- port = serial->port[i]; +- if (!port) +- continue; +- portdata = usb_get_serial_port_data(port); +- if (!portdata) +- continue; +- kfree(portdata); ++ portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); ++ if (!portdata) ++ return -ENOMEM; ++ ++ spin_lock_init(&portdata->lock); ++ init_usb_anchor(&portdata->active); ++ init_usb_anchor(&portdata->delayed); ++ ++ /* Assume low memory requirements */ ++ portdata->num_out_urbs = N_OUT_URB; ++ portdata->num_in_urbs = N_IN_URB; ++ ++ /* Determine actual memory requirements */ ++ if (serial->num_ports == 1) { ++ /* Get interface number for composite device */ ++ ifnum = sierra_calc_interface(serial); ++ himemoryp = &typeB_interface_list; ++ } else { ++ /* This is really the usb-serial port number of the interface ++ * rather than the interface number. ++ */ ++ ifnum = port->number - serial->minor; ++ himemoryp = &typeA_interface_list; ++ } ++ ++ if (is_himemory(ifnum, himemoryp)) { ++ portdata->num_out_urbs = N_OUT_URB_HM; ++ portdata->num_in_urbs = N_IN_URB_HM; + } +- kfree(serial->private); ++ ++ dev_dbg(&port->dev, ++ "Memory usage (urbs) interface #%d, in=%d, out=%d\n", ++ ifnum, portdata->num_in_urbs, portdata->num_out_urbs); ++ ++ usb_set_serial_port_data(port, portdata); ++ ++ return 0; ++} ++ ++static int sierra_port_remove(struct usb_serial_port *port) ++{ ++ struct sierra_port_private *portdata; ++ ++ portdata = usb_get_serial_port_data(port); ++ kfree(portdata); ++ ++ return 0; + } + + #ifdef CONFIG_PM +@@ -1076,6 +1065,8 @@ static struct usb_serial_driver sierra_d + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .release = sierra_release, ++ .port_probe = sierra_port_probe, ++ .port_remove = sierra_port_remove, + .suspend = sierra_suspend, + .resume = sierra_resume, + .read_int_callback = sierra_instat_callback,