aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/n_tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r--drivers/tty/n_tty.c29
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
93static void n_tty_set_room(struct tty_struct *tty) 93static 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
1437int is_ignored(int sig) 1451int 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
1729do_it_again: 1743do_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 {