diff options
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r-- | drivers/tty/n_tty.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index ee1c268f5f9d..8c0b7b42319c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -92,10 +92,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, | |||
92 | 92 | ||
93 | static void n_tty_set_room(struct tty_struct *tty) | 93 | static void n_tty_set_room(struct tty_struct *tty) |
94 | { | 94 | { |
95 | /* tty->read_cnt is not read locked ? */ | 95 | int left; |
96 | int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; | ||
97 | int old_left; | 96 | int old_left; |
98 | 97 | ||
98 | /* tty->read_cnt is not read locked ? */ | ||
99 | if (I_PARMRK(tty)) { | ||
100 | /* Multiply read_cnt by 3, since each byte might take up to | ||
101 | * three times as many spaces when PARMRK is set (depending on | ||
102 | * its flags, e.g. parity error). */ | ||
103 | left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1; | ||
104 | } else | ||
105 | left = N_TTY_BUF_SIZE - tty->read_cnt - 1; | ||
106 | |||
99 | /* | 107 | /* |
100 | * If we are doing input canonicalization, and there are no | 108 | * If we are doing input canonicalization, and there are no |
101 | * pending newlines, let characters through without limit, so | 109 | * pending newlines, let characters through without limit, so |
@@ -1432,6 +1440,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, | |||
1432 | */ | 1440 | */ |
1433 | if (tty->receive_room < TTY_THRESHOLD_THROTTLE) | 1441 | if (tty->receive_room < TTY_THRESHOLD_THROTTLE) |
1434 | tty_throttle(tty); | 1442 | tty_throttle(tty); |
1443 | |||
1444 | /* FIXME: there is a tiny race here if the receive room check runs | ||
1445 | before the other work executes and empties the buffer (upping | ||
1446 | the receiving room and unthrottling. We then throttle and get | ||
1447 | stuck. This has been observed and traced down by Vincent Pillet/ | ||
1448 | We need to address this when we sort out out the rx path locking */ | ||
1435 | } | 1449 | } |
1436 | 1450 | ||
1437 | int is_ignored(int sig) | 1451 | int is_ignored(int sig) |
@@ -1460,7 +1474,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) | |||
1460 | BUG_ON(!tty); | 1474 | BUG_ON(!tty); |
1461 | 1475 | ||
1462 | if (old) | 1476 | if (old) |
1463 | canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; | 1477 | canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON; |
1464 | if (canon_change) { | 1478 | if (canon_change) { |
1465 | memset(&tty->read_flags, 0, sizeof tty->read_flags); | 1479 | memset(&tty->read_flags, 0, sizeof tty->read_flags); |
1466 | tty->canon_head = tty->read_tail; | 1480 | tty->canon_head = tty->read_tail; |
@@ -1728,7 +1742,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, | |||
1728 | 1742 | ||
1729 | do_it_again: | 1743 | do_it_again: |
1730 | 1744 | ||
1731 | BUG_ON(!tty->read_buf); | 1745 | if (WARN_ON(!tty->read_buf)) |
1746 | return -EAGAIN; | ||
1732 | 1747 | ||
1733 | c = job_control(tty, file); | 1748 | c = job_control(tty, file); |
1734 | if (c < 0) | 1749 | if (c < 0) |
@@ -1832,13 +1847,13 @@ do_it_again: | |||
1832 | 1847 | ||
1833 | if (tty->icanon && !L_EXTPROC(tty)) { | 1848 | if (tty->icanon && !L_EXTPROC(tty)) { |
1834 | /* N.B. avoid overrun if nr == 0 */ | 1849 | /* N.B. avoid overrun if nr == 0 */ |
1850 | spin_lock_irqsave(&tty->read_lock, flags); | ||
1835 | while (nr && tty->read_cnt) { | 1851 | while (nr && tty->read_cnt) { |
1836 | int eol; | 1852 | int eol; |
1837 | 1853 | ||
1838 | eol = test_and_clear_bit(tty->read_tail, | 1854 | eol = test_and_clear_bit(tty->read_tail, |
1839 | tty->read_flags); | 1855 | tty->read_flags); |
1840 | c = tty->read_buf[tty->read_tail]; | 1856 | c = tty->read_buf[tty->read_tail]; |
1841 | spin_lock_irqsave(&tty->read_lock, flags); | ||
1842 | tty->read_tail = ((tty->read_tail+1) & | 1857 | tty->read_tail = ((tty->read_tail+1) & |
1843 | (N_TTY_BUF_SIZE-1)); | 1858 | (N_TTY_BUF_SIZE-1)); |
1844 | tty->read_cnt--; | 1859 | tty->read_cnt--; |
@@ -1856,15 +1871,19 @@ do_it_again: | |||
1856 | if (tty_put_user(tty, c, b++)) { | 1871 | if (tty_put_user(tty, c, b++)) { |
1857 | retval = -EFAULT; | 1872 | retval = -EFAULT; |
1858 | b--; | 1873 | b--; |
1874 | spin_lock_irqsave(&tty->read_lock, flags); | ||
1859 | break; | 1875 | break; |
1860 | } | 1876 | } |
1861 | nr--; | 1877 | nr--; |
1862 | } | 1878 | } |
1863 | if (eol) { | 1879 | if (eol) { |
1864 | tty_audit_push(tty); | 1880 | tty_audit_push(tty); |
1881 | spin_lock_irqsave(&tty->read_lock, flags); | ||
1865 | break; | 1882 | break; |
1866 | } | 1883 | } |
1884 | spin_lock_irqsave(&tty->read_lock, flags); | ||
1867 | } | 1885 | } |
1886 | spin_unlock_irqrestore(&tty->read_lock, flags); | ||
1868 | if (retval) | 1887 | if (retval) |
1869 | break; | 1888 | break; |
1870 | } else { | 1889 | } else { |