aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2012-10-25 04:29:04 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-25 12:36:57 -0400
commitfb44ff854e148bc5c5982dad32da98b7a0989d2d (patch)
treead1fe909a554251bb80c8631e95039adbb95d117 /drivers/usb
parent456c5be56ed070a4d883c60b587bcc1c97a8cf3e (diff)
USB: digi_acceleport: 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 oob port is never registered as a port device and should thus be handled in attach and release. Compile-only tested. Cc: Peter Berger <pberger@brimson.com> Cc: Al Borchers <alborchers@steinerpoint.com> 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/digi_acceleport.c117
1 files changed, 67 insertions, 50 deletions
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index c86f68c6b078..b50fa1c6d885 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -244,6 +244,8 @@ static int digi_startup_device(struct usb_serial *serial);
244static int digi_startup(struct usb_serial *serial); 244static int digi_startup(struct usb_serial *serial);
245static void digi_disconnect(struct usb_serial *serial); 245static void digi_disconnect(struct usb_serial *serial);
246static void digi_release(struct usb_serial *serial); 246static void digi_release(struct usb_serial *serial);
247static int digi_port_probe(struct usb_serial_port *port);
248static int digi_port_remove(struct usb_serial_port *port);
247static void digi_read_bulk_callback(struct urb *urb); 249static void digi_read_bulk_callback(struct urb *urb);
248static int digi_read_inb_callback(struct urb *urb); 250static int digi_read_inb_callback(struct urb *urb);
249static int digi_read_oob_callback(struct urb *urb); 251static int digi_read_oob_callback(struct urb *urb);
@@ -294,6 +296,8 @@ static struct usb_serial_driver digi_acceleport_2_device = {
294 .attach = digi_startup, 296 .attach = digi_startup,
295 .disconnect = digi_disconnect, 297 .disconnect = digi_disconnect,
296 .release = digi_release, 298 .release = digi_release,
299 .port_probe = digi_port_probe,
300 .port_remove = digi_port_remove,
297}; 301};
298 302
299static struct usb_serial_driver digi_acceleport_4_device = { 303static struct usb_serial_driver digi_acceleport_4_device = {
@@ -320,6 +324,8 @@ static struct usb_serial_driver digi_acceleport_4_device = {
320 .attach = digi_startup, 324 .attach = digi_startup,
321 .disconnect = digi_disconnect, 325 .disconnect = digi_disconnect,
322 .release = digi_release, 326 .release = digi_release,
327 .port_probe = digi_port_probe,
328 .port_remove = digi_port_remove,
323}; 329};
324 330
325static struct usb_serial_driver * const serial_drivers[] = { 331static struct usb_serial_driver * const serial_drivers[] = {
@@ -1240,59 +1246,50 @@ static int digi_startup_device(struct usb_serial *serial)
1240 return ret; 1246 return ret;
1241} 1247}
1242 1248
1243 1249static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
1244static int digi_startup(struct usb_serial *serial)
1245{ 1250{
1246
1247 int i;
1248 struct digi_port *priv; 1251 struct digi_port *priv;
1249 struct digi_serial *serial_priv;
1250 1252
1251 /* allocate the private data structures for all ports */ 1253 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1252 /* number of regular ports + 1 for the out-of-band port */ 1254 if (!priv)
1253 for (i = 0; i < serial->type->num_ports + 1; i++) { 1255 return -ENOMEM;
1254 /* allocate port private structure */
1255 priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL);
1256 if (priv == NULL) {
1257 while (--i >= 0)
1258 kfree(usb_get_serial_port_data(serial->port[i]));
1259 return 1; /* error */
1260 }
1261 1256
1262 /* initialize port private structure */ 1257 spin_lock_init(&priv->dp_port_lock);
1263 spin_lock_init(&priv->dp_port_lock); 1258 priv->dp_port_num = port_num;
1264 priv->dp_port_num = i; 1259 init_waitqueue_head(&priv->dp_modem_change_wait);
1265 priv->dp_out_buf_len = 0; 1260 init_waitqueue_head(&priv->dp_transmit_idle_wait);
1266 priv->dp_write_urb_in_use = 0; 1261 init_waitqueue_head(&priv->dp_flush_wait);
1267 priv->dp_modem_signals = 0; 1262 init_waitqueue_head(&priv->dp_close_wait);
1268 init_waitqueue_head(&priv->dp_modem_change_wait); 1263 INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
1269 priv->dp_transmit_idle = 0; 1264 priv->dp_port = port;
1270 init_waitqueue_head(&priv->dp_transmit_idle_wait);
1271 priv->dp_throttled = 0;
1272 priv->dp_throttle_restart = 0;
1273 init_waitqueue_head(&priv->dp_flush_wait);
1274 init_waitqueue_head(&priv->dp_close_wait);
1275 INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
1276 priv->dp_port = serial->port[i];
1277 /* initialize write wait queue for this port */
1278 init_waitqueue_head(&serial->port[i]->write_wait);
1279
1280 usb_set_serial_port_data(serial->port[i], priv);
1281 }
1282 1265
1283 /* allocate serial private structure */ 1266 init_waitqueue_head(&port->write_wait);
1284 serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL); 1267
1285 if (serial_priv == NULL) { 1268 usb_set_serial_port_data(port, priv);
1286 for (i = 0; i < serial->type->num_ports + 1; i++) 1269
1287 kfree(usb_get_serial_port_data(serial->port[i])); 1270 return 0;
1288 return 1; /* error */ 1271}
1289 } 1272
1273static int digi_startup(struct usb_serial *serial)
1274{
1275 struct digi_serial *serial_priv;
1276 int ret;
1277
1278 serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
1279 if (!serial_priv)
1280 return -ENOMEM;
1290 1281
1291 /* initialize serial private structure */
1292 spin_lock_init(&serial_priv->ds_serial_lock); 1282 spin_lock_init(&serial_priv->ds_serial_lock);
1293 serial_priv->ds_oob_port_num = serial->type->num_ports; 1283 serial_priv->ds_oob_port_num = serial->type->num_ports;
1294 serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num]; 1284 serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num];
1295 serial_priv->ds_device_started = 0; 1285
1286 ret = digi_port_init(serial_priv->ds_oob_port,
1287 serial_priv->ds_oob_port_num);
1288 if (ret) {
1289 kfree(serial_priv);
1290 return ret;
1291 }
1292
1296 usb_set_serial_data(serial, serial_priv); 1293 usb_set_serial_data(serial, serial_priv);
1297 1294
1298 return 0; 1295 return 0;
@@ -1313,15 +1310,35 @@ static void digi_disconnect(struct usb_serial *serial)
1313 1310
1314static void digi_release(struct usb_serial *serial) 1311static void digi_release(struct usb_serial *serial)
1315{ 1312{
1316 int i; 1313 struct digi_serial *serial_priv;
1314 struct digi_port *priv;
1315
1316 serial_priv = usb_get_serial_data(serial);
1317
1318 priv = usb_get_serial_port_data(serial_priv->ds_oob_port);
1319 kfree(priv);
1317 1320
1318 /* free the private data structures for all ports */ 1321 kfree(serial_priv);
1319 /* number of regular ports + 1 for the out-of-band port */
1320 for (i = 0; i < serial->type->num_ports + 1; i++)
1321 kfree(usb_get_serial_port_data(serial->port[i]));
1322 kfree(usb_get_serial_data(serial));
1323} 1322}
1324 1323
1324static int digi_port_probe(struct usb_serial_port *port)
1325{
1326 unsigned port_num;
1327
1328 port_num = port->number - port->serial->minor;
1329
1330 return digi_port_init(port, port_num);
1331}
1332
1333static int digi_port_remove(struct usb_serial_port *port)
1334{
1335 struct digi_port *priv;
1336
1337 priv = usb_get_serial_port_data(port);
1338 kfree(priv);
1339
1340 return 0;
1341}
1325 1342
1326static void digi_read_bulk_callback(struct urb *urb) 1343static void digi_read_bulk_callback(struct urb *urb)
1327{ 1344{