aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/ftdi_sio.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-04-30 10:06:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-05-08 22:34:57 -0400
commitc45d63202fbaccef7ef7946c03f27f72c809b1cc (patch)
treef9dd1d104167b9443a6d7c7a5f1f693052023675 /drivers/usb/serial/ftdi_sio.c
parent031defd11ee11753110098603236a4257b2cc03d (diff)
usb-serial: ftdi_sio: fix reference counting of ftdi_private
This patch (as1238) adds proper reference counting for ftdi_sio's private data structure. Without it, the driver will free the structure while it is still in use if the user unplugs the serial device before closing the device file. The patch also replaces a slightly dangerous cancel_delayed_work/flush_scheduled_work pair with cancel_delayed_work_sync, which is always safer. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Daniel Mack <daniel@caiaq.de> Tested-by: Daniel Mack <daniel@caiaq.de> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r--drivers/usb/serial/ftdi_sio.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index aab567644b99..0ab8474b00cb 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -56,6 +56,7 @@ static __u16 vendor = FTDI_VID;
56static __u16 product; 56static __u16 product;
57 57
58struct ftdi_private { 58struct ftdi_private {
59 struct kref kref;
59 ftdi_chip_type_t chip_type; 60 ftdi_chip_type_t chip_type;
60 /* type of device, either SIO or FT8U232AM */ 61 /* type of device, either SIO or FT8U232AM */
61 int baud_base; /* baud base clock for divisor setting */ 62 int baud_base; /* baud base clock for divisor setting */
@@ -1354,6 +1355,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
1354 return -ENOMEM; 1355 return -ENOMEM;
1355 } 1356 }
1356 1357
1358 kref_init(&priv->kref);
1357 spin_lock_init(&priv->rx_lock); 1359 spin_lock_init(&priv->rx_lock);
1358 spin_lock_init(&priv->tx_lock); 1360 spin_lock_init(&priv->tx_lock);
1359 init_waitqueue_head(&priv->delta_msr_wait); 1361 init_waitqueue_head(&priv->delta_msr_wait);
@@ -1470,6 +1472,13 @@ static void ftdi_shutdown(struct usb_serial *serial)
1470 dbg("%s", __func__); 1472 dbg("%s", __func__);
1471} 1473}
1472 1474
1475static void ftdi_sio_priv_release(struct kref *k)
1476{
1477 struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
1478
1479 kfree(priv);
1480}
1481
1473static int ftdi_sio_port_remove(struct usb_serial_port *port) 1482static int ftdi_sio_port_remove(struct usb_serial_port *port)
1474{ 1483{
1475 struct ftdi_private *priv = usb_get_serial_port_data(port); 1484 struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1484,7 +1493,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
1484 1493
1485 if (priv) { 1494 if (priv) {
1486 usb_set_serial_port_data(port, NULL); 1495 usb_set_serial_port_data(port, NULL);
1487 kfree(priv); 1496 kref_put(&priv->kref, ftdi_sio_priv_release);
1488 } 1497 }
1489 1498
1490 return 0; 1499 return 0;
@@ -1549,7 +1558,8 @@ static int ftdi_open(struct tty_struct *tty,
1549 dev_err(&port->dev, 1558 dev_err(&port->dev,
1550 "%s - failed submitting read urb, error %d\n", 1559 "%s - failed submitting read urb, error %d\n",
1551 __func__, result); 1560 __func__, result);
1552 1561 else
1562 kref_get(&priv->kref);
1553 1563
1554 return result; 1564 return result;
1555} /* ftdi_open */ 1565} /* ftdi_open */
@@ -1591,11 +1601,11 @@ static void ftdi_close(struct tty_struct *tty,
1591 mutex_unlock(&port->serial->disc_mutex); 1601 mutex_unlock(&port->serial->disc_mutex);
1592 1602
1593 /* cancel any scheduled reading */ 1603 /* cancel any scheduled reading */
1594 cancel_delayed_work(&priv->rx_work); 1604 cancel_delayed_work_sync(&priv->rx_work);
1595 flush_scheduled_work();
1596 1605
1597 /* shutdown our bulk read */ 1606 /* shutdown our bulk read */
1598 usb_kill_urb(port->read_urb); 1607 usb_kill_urb(port->read_urb);
1608 kref_put(&priv->kref, ftdi_sio_priv_release);
1599} /* ftdi_close */ 1609} /* ftdi_close */
1600 1610
1601 1611