aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/ftdi_sio.c
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2007-03-23 09:30:16 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 16:28:38 -0400
commit62127a585cc72509a0bfae502cc16f9935a4cda6 (patch)
tree96515ced9943c82c36103cf2e48d859cb4c237e6 /drivers/usb/serial/ftdi_sio.c
parentb80349b17c6e1236a24616f71e59ed31279de25a (diff)
USB: fix race in ftdio_write
this has the same race as the visor driver. The counter must be incremented under the lock it is checked under. Signed-off-by: Oliver Neukum <oneukum@suse.de> 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.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 8ff9d54b21e6..8fb8e2f64545 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1433,6 +1433,7 @@ static int ftdi_write (struct usb_serial_port *port,
1433 dbg("%s - write limit hit\n", __FUNCTION__); 1433 dbg("%s - write limit hit\n", __FUNCTION__);
1434 return 0; 1434 return 0;
1435 } 1435 }
1436 priv->tx_outstanding_urbs++;
1436 spin_unlock_irqrestore(&priv->tx_lock, flags); 1437 spin_unlock_irqrestore(&priv->tx_lock, flags);
1437 1438
1438 data_offset = priv->write_offset; 1439 data_offset = priv->write_offset;
@@ -1450,14 +1451,15 @@ static int ftdi_write (struct usb_serial_port *port,
1450 buffer = kmalloc (transfer_size, GFP_ATOMIC); 1451 buffer = kmalloc (transfer_size, GFP_ATOMIC);
1451 if (!buffer) { 1452 if (!buffer) {
1452 err("%s ran out of kernel memory for urb ...", __FUNCTION__); 1453 err("%s ran out of kernel memory for urb ...", __FUNCTION__);
1453 return -ENOMEM; 1454 count = -ENOMEM;
1455 goto error_no_buffer;
1454 } 1456 }
1455 1457
1456 urb = usb_alloc_urb(0, GFP_ATOMIC); 1458 urb = usb_alloc_urb(0, GFP_ATOMIC);
1457 if (!urb) { 1459 if (!urb) {
1458 err("%s - no more free urbs", __FUNCTION__); 1460 err("%s - no more free urbs", __FUNCTION__);
1459 kfree (buffer); 1461 count = -ENOMEM;
1460 return -ENOMEM; 1462 goto error_no_urb;
1461 } 1463 }
1462 1464
1463 /* Copy data */ 1465 /* Copy data */
@@ -1499,10 +1501,9 @@ static int ftdi_write (struct usb_serial_port *port,
1499 if (status) { 1501 if (status) {
1500 err("%s - failed submitting write urb, error %d", __FUNCTION__, status); 1502 err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
1501 count = status; 1503 count = status;
1502 kfree (buffer); 1504 goto error;
1503 } else { 1505 } else {
1504 spin_lock_irqsave(&priv->tx_lock, flags); 1506 spin_lock_irqsave(&priv->tx_lock, flags);
1505 ++priv->tx_outstanding_urbs;
1506 priv->tx_outstanding_bytes += count; 1507 priv->tx_outstanding_bytes += count;
1507 priv->tx_bytes += count; 1508 priv->tx_bytes += count;
1508 spin_unlock_irqrestore(&priv->tx_lock, flags); 1509 spin_unlock_irqrestore(&priv->tx_lock, flags);
@@ -1510,10 +1511,19 @@ static int ftdi_write (struct usb_serial_port *port,
1510 1511
1511 /* we are done with this urb, so let the host driver 1512 /* we are done with this urb, so let the host driver
1512 * really free it when it is finished with it */ 1513 * really free it when it is finished with it */
1513 usb_free_urb (urb); 1514 usb_free_urb(urb);
1514 1515
1515 dbg("%s write returning: %d", __FUNCTION__, count); 1516 dbg("%s write returning: %d", __FUNCTION__, count);
1516 return count; 1517 return count;
1518error:
1519 usb_free_urb(urb);
1520error_no_urb:
1521 kfree (buffer);
1522error_no_buffer:
1523 spin_lock_irqsave(&priv->tx_lock, flags);
1524 priv->tx_outstanding_urbs--;
1525 spin_unlock_irqrestore(&priv->tx_lock, flags);
1526 return count;
1517} /* ftdi_write */ 1527} /* ftdi_write */
1518 1528
1519 1529