diff options
author | Johan Hovold <jhovold@gmail.com> | 2012-10-17 10:31:35 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-17 16:47:59 -0400 |
commit | 51ef847df74632e7cfdf952afc3887de105b8b35 (patch) | |
tree | f74ce1e5e5dcafeb7a93eb5706264aa519c0a05f /drivers/usb/serial/ti_usb_3410_5052.c | |
parent | 289b076f89c2c3260e914dad18ae12f193ea86d5 (diff) |
USB: ti_usb_3410_5052: fix port-data memory leak
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.
Cc: <stable@vger.kernel.org>
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/serial/ti_usb_3410_5052.c')
-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 6f49392cda5b..f2530d2ef3c4 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c | |||
@@ -97,6 +97,8 @@ struct ti_device { | |||
97 | 97 | ||
98 | static int ti_startup(struct usb_serial *serial); | 98 | static int ti_startup(struct usb_serial *serial); |
99 | static void ti_release(struct usb_serial *serial); | 99 | static void ti_release(struct usb_serial *serial); |
100 | static int ti_port_probe(struct usb_serial_port *port); | ||
101 | static int ti_port_remove(struct usb_serial_port *port); | ||
100 | static int ti_open(struct tty_struct *tty, struct usb_serial_port *port); | 102 | static int ti_open(struct tty_struct *tty, struct usb_serial_port *port); |
101 | static void ti_close(struct usb_serial_port *port); | 103 | static void ti_close(struct usb_serial_port *port); |
102 | static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, | 104 | static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, |
@@ -221,6 +223,8 @@ static struct usb_serial_driver ti_1port_device = { | |||
221 | .num_ports = 1, | 223 | .num_ports = 1, |
222 | .attach = ti_startup, | 224 | .attach = ti_startup, |
223 | .release = ti_release, | 225 | .release = ti_release, |
226 | .port_probe = ti_port_probe, | ||
227 | .port_remove = ti_port_remove, | ||
224 | .open = ti_open, | 228 | .open = ti_open, |
225 | .close = ti_close, | 229 | .close = ti_close, |
226 | .write = ti_write, | 230 | .write = ti_write, |
@@ -249,6 +253,8 @@ static struct usb_serial_driver ti_2port_device = { | |||
249 | .num_ports = 2, | 253 | .num_ports = 2, |
250 | .attach = ti_startup, | 254 | .attach = ti_startup, |
251 | .release = ti_release, | 255 | .release = ti_release, |
256 | .port_probe = ti_port_probe, | ||
257 | .port_remove = ti_port_remove, | ||
252 | .open = ti_open, | 258 | .open = ti_open, |
253 | .close = ti_close, | 259 | .close = ti_close, |
254 | .write = ti_write, | 260 | .write = ti_write, |
@@ -347,11 +353,8 @@ module_exit(ti_exit); | |||
347 | static int ti_startup(struct usb_serial *serial) | 353 | static int ti_startup(struct usb_serial *serial) |
348 | { | 354 | { |
349 | struct ti_device *tdev; | 355 | struct ti_device *tdev; |
350 | struct ti_port *tport; | ||
351 | struct usb_device *dev = serial->dev; | 356 | struct usb_device *dev = serial->dev; |
352 | int status; | 357 | int status; |
353 | int i; | ||
354 | |||
355 | 358 | ||
356 | dev_dbg(&dev->dev, | 359 | dev_dbg(&dev->dev, |
357 | "%s - product 0x%4X, num configurations %d, configuration value %d", | 360 | "%s - product 0x%4X, num configurations %d, configuration value %d", |
@@ -399,42 +402,8 @@ static int ti_startup(struct usb_serial *serial) | |||
399 | goto free_tdev; | 402 | goto free_tdev; |
400 | } | 403 | } |
401 | 404 | ||
402 | /* set up port structures */ | ||
403 | for (i = 0; i < serial->num_ports; ++i) { | ||
404 | tport = kzalloc(sizeof(struct ti_port), GFP_KERNEL); | ||
405 | if (tport == NULL) { | ||
406 | dev_err(&dev->dev, "%s - out of memory\n", __func__); | ||
407 | status = -ENOMEM; | ||
408 | goto free_tports; | ||
409 | } | ||
410 | spin_lock_init(&tport->tp_lock); | ||
411 | tport->tp_uart_base_addr = (i == 0 ? | ||
412 | TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR); | ||
413 | tport->tp_closing_wait = closing_wait; | ||
414 | init_waitqueue_head(&tport->tp_msr_wait); | ||
415 | init_waitqueue_head(&tport->tp_write_wait); | ||
416 | if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, | ||
417 | GFP_KERNEL)) { | ||
418 | dev_err(&dev->dev, "%s - out of memory\n", __func__); | ||
419 | kfree(tport); | ||
420 | status = -ENOMEM; | ||
421 | goto free_tports; | ||
422 | } | ||
423 | tport->tp_port = serial->port[i]; | ||
424 | tport->tp_tdev = tdev; | ||
425 | usb_set_serial_port_data(serial->port[i], tport); | ||
426 | tport->tp_uart_mode = 0; /* default is RS232 */ | ||
427 | } | ||
428 | |||
429 | return 0; | 405 | return 0; |
430 | 406 | ||
431 | free_tports: | ||
432 | for (--i; i >= 0; --i) { | ||
433 | tport = usb_get_serial_port_data(serial->port[i]); | ||
434 | kfifo_free(&tport->write_fifo); | ||
435 | kfree(tport); | ||
436 | usb_set_serial_port_data(serial->port[i], NULL); | ||
437 | } | ||
438 | free_tdev: | 407 | free_tdev: |
439 | kfree(tdev); | 408 | kfree(tdev); |
440 | usb_set_serial_data(serial, NULL); | 409 | usb_set_serial_data(serial, NULL); |
@@ -444,21 +413,50 @@ free_tdev: | |||
444 | 413 | ||
445 | static void ti_release(struct usb_serial *serial) | 414 | static void ti_release(struct usb_serial *serial) |
446 | { | 415 | { |
447 | int i; | ||
448 | struct ti_device *tdev = usb_get_serial_data(serial); | 416 | struct ti_device *tdev = usb_get_serial_data(serial); |
417 | |||
418 | kfree(tdev); | ||
419 | } | ||
420 | |||
421 | static int ti_port_probe(struct usb_serial_port *port) | ||
422 | { | ||
449 | struct ti_port *tport; | 423 | struct ti_port *tport; |
450 | 424 | ||
451 | for (i = 0; i < serial->num_ports; ++i) { | 425 | tport = kzalloc(sizeof(*tport), GFP_KERNEL); |
452 | tport = usb_get_serial_port_data(serial->port[i]); | 426 | if (!tport) |
453 | if (tport) { | 427 | return -ENOMEM; |
454 | kfifo_free(&tport->write_fifo); | 428 | |
455 | kfree(tport); | 429 | spin_lock_init(&tport->tp_lock); |
456 | } | 430 | if (port == port->serial->port[0]) |
431 | tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; | ||
432 | else | ||
433 | tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; | ||
434 | tport->tp_closing_wait = closing_wait; | ||
435 | init_waitqueue_head(&tport->tp_msr_wait); | ||
436 | init_waitqueue_head(&tport->tp_write_wait); | ||
437 | if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) { | ||
438 | kfree(tport); | ||
439 | return -ENOMEM; | ||
457 | } | 440 | } |
441 | tport->tp_port = port; | ||
442 | tport->tp_tdev = usb_get_serial_data(port->serial); | ||
443 | tport->tp_uart_mode = 0; /* default is RS232 */ | ||
458 | 444 | ||
459 | kfree(tdev); | 445 | usb_set_serial_port_data(port, tport); |
446 | |||
447 | return 0; | ||
460 | } | 448 | } |
461 | 449 | ||
450 | static int ti_port_remove(struct usb_serial_port *port) | ||
451 | { | ||
452 | struct ti_port *tport; | ||
453 | |||
454 | tport = usb_get_serial_port_data(port); | ||
455 | kfifo_free(&tport->write_fifo); | ||
456 | kfree(tport); | ||
457 | |||
458 | return 0; | ||
459 | } | ||
462 | 460 | ||
463 | static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) | 461 | static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) |
464 | { | 462 | { |