Skip to content

Commit

Permalink
USB: last abuses of intfdata in close for usb-serial drivers
Browse files Browse the repository at this point in the history
these drivers abused intfdata in close() as flags for binding.
That races with reprobing of those devices. This patch fixes that by using
the flag and the locks introduced with the patch against mos7720.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Oliver Neukum authored and Greg Kroah-Hartman committed Feb 1, 2008
1 parent 3edbc98 commit 0915f49
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 15 deletions.
13 changes: 7 additions & 6 deletions drivers/usb/serial/digi_acceleport.c
Original file line number Diff line number Diff line change
Expand Up @@ -1405,19 +1405,19 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
unsigned char buf[32];
struct tty_struct *tty = port->tty;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned long flags = 0;

dbg("digi_close: TOP: port=%d, open_count=%d",
priv->dp_port_num, port->open_count);

mutex_lock(&port->serial->disc_mutex);
/* if disconnected, just clear flags */
if (!usb_get_intfdata(port->serial->interface))
if (port->serial->disconnected)
goto exit;

/* do cleanup only after final close on this port */
spin_lock_irqsave(&priv->dp_port_lock, flags);
spin_lock_irq(&priv->dp_port_lock);
priv->dp_in_close = 1;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
spin_unlock_irq(&priv->dp_port_lock);

/* tell line discipline to process only XON/XOFF */
tty->closing = 1;
Expand Down Expand Up @@ -1482,11 +1482,12 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
}
tty->closing = 0;
exit:
spin_lock_irqsave(&priv->dp_port_lock, flags);
spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
wake_up_interruptible(&priv->dp_close_wait);
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
spin_unlock_irq(&priv->dp_port_lock);
mutex_unlock(&port->serial->disc_mutex);
dbg("digi_close: done");
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/serial/oti6858.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
set_current_state(TASK_INTERRUPTIBLE);
if (oti6858_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
|| !usb_get_intfdata(port->serial->interface)) /* disconnect */
|| port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/serial/pl2303.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp)
set_current_state(TASK_INTERRUPTIBLE);
if (pl2303_buf_data_avail(priv->buf) == 0 ||
timeout == 0 || signal_pending(current) ||
!usb_get_intfdata(port->serial->interface)) /* disconnect */
port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
Expand Down
17 changes: 10 additions & 7 deletions drivers/usb/serial/ti_usb_3410_5052.c
Original file line number Diff line number Diff line change
Expand Up @@ -1493,11 +1493,10 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
struct ti_device *tdev = tport->tp_tdev;
struct usb_serial_port *port = tport->tp_port;
wait_queue_t wait;
unsigned long flags;

dbg("%s - port %d", __FUNCTION__, port->number);

spin_lock_irqsave(&tport->tp_lock, flags);
spin_lock_irq(&tport->tp_lock);

/* wait for data to drain from the buffer */
tdev->td_urb_error = 0;
Expand All @@ -1508,11 +1507,11 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
if (ti_buf_data_avail(tport->tp_write_buf) == 0
|| timeout == 0 || signal_pending(current)
|| tdev->td_urb_error
|| !usb_get_intfdata(port->serial->interface)) /* disconnect */
|| port->serial->disconnected) /* disconnect */
break;
spin_unlock_irqrestore(&tport->tp_lock, flags);
spin_unlock_irq(&tport->tp_lock);
timeout = schedule_timeout(timeout);
spin_lock_irqsave(&tport->tp_lock, flags);
spin_lock_irq(&tport->tp_lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tport->tp_write_wait, &wait);
Expand All @@ -1521,19 +1520,23 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
if (flush)
ti_buf_clear(tport->tp_write_buf);

spin_unlock_irqrestore(&tport->tp_lock, flags);
spin_unlock_irq(&tport->tp_lock);

mutex_lock(&port->serial->disc_mutex);
/* wait for data to drain from the device */
/* wait for empty tx register, plus 20 ms */
timeout += jiffies;
tport->tp_lsr &= ~TI_LSR_TX_EMPTY;
while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
&& !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error
&& usb_get_intfdata(port->serial->interface)) { /* not disconnected */
&& !port->serial->disconnected) {
if (ti_get_lsr(tport))
break;
mutex_unlock(&port->serial->disc_mutex);
msleep_interruptible(20);
mutex_lock(&port->serial->disc_mutex);
}
mutex_unlock(&port->serial->disc_mutex);
}


Expand Down

0 comments on commit 0915f49

Please sign in to comment.