diff options
author | Johan Hovold <jhovold@gmail.com> | 2012-10-17 16:31:35 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-28 10:56:13 -0700 |
commit | ef7c9b6a9cc09853a449a43050153cc785788d16 (patch) | |
tree | 64cb5128605cb8f8546f969ac99f4bcad3613ef6 | |
parent | 5592d451ce00a108312bf2152bde273e8532cf8c (diff) | |
download | linux-stable-ef7c9b6a9cc09853a449a43050153cc785788d16.tar.gz linux-stable-ef7c9b6a9cc09853a449a43050153cc785788d16.tar.bz2 linux-stable-ef7c9b6a9cc09853a449a43050153cc785788d16.zip |
USB: ti_usb_3410_5052: fix port-data memory leak
commit 51ef847df74632e7cfdf952afc3887de105b8b35 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.
Compile-only tested.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/serial/ti_usb_3410_5052.c | 88 |
1 files changed, 43 insertions, 45 deletions
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index a4404f5ad68e..33537bb778d0 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -98,6 +98,8 @@ struct ti_device { static int ti_startup(struct usb_serial *serial); static void ti_release(struct usb_serial *serial); +static int ti_port_probe(struct usb_serial_port *port); +static int ti_port_remove(struct usb_serial_port *port); static int ti_open(struct tty_struct *tty, struct usb_serial_port *port); static void ti_close(struct usb_serial_port *port); static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -223,6 +225,8 @@ static struct usb_serial_driver ti_1port_device = { .num_ports = 1, .attach = ti_startup, .release = ti_release, + .port_probe = ti_port_probe, + .port_remove = ti_port_remove, .open = ti_open, .close = ti_close, .write = ti_write, @@ -251,6 +255,8 @@ static struct usb_serial_driver ti_2port_device = { .num_ports = 2, .attach = ti_startup, .release = ti_release, + .port_probe = ti_port_probe, + .port_remove = ti_port_remove, .open = ti_open, .close = ti_close, .write = ti_write, @@ -358,11 +364,8 @@ module_exit(ti_exit); static int ti_startup(struct usb_serial *serial) { struct ti_device *tdev; - struct ti_port *tport; struct usb_device *dev = serial->dev; int status; - int i; - dbg("%s - product 0x%4X, num configurations %d, configuration value %d", __func__, le16_to_cpu(dev->descriptor.idProduct), @@ -409,42 +412,8 @@ static int ti_startup(struct usb_serial *serial) goto free_tdev; } - /* set up port structures */ - for (i = 0; i < serial->num_ports; ++i) { - tport = kzalloc(sizeof(struct ti_port), GFP_KERNEL); - if (tport == NULL) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - status = -ENOMEM; - goto free_tports; - } - spin_lock_init(&tport->tp_lock); - tport->tp_uart_base_addr = (i == 0 ? - TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR); - tport->tp_closing_wait = closing_wait; - init_waitqueue_head(&tport->tp_msr_wait); - init_waitqueue_head(&tport->tp_write_wait); - if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, - GFP_KERNEL)) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - kfree(tport); - status = -ENOMEM; - goto free_tports; - } - tport->tp_port = serial->port[i]; - tport->tp_tdev = tdev; - usb_set_serial_port_data(serial->port[i], tport); - tport->tp_uart_mode = 0; /* default is RS232 */ - } - return 0; -free_tports: - for (--i; i >= 0; --i) { - tport = usb_get_serial_port_data(serial->port[i]); - kfifo_free(&tport->write_fifo); - kfree(tport); - usb_set_serial_port_data(serial->port[i], NULL); - } free_tdev: kfree(tdev); usb_set_serial_data(serial, NULL); @@ -454,21 +423,50 @@ free_tdev: static void ti_release(struct usb_serial *serial) { - int i; struct ti_device *tdev = usb_get_serial_data(serial); + + kfree(tdev); +} + +static int ti_port_probe(struct usb_serial_port *port) +{ struct ti_port *tport; - for (i = 0; i < serial->num_ports; ++i) { - tport = usb_get_serial_port_data(serial->port[i]); - if (tport) { - kfifo_free(&tport->write_fifo); - kfree(tport); - } + tport = kzalloc(sizeof(*tport), GFP_KERNEL); + if (!tport) + return -ENOMEM; + + spin_lock_init(&tport->tp_lock); + if (port == port->serial->port[0]) + tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; + else + tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; + tport->tp_closing_wait = closing_wait; + init_waitqueue_head(&tport->tp_msr_wait); + init_waitqueue_head(&tport->tp_write_wait); + if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) { + kfree(tport); + return -ENOMEM; } + tport->tp_port = port; + tport->tp_tdev = usb_get_serial_data(port->serial); + tport->tp_uart_mode = 0; /* default is RS232 */ - kfree(tdev); + usb_set_serial_port_data(port, tport); + + return 0; } +static int ti_port_remove(struct usb_serial_port *port) +{ + struct ti_port *tport; + + tport = usb_get_serial_port_data(port); + kfifo_free(&tport->write_fifo); + kfree(tport); + + return 0; +} static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) { |