Browse Source

USB: fix race in visor_write

this fixes a small race in visor_write.


Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Oliver Neukum 18 years ago
parent
commit
b80349b17c
1 changed files with 16 additions and 6 deletions
  1. 16 6
      drivers/usb/serial/visor.c

+ 16 - 6
drivers/usb/serial/visor.c

@@ -384,19 +384,21 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
 		dbg("%s - write limit hit\n", __FUNCTION__);
 		dbg("%s - write limit hit\n", __FUNCTION__);
 		return 0;
 		return 0;
 	}
 	}
+	priv->outstanding_urbs++;
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 
 	buffer = kmalloc (count, GFP_ATOMIC);
 	buffer = kmalloc (count, GFP_ATOMIC);
 	if (!buffer) {
 	if (!buffer) {
 		dev_err(&port->dev, "out of memory\n");
 		dev_err(&port->dev, "out of memory\n");
-		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) {
 		dev_err(&port->dev, "no more free urbs\n");
 		dev_err(&port->dev, "no more free urbs\n");
-		kfree (buffer);
-		return -ENOMEM;
+		count = -ENOMEM;
+		goto error_no_urb;
 	}
 	}
 
 
 	memcpy (buffer, buf, count);
 	memcpy (buffer, buf, count);
@@ -415,18 +417,26 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
 		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
 		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
 			__FUNCTION__, status);
 			__FUNCTION__, status);
 		count = status;
 		count = status;
-		kfree (buffer);
+		goto error;
 	} else {
 	} else {
 		spin_lock_irqsave(&priv->lock, flags);
 		spin_lock_irqsave(&priv->lock, flags);
-		++priv->outstanding_urbs;
 		priv->bytes_out += count;
 		priv->bytes_out += count;
 		spin_unlock_irqrestore(&priv->lock, flags);
 		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 	}
 
 
 	/* 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);
 
 
+	return count;
+error:
+	usb_free_urb(urb);
+error_no_urb:
+	kfree(buffer);
+error_no_buffer:
+	spin_lock_irqsave(&priv->lock, flags);
+	--priv->outstanding_urbs;
+	spin_unlock_irqrestore(&priv->lock, flags);
 	return count;
 	return count;
 }
 }