aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2012-10-25 04:28:59 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-25 12:36:57 -0400
commit50dde8686eec41bf3d7cbec7a6f76c073ab01903 (patch)
tree6353829484f34cc1269d55e57ab32eb002ead831 /drivers/usb
parentd7870af7e2e3a91b462075ec1ca669b482215187 (diff)
USB: metro-usb: 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 call to metrousb_clean (close) in shutdown was redundant. 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')
-rw-r--r--drivers/usb/serial/metro-usb.c50
1 files changed, 13 insertions, 37 deletions
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 0b257ddffbdb..25cb97c25ad4 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -271,51 +271,27 @@ static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int contr
271 return retval; 271 return retval;
272} 272}
273 273
274static void metrousb_shutdown(struct usb_serial *serial) 274static int metrousb_port_probe(struct usb_serial_port *port)
275{ 275{
276 int i = 0; 276 struct metrousb_private *metro_priv;
277 277
278 dev_dbg(&serial->dev->dev, "%s\n", __func__); 278 metro_priv = kzalloc(sizeof(*metro_priv), GFP_KERNEL);
279 if (!metro_priv)
280 return -ENOMEM;
279 281
280 /* Stop reading and writing on all ports. */ 282 spin_lock_init(&metro_priv->lock);
281 for (i = 0; i < serial->num_ports; ++i) {
282 /* Close any open urbs. */
283 metrousb_cleanup(serial->port[i]);
284 283
285 /* Free memory. */ 284 usb_set_serial_port_data(port, metro_priv);
286 kfree(usb_get_serial_port_data(serial->port[i]));
287 usb_set_serial_port_data(serial->port[i], NULL);
288 285
289 dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n", 286 return 0;
290 __func__, serial->port[i]->number);
291 }
292} 287}
293 288
294static int metrousb_startup(struct usb_serial *serial) 289static int metrousb_port_remove(struct usb_serial_port *port)
295{ 290{
296 struct metrousb_private *metro_priv; 291 struct metrousb_private *metro_priv;
297 struct usb_serial_port *port;
298 int i = 0;
299
300 dev_dbg(&serial->dev->dev, "%s\n", __func__);
301 292
302 /* Loop through the serial ports setting up the private structures. 293 metro_priv = usb_get_serial_port_data(port);
303 * Currently we only use one port. */ 294 kfree(metro_priv);
304 for (i = 0; i < serial->num_ports; ++i) {
305 port = serial->port[i];
306
307 /* Declare memory. */
308 metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL);
309 if (!metro_priv)
310 return -ENOMEM;
311
312 /* Initialize memory. */
313 spin_lock_init(&metro_priv->lock);
314 usb_set_serial_port_data(port, metro_priv);
315
316 dev_dbg(&serial->dev->dev, "%s - port number=%d\n ",
317 __func__, port->number);
318 }
319 295
320 return 0; 296 return 0;
321} 297}
@@ -414,8 +390,8 @@ static struct usb_serial_driver metrousb_device = {
414 .close = metrousb_cleanup, 390 .close = metrousb_cleanup,
415 .read_int_callback = metrousb_read_int_callback, 391 .read_int_callback = metrousb_read_int_callback,
416 .write_int_callback = metrousb_write_int_callback, 392 .write_int_callback = metrousb_write_int_callback,
417 .attach = metrousb_startup, 393 .port_probe = metrousb_port_probe,
418 .release = metrousb_shutdown, 394 .port_remove = metrousb_port_remove,
419 .throttle = metrousb_throttle, 395 .throttle = metrousb_throttle,
420 .unthrottle = metrousb_unthrottle, 396 .unthrottle = metrousb_unthrottle,
421 .tiocmget = metrousb_tiocmget, 397 .tiocmget = metrousb_tiocmget,