aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2008-01-22 09:54:54 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 17:35:04 -0500
commit9e3b1d8e3d5d135ac7be43f6710b7a67b569c292 (patch)
treed49c28ab6eb379e9cdc7cd9d28110c0967790486 /drivers/usb/serial
parent0b3f5fe673d4626ea91816ca9c486b43b39a2fd1 (diff)
USB: stop abuse of intfdata in cypress_m8
this driver uses usb_get_intfdata() == NULL as a test for disconnect(). You must not do that as this races with probe(). By the time you test your erstwhile interface may already be somebody else's interface. This fixes the close() method of cypress_m8 to use the recently introduced flag and use locking against disconnect() where required in close(). Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/cypress_m8.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 163386336a5d..08c65c1a3771 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -682,7 +682,6 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
682{ 682{
683 struct cypress_private *priv = usb_get_serial_port_data(port); 683 struct cypress_private *priv = usb_get_serial_port_data(port);
684 unsigned int c_cflag; 684 unsigned int c_cflag;
685 unsigned long flags;
686 int bps; 685 int bps;
687 long timeout; 686 long timeout;
688 wait_queue_t wait; 687 wait_queue_t wait;
@@ -690,7 +689,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
690 dbg("%s - port %d", __FUNCTION__, port->number); 689 dbg("%s - port %d", __FUNCTION__, port->number);
691 690
692 /* wait for data to drain from buffer */ 691 /* wait for data to drain from buffer */
693 spin_lock_irqsave(&priv->lock, flags); 692 spin_lock_irq(&priv->lock);
694 timeout = CYPRESS_CLOSING_WAIT; 693 timeout = CYPRESS_CLOSING_WAIT;
695 init_waitqueue_entry(&wait, current); 694 init_waitqueue_entry(&wait, current);
696 add_wait_queue(&port->tty->write_wait, &wait); 695 add_wait_queue(&port->tty->write_wait, &wait);
@@ -698,18 +697,25 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
698 set_current_state(TASK_INTERRUPTIBLE); 697 set_current_state(TASK_INTERRUPTIBLE);
699 if (cypress_buf_data_avail(priv->buf) == 0 698 if (cypress_buf_data_avail(priv->buf) == 0
700 || timeout == 0 || signal_pending(current) 699 || timeout == 0 || signal_pending(current)
701 || !usb_get_intfdata(port->serial->interface)) 700 /* without mutex, allowed due to harmless failure mode */
701 || port->serial->disconnected)
702 break; 702 break;
703 spin_unlock_irqrestore(&priv->lock, flags); 703 spin_unlock_irq(&priv->lock);
704 timeout = schedule_timeout(timeout); 704 timeout = schedule_timeout(timeout);
705 spin_lock_irqsave(&priv->lock, flags); 705 spin_lock_irq(&priv->lock);
706 } 706 }
707 set_current_state(TASK_RUNNING); 707 set_current_state(TASK_RUNNING);
708 remove_wait_queue(&port->tty->write_wait, &wait); 708 remove_wait_queue(&port->tty->write_wait, &wait);
709 /* clear out any remaining data in the buffer */ 709 /* clear out any remaining data in the buffer */
710 cypress_buf_clear(priv->buf); 710 cypress_buf_clear(priv->buf);
711 spin_unlock_irqrestore(&priv->lock, flags); 711 spin_unlock_irq(&priv->lock);
712 712
713 /* writing is potentially harmful, lock must be taken */
714 mutex_lock(&port->serial->disc_mutex);
715 if (port->serial->disconnected) {
716 mutex_unlock(&port->serial->disc_mutex);
717 return;
718 }
713 /* wait for characters to drain from device */ 719 /* wait for characters to drain from device */
714 bps = tty_get_baud_rate(port->tty); 720 bps = tty_get_baud_rate(port->tty);
715 if (bps > 1200) 721 if (bps > 1200)
@@ -727,10 +733,10 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
727 if (c_cflag & HUPCL) { 733 if (c_cflag & HUPCL) {
728 /* drop dtr and rts */ 734 /* drop dtr and rts */
729 priv = usb_get_serial_port_data(port); 735 priv = usb_get_serial_port_data(port);
730 spin_lock_irqsave(&priv->lock, flags); 736 spin_lock_irq(&priv->lock);
731 priv->line_control = 0; 737 priv->line_control = 0;
732 priv->cmd_ctrl = 1; 738 priv->cmd_ctrl = 1;
733 spin_unlock_irqrestore(&priv->lock, flags); 739 spin_unlock_irq(&priv->lock);
734 cypress_write(port, NULL, 0); 740 cypress_write(port, NULL, 0);
735 } 741 }
736 } 742 }
@@ -738,6 +744,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
738 if (stats) 744 if (stats)
739 dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", 745 dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
740 priv->bytes_in, priv->bytes_out, priv->cmd_count); 746 priv->bytes_in, priv->bytes_out, priv->cmd_count);
747 mutex_unlock(&port->serial->disc_mutex);
741} /* cypress_close */ 748} /* cypress_close */
742 749
743 750