ChangeSet 1.1002.3.21, 2003/02/25 16:07:43-08:00, [EMAIL PROTECTED]
[PATCH] USB: fixed potential races in kl5kusb105.c now that there's no locks in the
usb-serial core
drivers/usb/serial/kl5kusb105.c | 69 ++++++++++++++++++++++++++--------------
1 files changed, 45 insertions(+), 24 deletions(-)
diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
--- a/drivers/usb/serial/kl5kusb105.c Fri Feb 28 14:49:33 2003
+++ b/drivers/usb/serial/kl5kusb105.c Fri Feb 28 14:49:33 2003
@@ -166,7 +166,7 @@
unsigned long line_state; /* modem line settings */
/* write pool */
struct urb * write_urb_pool[NUM_URBS];
- spinlock_t write_urb_pool_lock;
+ spinlock_t lock;
unsigned long bytes_in;
unsigned long bytes_out;
};
@@ -284,7 +284,7 @@
priv->bytes_out = 0;
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++) {
struct urb* urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -326,7 +326,7 @@
/* kill our write urb pool */
int j;
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++) {
if (write_urbs[j]) {
@@ -343,8 +343,7 @@
}
}
- spin_unlock_irqrestore (&priv->write_urb_pool_lock,
- flags);
+ spin_unlock_irqrestore (&priv->lock, flags);
kfree(priv);
usb_set_serial_port_data(&serial->port[i], NULL);
@@ -360,6 +359,8 @@
int rc;
int i;
unsigned long line_state;
+ struct klsi_105_port_settings cfg;
+ unsigned long flags;
dbg("%s port %d", __FUNCTION__, port->number);
@@ -374,21 +375,27 @@
* Then read the modem line control and store values in
* priv->line_state.
*/
- priv->cfg.pktlen = 5;
- priv->cfg.baudrate = kl5kusb105a_sio_b9600;
- priv->cfg.databits = kl5kusb105a_dtb_8;
- priv->cfg.unknown1 = 0;
- priv->cfg.unknown2 = 1;
- klsi_105_chg_port_settings(serial, &(priv->cfg));
+ cfg.pktlen = 5;
+ cfg.baudrate = kl5kusb105a_sio_b9600;
+ cfg.databits = kl5kusb105a_dtb_8;
+ cfg.unknown1 = 0;
+ cfg.unknown2 = 1;
+ klsi_105_chg_port_settings(serial, &cfg);
/* set up termios structure */
+ spin_lock_irqsave (&priv->lock, flags);
priv->termios.c_iflag = port->tty->termios->c_iflag;
priv->termios.c_oflag = port->tty->termios->c_oflag;
priv->termios.c_cflag = port->tty->termios->c_cflag;
priv->termios.c_lflag = port->tty->termios->c_lflag;
for (i=0; i<NCCS; 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 */
usb_fill_bulk_urb(port->read_urb, serial->dev,
@@ -422,7 +429,9 @@
rc = klsi_105_get_line_state(serial, &line_state);
if (rc >= 0) {
+ 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);
retval = 0;
} else
@@ -492,7 +501,7 @@
unsigned long flags;
int i;
/* 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++) {
if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
urb = priv->write_urb_pool[i];
@@ -500,7 +509,7 @@
break;
}
}
- spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+ spin_unlock_irqrestore (&priv->lock, flags);
if (urb==NULL) {
dbg("%s - no more free urbs", __FUNCTION__);
@@ -552,6 +561,7 @@
count -= size;
}
exit:
+ /* lockless, but it's for debug info only... */
priv->bytes_out+=bytes_sent;
return bytes_sent; /* that's how much we wrote */
@@ -588,7 +598,7 @@
unsigned long flags;
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) {
if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
@@ -596,7 +606,7 @@
}
}
- spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+ spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - returns %d", __FUNCTION__, chars);
return (chars);
@@ -609,14 +619,14 @@
int room = 0;
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) {
if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
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);
return (room);
@@ -690,6 +700,8 @@
tty_insert_flip_char(tty, ((__u8*) data)[i], 0);
}
tty_flip_buffer_push(tty);
+
+ /* again lockless, but debug info only */
priv->bytes_in += bytes_sent;
}
/* Continue trying to always read */
@@ -715,6 +727,11 @@
unsigned int old_iflag = old_termios->c_iflag;
unsigned int cflag = port->tty->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
@@ -838,9 +855,11 @@
#endif
;
}
-
+ memcpy (&cfg, &priv->cfg, sizeof(cfg));
+ spin_unlock_irqrestore (&priv->lock, flags);
+
/* now commit changes to device */
- klsi_105_chg_port_settings(serial, &(priv->cfg));
+ klsi_105_chg_port_settings(serial, &cfg);
} /* klsi_105_set_termios */
@@ -866,6 +885,7 @@
struct usb_serial *serial = port->serial;
struct klsi_105_private *priv = usb_get_serial_port_data(port);
int mask;
+ unsigned long flags;
dbg("%scmd=0x%x", __FUNCTION__, cmd);
@@ -881,11 +901,12 @@
err("Reading line control failed (error = %d)", rc);
/* better return value? EAGAIN? */
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 */
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel