Commit 62127a58 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

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: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b80349b1
...@@ -1433,6 +1433,7 @@ static int ftdi_write (struct usb_serial_port *port, ...@@ -1433,6 +1433,7 @@ static int ftdi_write (struct usb_serial_port *port,
dbg("%s - write limit hit\n", __FUNCTION__); dbg("%s - write limit hit\n", __FUNCTION__);
return 0; return 0;
} }
priv->tx_outstanding_urbs++;
spin_unlock_irqrestore(&priv->tx_lock, flags); spin_unlock_irqrestore(&priv->tx_lock, flags);
data_offset = priv->write_offset; data_offset = priv->write_offset;
...@@ -1450,14 +1451,15 @@ static int ftdi_write (struct usb_serial_port *port, ...@@ -1450,14 +1451,15 @@ static int ftdi_write (struct usb_serial_port *port,
buffer = kmalloc (transfer_size, GFP_ATOMIC); buffer = kmalloc (transfer_size, GFP_ATOMIC);
if (!buffer) { if (!buffer) {
err("%s ran out of kernel memory for urb ...", __FUNCTION__); err("%s ran out of kernel memory for urb ...", __FUNCTION__);
return -ENOMEM; count = -ENOMEM;
goto error_no_buffer;
} }
urb = usb_alloc_urb(0, GFP_ATOMIC); urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) { if (!urb) {
err("%s - no more free urbs", __FUNCTION__); err("%s - no more free urbs", __FUNCTION__);
kfree (buffer); count = -ENOMEM;
return -ENOMEM; goto error_no_urb;
} }
/* Copy data */ /* Copy data */
...@@ -1499,10 +1501,9 @@ static int ftdi_write (struct usb_serial_port *port, ...@@ -1499,10 +1501,9 @@ static int ftdi_write (struct usb_serial_port *port,
if (status) { if (status) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, status); err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
count = status; count = status;
kfree (buffer); goto error;
} else { } else {
spin_lock_irqsave(&priv->tx_lock, flags); spin_lock_irqsave(&priv->tx_lock, flags);
++priv->tx_outstanding_urbs;
priv->tx_outstanding_bytes += count; priv->tx_outstanding_bytes += count;
priv->tx_bytes += count; priv->tx_bytes += count;
spin_unlock_irqrestore(&priv->tx_lock, flags); spin_unlock_irqrestore(&priv->tx_lock, flags);
...@@ -1510,10 +1511,19 @@ static int ftdi_write (struct usb_serial_port *port, ...@@ -1510,10 +1511,19 @@ static int ftdi_write (struct usb_serial_port *port,
/* we are done with this urb, so let the host driver /* we are done with this urb, so let the host driver
* really free it when it is finished with it */ * really free it when it is finished with it */
usb_free_urb (urb); usb_free_urb(urb);
dbg("%s write returning: %d", __FUNCTION__, count); dbg("%s write returning: %d", __FUNCTION__, count);
return count; return count;
error:
usb_free_urb(urb);
error_no_urb:
kfree (buffer);
error_no_buffer:
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_outstanding_urbs--;
spin_unlock_irqrestore(&priv->tx_lock, flags);
return count;
} /* ftdi_write */ } /* ftdi_write */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment