aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/hso.c
diff options
context:
space:
mode:
authorAlan Cox <alan@redhat.com>2009-01-02 08:47:39 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-02 13:19:41 -0500
commite136e3036bf27569dbfeae245cc09c7167cdc749 (patch)
tree106be43f343a4fce34076781df05af0d32e2799a /drivers/net/usb/hso.c
parent33dd474ae712dc435eb586b44cb771cc8d24e2bd (diff)
hso: net driver using tty without locking
Checking tty == NULL doesn't help us unless we have a clear semantic for the locking of the tty object in the driver. Use the tty kref objects so that we can take references to the tty in the USB event handling paths. Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/net/usb/hso.c')
-rw-r--r--drivers/net/usb/hso.c54
1 files changed, 42 insertions, 12 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 9f7896a25f1b..d345a6eec4ca 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1015,7 +1015,7 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
1015 struct hso_serial *serial = get_serial_by_tty(tty); 1015 struct hso_serial *serial = get_serial_by_tty(tty);
1016 struct ktermios *termios; 1016 struct ktermios *termios;
1017 1017
1018 if ((!tty) || (!tty->termios) || (!serial)) { 1018 if (!serial) {
1019 printk(KERN_ERR "%s: no tty structures", __func__); 1019 printk(KERN_ERR "%s: no tty structures", __func__);
1020 return; 1020 return;
1021 } 1021 }
@@ -1057,14 +1057,14 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
1057 termios->c_cflag |= CS8; /* character size 8 bits */ 1057 termios->c_cflag |= CS8; /* character size 8 bits */
1058 1058
1059 /* baud rate 115200 */ 1059 /* baud rate 115200 */
1060 tty_encode_baud_rate(serial->tty, 115200, 115200); 1060 tty_encode_baud_rate(tty, 115200, 115200);
1061 1061
1062 /* 1062 /*
1063 * Force low_latency on; otherwise the pushes are scheduled; 1063 * Force low_latency on; otherwise the pushes are scheduled;
1064 * this is bad as it opens up the possibility of dropping bytes 1064 * this is bad as it opens up the possibility of dropping bytes
1065 * on the floor. We don't want to drop bytes on the floor. :) 1065 * on the floor. We don't want to drop bytes on the floor. :)
1066 */ 1066 */
1067 serial->tty->low_latency = 1; 1067 tty->low_latency = 1;
1068 return; 1068 return;
1069} 1069}
1070 1070
@@ -1228,6 +1228,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
1228 1228
1229 /* sanity check */ 1229 /* sanity check */
1230 if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { 1230 if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {
1231 WARN_ON(1);
1231 tty->driver_data = NULL; 1232 tty->driver_data = NULL;
1232 D1("Failed to open port"); 1233 D1("Failed to open port");
1233 return -ENODEV; 1234 return -ENODEV;
@@ -1242,8 +1243,10 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
1242 kref_get(&serial->parent->ref); 1243 kref_get(&serial->parent->ref);
1243 1244
1244 /* setup */ 1245 /* setup */
1246 spin_lock_irq(&serial->serial_lock);
1245 tty->driver_data = serial; 1247 tty->driver_data = serial;
1246 serial->tty = tty; 1248 serial->tty = tty_kref_get(tty);
1249 spin_unlock_irq(&serial->serial_lock);
1247 1250
1248 /* check for port already opened, if not set the termios */ 1251 /* check for port already opened, if not set the termios */
1249 serial->open_count++; 1252 serial->open_count++;
@@ -1285,6 +1288,10 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
1285 1288
1286 D1("Closing serial port"); 1289 D1("Closing serial port");
1287 1290
1291 /* Open failed, no close cleanup required */
1292 if (serial == NULL)
1293 return;
1294
1288 mutex_lock(&serial->parent->mutex); 1295 mutex_lock(&serial->parent->mutex);
1289 usb_gone = serial->parent->usb_gone; 1296 usb_gone = serial->parent->usb_gone;
1290 1297
@@ -1297,10 +1304,13 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
1297 kref_put(&serial->parent->ref, hso_serial_ref_free); 1304 kref_put(&serial->parent->ref, hso_serial_ref_free);
1298 if (serial->open_count <= 0) { 1305 if (serial->open_count <= 0) {
1299 serial->open_count = 0; 1306 serial->open_count = 0;
1300 if (serial->tty) { 1307 spin_lock_irq(&serial->serial_lock);
1308 if (serial->tty == tty) {
1301 serial->tty->driver_data = NULL; 1309 serial->tty->driver_data = NULL;
1302 serial->tty = NULL; 1310 serial->tty = NULL;
1311 tty_kref_put(tty);
1303 } 1312 }
1313 spin_unlock_irq(&serial->serial_lock);
1304 if (!usb_gone) 1314 if (!usb_gone)
1305 hso_stop_serial_device(serial->parent); 1315 hso_stop_serial_device(serial->parent);
1306 tasklet_kill(&serial->unthrottle_tasklet); 1316 tasklet_kill(&serial->unthrottle_tasklet);
@@ -1653,6 +1663,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
1653{ 1663{
1654 struct hso_serial *serial = urb->context; 1664 struct hso_serial *serial = urb->context;
1655 int status = urb->status; 1665 int status = urb->status;
1666 struct tty_struct *tty;
1656 1667
1657 /* sanity check */ 1668 /* sanity check */
1658 if (!serial) { 1669 if (!serial) {
@@ -1662,14 +1673,18 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
1662 1673
1663 spin_lock(&serial->serial_lock); 1674 spin_lock(&serial->serial_lock);
1664 serial->tx_urb_used = 0; 1675 serial->tx_urb_used = 0;
1676 tty = tty_kref_get(serial->tty);
1665 spin_unlock(&serial->serial_lock); 1677 spin_unlock(&serial->serial_lock);
1666 if (status) { 1678 if (status) {
1667 log_usb_status(status, __func__); 1679 log_usb_status(status, __func__);
1680 tty_kref_put(tty);
1668 return; 1681 return;
1669 } 1682 }
1670 hso_put_activity(serial->parent); 1683 hso_put_activity(serial->parent);
1671 if (serial->tty) 1684 if (tty) {
1672 tty_wakeup(serial->tty); 1685 tty_wakeup(tty);
1686 tty_kref_put(tty);
1687 }
1673 hso_kick_transmit(serial); 1688 hso_kick_transmit(serial);
1674 1689
1675 D1(" "); 1690 D1(" ");
@@ -1706,6 +1721,7 @@ static void ctrl_callback(struct urb *urb)
1706 struct hso_serial *serial = urb->context; 1721 struct hso_serial *serial = urb->context;
1707 struct usb_ctrlrequest *req; 1722 struct usb_ctrlrequest *req;
1708 int status = urb->status; 1723 int status = urb->status;
1724 struct tty_struct *tty;
1709 1725
1710 /* sanity check */ 1726 /* sanity check */
1711 if (!serial) 1727 if (!serial)
@@ -1713,9 +1729,11 @@ static void ctrl_callback(struct urb *urb)
1713 1729
1714 spin_lock(&serial->serial_lock); 1730 spin_lock(&serial->serial_lock);
1715 serial->tx_urb_used = 0; 1731 serial->tx_urb_used = 0;
1732 tty = tty_kref_get(serial->tty);
1716 spin_unlock(&serial->serial_lock); 1733 spin_unlock(&serial->serial_lock);
1717 if (status) { 1734 if (status) {
1718 log_usb_status(status, __func__); 1735 log_usb_status(status, __func__);
1736 tty_kref_put(tty);
1719 return; 1737 return;
1720 } 1738 }
1721 1739
@@ -1734,25 +1752,31 @@ static void ctrl_callback(struct urb *urb)
1734 spin_unlock(&serial->serial_lock); 1752 spin_unlock(&serial->serial_lock);
1735 } else { 1753 } else {
1736 hso_put_activity(serial->parent); 1754 hso_put_activity(serial->parent);
1737 if (serial->tty) 1755 if (tty)
1738 tty_wakeup(serial->tty); 1756 tty_wakeup(tty);
1739 /* response to a write command */ 1757 /* response to a write command */
1740 hso_kick_transmit(serial); 1758 hso_kick_transmit(serial);
1741 } 1759 }
1760 tty_kref_put(tty);
1742} 1761}
1743 1762
1744/* handle RX data for serial port */ 1763/* handle RX data for serial port */
1745static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) 1764static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
1746{ 1765{
1747 struct tty_struct *tty = serial->tty; 1766 struct tty_struct *tty;
1748 int write_length_remaining = 0; 1767 int write_length_remaining = 0;
1749 int curr_write_len; 1768 int curr_write_len;
1769
1750 /* Sanity check */ 1770 /* Sanity check */
1751 if (urb == NULL || serial == NULL) { 1771 if (urb == NULL || serial == NULL) {
1752 D1("serial = NULL"); 1772 D1("serial = NULL");
1753 return -2; 1773 return -2;
1754 } 1774 }
1755 1775
1776 spin_lock(&serial->serial_lock);
1777 tty = tty_kref_get(serial->tty);
1778 spin_unlock(&serial->serial_lock);
1779
1756 /* Push data to tty */ 1780 /* Push data to tty */
1757 if (tty) { 1781 if (tty) {
1758 write_length_remaining = urb->actual_length - 1782 write_length_remaining = urb->actual_length -
@@ -1774,6 +1798,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
1774 serial->curr_rx_urb_offset = 0; 1798 serial->curr_rx_urb_offset = 0;
1775 serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; 1799 serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
1776 } 1800 }
1801 tty_kref_put(tty);
1777 return write_length_remaining; 1802 return write_length_remaining;
1778} 1803}
1779 1804
@@ -2786,15 +2811,20 @@ static void hso_serial_ref_free(struct kref *ref)
2786static void hso_free_interface(struct usb_interface *interface) 2811static void hso_free_interface(struct usb_interface *interface)
2787{ 2812{
2788 struct hso_serial *hso_dev; 2813 struct hso_serial *hso_dev;
2814 struct tty_struct *tty;
2789 int i; 2815 int i;
2790 2816
2791 for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { 2817 for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
2792 if (serial_table[i] 2818 if (serial_table[i]
2793 && (serial_table[i]->interface == interface)) { 2819 && (serial_table[i]->interface == interface)) {
2794 hso_dev = dev2ser(serial_table[i]); 2820 hso_dev = dev2ser(serial_table[i]);
2795 if (hso_dev->tty) 2821 spin_lock_irq(&hso_dev->serial_lock);
2796 tty_hangup(hso_dev->tty); 2822 tty = tty_kref_get(hso_dev->tty);
2823 spin_unlock_irq(&hso_dev->serial_lock);
2824 if (tty)
2825 tty_hangup(tty);
2797 mutex_lock(&hso_dev->parent->mutex); 2826 mutex_lock(&hso_dev->parent->mutex);
2827 tty_kref_put(tty);
2798 hso_dev->parent->usb_gone = 1; 2828 hso_dev->parent->usb_gone = 1;
2799 mutex_unlock(&hso_dev->parent->mutex); 2829 mutex_unlock(&hso_dev->parent->mutex);
2800 kref_put(&serial_table[i]->ref, hso_serial_ref_free); 2830 kref_put(&serial_table[i]->ref, hso_serial_ref_free);