aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2012-10-25 04:29:02 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-25 12:36:57 -0400
commitc467206ed6bcce26c83d0435612cc4fee2527305 (patch)
tree80275e6791a2d2990c7380cad4a69569beb82f34
parentc129197c99550d356cf5f69b046994dd53cd1b9d (diff)
USB: whiteheat: 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. Note that the fifth port (command port) is never registered as a port device and thus should be handled in attach and release. Compile-only tested. Cc: <support@connecttech.com> Cc: <stable@vger.kernel.org> Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/serial/whiteheat.c59
1 files changed, 26 insertions, 33 deletions
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index cfd155e2b6a2..b9fca3586d74 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -83,6 +83,8 @@ static int whiteheat_firmware_attach(struct usb_serial *serial);
83/* function prototypes for the Connect Tech WhiteHEAT serial converter */ 83/* function prototypes for the Connect Tech WhiteHEAT serial converter */
84static int whiteheat_attach(struct usb_serial *serial); 84static int whiteheat_attach(struct usb_serial *serial);
85static void whiteheat_release(struct usb_serial *serial); 85static void whiteheat_release(struct usb_serial *serial);
86static int whiteheat_port_probe(struct usb_serial_port *port);
87static int whiteheat_port_remove(struct usb_serial_port *port);
86static int whiteheat_open(struct tty_struct *tty, 88static int whiteheat_open(struct tty_struct *tty,
87 struct usb_serial_port *port); 89 struct usb_serial_port *port);
88static void whiteheat_close(struct usb_serial_port *port); 90static void whiteheat_close(struct usb_serial_port *port);
@@ -117,6 +119,8 @@ static struct usb_serial_driver whiteheat_device = {
117 .num_ports = 4, 119 .num_ports = 4,
118 .attach = whiteheat_attach, 120 .attach = whiteheat_attach,
119 .release = whiteheat_release, 121 .release = whiteheat_release,
122 .port_probe = whiteheat_port_probe,
123 .port_remove = whiteheat_port_remove,
120 .open = whiteheat_open, 124 .open = whiteheat_open,
121 .close = whiteheat_close, 125 .close = whiteheat_close,
122 .ioctl = whiteheat_ioctl, 126 .ioctl = whiteheat_ioctl,
@@ -218,15 +222,12 @@ static int whiteheat_attach(struct usb_serial *serial)
218{ 222{
219 struct usb_serial_port *command_port; 223 struct usb_serial_port *command_port;
220 struct whiteheat_command_private *command_info; 224 struct whiteheat_command_private *command_info;
221 struct usb_serial_port *port;
222 struct whiteheat_private *info;
223 struct whiteheat_hw_info *hw_info; 225 struct whiteheat_hw_info *hw_info;
224 int pipe; 226 int pipe;
225 int ret; 227 int ret;
226 int alen; 228 int alen;
227 __u8 *command; 229 __u8 *command;
228 __u8 *result; 230 __u8 *result;
229 int i;
230 231
231 command_port = serial->port[COMMAND_PORT]; 232 command_port = serial->port[COMMAND_PORT];
232 233
@@ -285,22 +286,6 @@ static int whiteheat_attach(struct usb_serial *serial)
285 serial->type->description, 286 serial->type->description,
286 hw_info->sw_major_rev, hw_info->sw_minor_rev); 287 hw_info->sw_major_rev, hw_info->sw_minor_rev);
287 288
288 for (i = 0; i < serial->num_ports; i++) {
289 port = serial->port[i];
290
291 info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
292 if (info == NULL) {
293 dev_err(&port->dev,
294 "%s: Out of memory for port structures\n",
295 serial->type->description);
296 goto no_private;
297 }
298
299 info->mcr = 0;
300
301 usb_set_serial_port_data(port, info);
302 }
303
304 command_info = kmalloc(sizeof(struct whiteheat_command_private), 289 command_info = kmalloc(sizeof(struct whiteheat_command_private),
305 GFP_KERNEL); 290 GFP_KERNEL);
306 if (command_info == NULL) { 291 if (command_info == NULL) {
@@ -337,13 +322,6 @@ no_firmware:
337 return -ENODEV; 322 return -ENODEV;
338 323
339no_command_private: 324no_command_private:
340 for (i = serial->num_ports - 1; i >= 0; i--) {
341 port = serial->port[i];
342 info = usb_get_serial_port_data(port);
343 kfree(info);
344no_private:
345 ;
346 }
347 kfree(result); 325 kfree(result);
348no_result_buffer: 326no_result_buffer:
349 kfree(command); 327 kfree(command);
@@ -351,21 +329,36 @@ no_command_buffer:
351 return -ENOMEM; 329 return -ENOMEM;
352} 330}
353 331
354
355static void whiteheat_release(struct usb_serial *serial) 332static void whiteheat_release(struct usb_serial *serial)
356{ 333{
357 struct usb_serial_port *command_port; 334 struct usb_serial_port *command_port;
358 struct whiteheat_private *info;
359 int i;
360 335
361 /* free up our private data for our command port */ 336 /* free up our private data for our command port */
362 command_port = serial->port[COMMAND_PORT]; 337 command_port = serial->port[COMMAND_PORT];
363 kfree(usb_get_serial_port_data(command_port)); 338 kfree(usb_get_serial_port_data(command_port));
339}
364 340
365 for (i = 0; i < serial->num_ports; i++) { 341static int whiteheat_port_probe(struct usb_serial_port *port)
366 info = usb_get_serial_port_data(serial->port[i]); 342{
367 kfree(info); 343 struct whiteheat_private *info;
368 } 344
345 info = kzalloc(sizeof(*info), GFP_KERNEL);
346 if (!info)
347 return -ENOMEM;
348
349 usb_set_serial_port_data(port, info);
350
351 return 0;
352}
353
354static int whiteheat_port_remove(struct usb_serial_port *port)
355{
356 struct whiteheat_private *info;
357
358 info = usb_get_serial_port_data(port);
359 kfree(info);
360
361 return 0;
369} 362}
370 363
371static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) 364static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)