Commit 8d88259b authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

[PATCH] USB: fixed potential races in kl5kusb105.c now that there's no locks in the usb-serial core

parent 20e66b29
...@@ -166,7 +166,7 @@ struct klsi_105_private { ...@@ -166,7 +166,7 @@ struct klsi_105_private {
unsigned long line_state; /* modem line settings */ unsigned long line_state; /* modem line settings */
/* write pool */ /* write pool */
struct urb * write_urb_pool[NUM_URBS]; struct urb * write_urb_pool[NUM_URBS];
spinlock_t write_urb_pool_lock; spinlock_t lock;
unsigned long bytes_in; unsigned long bytes_in;
unsigned long bytes_out; unsigned long bytes_out;
}; };
...@@ -284,7 +284,7 @@ static int klsi_105_startup (struct usb_serial *serial) ...@@ -284,7 +284,7 @@ static int klsi_105_startup (struct usb_serial *serial)
priv->bytes_out = 0; priv->bytes_out = 0;
usb_set_serial_port_data(&serial->port[i], priv); usb_set_serial_port_data(&serial->port[i], priv);
spin_lock_init (&priv->write_urb_pool_lock); spin_lock_init (&priv->lock);
for (i=0; i<NUM_URBS; i++) { for (i=0; i<NUM_URBS; i++) {
struct urb* urb = usb_alloc_urb(0, GFP_KERNEL); struct urb* urb = usb_alloc_urb(0, GFP_KERNEL);
...@@ -326,7 +326,7 @@ static void klsi_105_shutdown (struct usb_serial *serial) ...@@ -326,7 +326,7 @@ static void klsi_105_shutdown (struct usb_serial *serial)
/* kill our write urb pool */ /* kill our write urb pool */
int j; int j;
struct urb **write_urbs = priv->write_urb_pool; struct urb **write_urbs = priv->write_urb_pool;
spin_lock_irqsave(&priv->write_urb_pool_lock,flags); spin_lock_irqsave(&priv->lock,flags);
for (j = 0; j < NUM_URBS; j++) { for (j = 0; j < NUM_URBS; j++) {
if (write_urbs[j]) { if (write_urbs[j]) {
...@@ -343,8 +343,7 @@ static void klsi_105_shutdown (struct usb_serial *serial) ...@@ -343,8 +343,7 @@ static void klsi_105_shutdown (struct usb_serial *serial)
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, spin_unlock_irqrestore (&priv->lock, flags);
flags);
kfree(priv); kfree(priv);
usb_set_serial_port_data(&serial->port[i], NULL); usb_set_serial_port_data(&serial->port[i], NULL);
...@@ -360,6 +359,8 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp) ...@@ -360,6 +359,8 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
int rc; int rc;
int i; int i;
unsigned long line_state; unsigned long line_state;
struct klsi_105_port_settings cfg;
unsigned long flags;
dbg("%s port %d", __FUNCTION__, port->number); dbg("%s port %d", __FUNCTION__, port->number);
...@@ -374,21 +375,27 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp) ...@@ -374,21 +375,27 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
* Then read the modem line control and store values in * Then read the modem line control and store values in
* priv->line_state. * priv->line_state.
*/ */
priv->cfg.pktlen = 5; cfg.pktlen = 5;
priv->cfg.baudrate = kl5kusb105a_sio_b9600; cfg.baudrate = kl5kusb105a_sio_b9600;
priv->cfg.databits = kl5kusb105a_dtb_8; cfg.databits = kl5kusb105a_dtb_8;
priv->cfg.unknown1 = 0; cfg.unknown1 = 0;
priv->cfg.unknown2 = 1; cfg.unknown2 = 1;
klsi_105_chg_port_settings(serial, &(priv->cfg)); klsi_105_chg_port_settings(serial, &cfg);
/* set up termios structure */ /* set up termios structure */
spin_lock_irqsave (&priv->lock, flags);
priv->termios.c_iflag = port->tty->termios->c_iflag; priv->termios.c_iflag = port->tty->termios->c_iflag;
priv->termios.c_oflag = port->tty->termios->c_oflag; priv->termios.c_oflag = port->tty->termios->c_oflag;
priv->termios.c_cflag = port->tty->termios->c_cflag; priv->termios.c_cflag = port->tty->termios->c_cflag;
priv->termios.c_lflag = port->tty->termios->c_lflag; priv->termios.c_lflag = port->tty->termios->c_lflag;
for (i=0; i<NCCS; i++) for (i=0; i<NCCS; i++)
priv->termios.c_cc[i] = port->tty->termios->c_cc[i]; priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
priv->cfg.pktlen = cfg.pktlen;
priv->cfg.baudrate = cfg.baudrate;
priv->cfg.databits = cfg.databits;
priv->cfg.unknown1 = cfg.unknown1;
priv->cfg.unknown2 = cfg.unknown2;
spin_unlock_irqrestore (&priv->lock, flags);
/* READ_ON and urb submission */ /* READ_ON and urb submission */
usb_fill_bulk_urb(port->read_urb, serial->dev, usb_fill_bulk_urb(port->read_urb, serial->dev,
...@@ -422,7 +429,9 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp) ...@@ -422,7 +429,9 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
rc = klsi_105_get_line_state(serial, &line_state); rc = klsi_105_get_line_state(serial, &line_state);
if (rc >= 0) { if (rc >= 0) {
spin_lock_irqsave (&priv->lock, flags);
priv->line_state = line_state; priv->line_state = line_state;
spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - read line state 0x%lx", __FUNCTION__, line_state); dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
retval = 0; retval = 0;
} else } else
...@@ -492,7 +501,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, ...@@ -492,7 +501,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user,
unsigned long flags; unsigned long flags;
int i; int i;
/* since the pool is per-port we might not need the spin lock !? */ /* since the pool is per-port we might not need the spin lock !? */
spin_lock_irqsave (&priv->write_urb_pool_lock, flags); spin_lock_irqsave (&priv->lock, flags);
for (i=0; i<NUM_URBS; i++) { for (i=0; i<NUM_URBS; i++) {
if (priv->write_urb_pool[i]->status != -EINPROGRESS) { if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
urb = priv->write_urb_pool[i]; urb = priv->write_urb_pool[i];
...@@ -500,7 +509,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, ...@@ -500,7 +509,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user,
break; break;
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); spin_unlock_irqrestore (&priv->lock, flags);
if (urb==NULL) { if (urb==NULL) {
dbg("%s - no more free urbs", __FUNCTION__); dbg("%s - no more free urbs", __FUNCTION__);
...@@ -552,6 +561,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, ...@@ -552,6 +561,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user,
count -= size; count -= size;
} }
exit: exit:
/* lockless, but it's for debug info only... */
priv->bytes_out+=bytes_sent; priv->bytes_out+=bytes_sent;
return bytes_sent; /* that's how much we wrote */ return bytes_sent; /* that's how much we wrote */
...@@ -588,7 +598,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port) ...@@ -588,7 +598,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
unsigned long flags; unsigned long flags;
struct klsi_105_private *priv = usb_get_serial_port_data(port); struct klsi_105_private *priv = usb_get_serial_port_data(port);
spin_lock_irqsave (&priv->write_urb_pool_lock, flags); spin_lock_irqsave (&priv->lock, flags);
for (i = 0; i < NUM_URBS; ++i) { for (i = 0; i < NUM_URBS; ++i) {
if (priv->write_urb_pool[i]->status == -EINPROGRESS) { if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
...@@ -596,7 +606,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port) ...@@ -596,7 +606,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - returns %d", __FUNCTION__, chars); dbg("%s - returns %d", __FUNCTION__, chars);
return (chars); return (chars);
...@@ -609,14 +619,14 @@ static int klsi_105_write_room (struct usb_serial_port *port) ...@@ -609,14 +619,14 @@ static int klsi_105_write_room (struct usb_serial_port *port)
int room = 0; int room = 0;
struct klsi_105_private *priv = usb_get_serial_port_data(port); struct klsi_105_private *priv = usb_get_serial_port_data(port);
spin_lock_irqsave (&priv->write_urb_pool_lock, flags); spin_lock_irqsave (&priv->lock, flags);
for (i = 0; i < NUM_URBS; ++i) { for (i = 0; i < NUM_URBS; ++i) {
if (priv->write_urb_pool[i]->status != -EINPROGRESS) { if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
room += URB_TRANSFER_BUFFER_SIZE; room += URB_TRANSFER_BUFFER_SIZE;
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - returns %d", __FUNCTION__, room); dbg("%s - returns %d", __FUNCTION__, room);
return (room); return (room);
...@@ -690,6 +700,8 @@ static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -690,6 +700,8 @@ static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
tty_insert_flip_char(tty, ((__u8*) data)[i], 0); tty_insert_flip_char(tty, ((__u8*) data)[i], 0);
} }
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
/* again lockless, but debug info only */
priv->bytes_in += bytes_sent; priv->bytes_in += bytes_sent;
} }
/* Continue trying to always read */ /* Continue trying to always read */
...@@ -715,6 +727,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port, ...@@ -715,6 +727,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
unsigned int old_iflag = old_termios->c_iflag; unsigned int old_iflag = old_termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag; unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag;
struct klsi_105_port_settings cfg;
unsigned long flags;
/* lock while we are modifying the settings */
spin_lock_irqsave (&priv->lock, flags);
/* /*
* Update baud rate * Update baud rate
...@@ -838,9 +855,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port, ...@@ -838,9 +855,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
#endif #endif
; ;
} }
memcpy (&cfg, &priv->cfg, sizeof(cfg));
spin_unlock_irqrestore (&priv->lock, flags);
/* now commit changes to device */ /* now commit changes to device */
klsi_105_chg_port_settings(serial, &(priv->cfg)); klsi_105_chg_port_settings(serial, &cfg);
} /* klsi_105_set_termios */ } /* klsi_105_set_termios */
...@@ -866,6 +885,7 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, ...@@ -866,6 +885,7 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct klsi_105_private *priv = usb_get_serial_port_data(port); struct klsi_105_private *priv = usb_get_serial_port_data(port);
int mask; int mask;
unsigned long flags;
dbg("%scmd=0x%x", __FUNCTION__, cmd); dbg("%scmd=0x%x", __FUNCTION__, cmd);
...@@ -881,11 +901,12 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, ...@@ -881,11 +901,12 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
err("Reading line control failed (error = %d)", rc); err("Reading line control failed (error = %d)", rc);
/* better return value? EAGAIN? */ /* better return value? EAGAIN? */
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} else {
priv->line_state = line_state;
dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
} }
return put_user(priv->line_state, (unsigned long *) arg); spin_lock_irqsave (&priv->lock, flags);
priv->line_state = line_state;
spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
return put_user(line_state, (unsigned long *) arg);
}; };
case TIOCMSET: /* Turns on and off the lines as specified by the mask */ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
......
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