aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2015-01-16 15:05:37 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-02-02 13:11:26 -0500
commit70aca71f92ca2c111978bf676287fab5580d2598 (patch)
treef9fc767837a07d5381f3c61e791dd02caeb754d4 /drivers/tty
parent5e28cca1539f3532cb2392710655cd3e562cee8b (diff)
n_tty: Fix unordered accesses to lockless read buffer
Add commit_head buffer index, which the producer-side publishes after input processing in non-canon mode. This ensures the consumer-side observes correctly-ordered writes in non-canonical mode (ie., the buffer data is written before the buffer index is advanced). Fix consumer-side uses of read_cnt() to use commit_head instead. Add required memory barriers to the tail index to guarantee the consumer-side has completed the loads before the producer-side begins writing new data. Open-code the producer-side receive_room() into the i/o loop. Remove no-longer-referenced receive_room(). Based on work by Christian Riesch <christian.riesch@omicron.at> Cc: Christian Riesch <christian.riesch@omicron.at> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/n_tty.c101
1 files changed, 48 insertions, 53 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 7efabc4673b6..f63b25bbe895 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -90,6 +90,7 @@
90struct n_tty_data { 90struct n_tty_data {
91 /* producer-published */ 91 /* producer-published */
92 size_t read_head; 92 size_t read_head;
93 size_t commit_head;
93 size_t canon_head; 94 size_t canon_head;
94 size_t echo_head; 95 size_t echo_head;
95 size_t echo_commit; 96 size_t echo_commit;
@@ -161,31 +162,6 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
161 return put_user(x, ptr); 162 return put_user(x, ptr);
162} 163}
163 164
164static int receive_room(struct tty_struct *tty)
165{
166 struct n_tty_data *ldata = tty->disc_data;
167 int left;
168
169 if (I_PARMRK(tty)) {
170 /* Multiply read_cnt by 3, since each byte might take up to
171 * three times as many spaces when PARMRK is set (depending on
172 * its flags, e.g. parity error). */
173 left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1;
174 } else
175 left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1;
176
177 /*
178 * If we are doing input canonicalization, and there are no
179 * pending newlines, let characters through without limit, so
180 * that erase characters will be handled. Other excess
181 * characters will be beeped.
182 */
183 if (left <= 0)
184 left = ldata->icanon && ldata->canon_head == ldata->read_tail;
185
186 return left;
187}
188
189/** 165/**
190 * n_tty_kick_worker - start input worker (if required) 166 * n_tty_kick_worker - start input worker (if required)
191 * @tty: terminal 167 * @tty: terminal
@@ -224,7 +200,7 @@ static ssize_t chars_in_buffer(struct tty_struct *tty)
224 ssize_t n = 0; 200 ssize_t n = 0;
225 201
226 if (!ldata->icanon) 202 if (!ldata->icanon)
227 n = read_cnt(ldata); 203 n = ldata->commit_head - ldata->read_tail;
228 else 204 else
229 n = ldata->canon_head - ldata->read_tail; 205 n = ldata->canon_head - ldata->read_tail;
230 return n; 206 return n;
@@ -318,10 +294,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
318 * 294 *
319 * n_tty_receive_buf()/producer path: 295 * n_tty_receive_buf()/producer path:
320 * caller holds non-exclusive termios_rwsem 296 * caller holds non-exclusive termios_rwsem
321 * modifies read_head
322 *
323 * read_head is only considered 'published' if canonical mode is
324 * not active.
325 */ 297 */
326 298
327static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) 299static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
@@ -345,6 +317,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
345{ 317{
346 ldata->read_head = ldata->canon_head = ldata->read_tail = 0; 318 ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
347 ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; 319 ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
320 ldata->commit_head = 0;
348 ldata->echo_mark = 0; 321 ldata->echo_mark = 0;
349 ldata->line_start = 0; 322 ldata->line_start = 0;
350 323
@@ -992,10 +965,6 @@ static inline void finish_erasing(struct n_tty_data *ldata)
992 * 965 *
993 * n_tty_receive_buf()/producer path: 966 * n_tty_receive_buf()/producer path:
994 * caller holds non-exclusive termios_rwsem 967 * caller holds non-exclusive termios_rwsem
995 * modifies read_head
996 *
997 * Modifying the read_head is not considered a publish in this context
998 * because canonical mode is active -- only canon_head publishes
999 */ 968 */
1000 969
1001static void eraser(unsigned char c, struct tty_struct *tty) 970static void eraser(unsigned char c, struct tty_struct *tty)
@@ -1144,7 +1113,6 @@ static void isig(int sig, struct tty_struct *tty)
1144 * 1113 *
1145 * n_tty_receive_buf()/producer path: 1114 * n_tty_receive_buf()/producer path:
1146 * caller holds non-exclusive termios_rwsem 1115 * caller holds non-exclusive termios_rwsem
1147 * publishes read_head via put_tty_queue()
1148 * 1116 *
1149 * Note: may get exclusive termios_rwsem if flushing input buffer 1117 * Note: may get exclusive termios_rwsem if flushing input buffer
1150 */ 1118 */
@@ -1214,7 +1182,6 @@ static void n_tty_receive_overrun(struct tty_struct *tty)
1214 * 1182 *
1215 * n_tty_receive_buf()/producer path: 1183 * n_tty_receive_buf()/producer path:
1216 * caller holds non-exclusive termios_rwsem 1184 * caller holds non-exclusive termios_rwsem
1217 * publishes read_head via put_tty_queue()
1218 */ 1185 */
1219static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) 1186static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
1220{ 1187{
@@ -1268,7 +1235,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
1268 * n_tty_receive_buf()/producer path: 1235 * n_tty_receive_buf()/producer path:
1269 * caller holds non-exclusive termios_rwsem 1236 * caller holds non-exclusive termios_rwsem
1270 * publishes canon_head if canonical mode is active 1237 * publishes canon_head if canonical mode is active
1271 * otherwise, publishes read_head via put_tty_queue()
1272 * 1238 *
1273 * Returns 1 if LNEXT was received, else returns 0 1239 * Returns 1 if LNEXT was received, else returns 0
1274 */ 1240 */
@@ -1381,7 +1347,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
1381handle_newline: 1347handle_newline:
1382 set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags); 1348 set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
1383 put_tty_queue(c, ldata); 1349 put_tty_queue(c, ldata);
1384 ldata->canon_head = ldata->read_head; 1350 smp_store_release(&ldata->canon_head, ldata->read_head);
1385 kill_fasync(&tty->fasync, SIGIO, POLL_IN); 1351 kill_fasync(&tty->fasync, SIGIO, POLL_IN);
1386 if (waitqueue_active(&tty->read_wait)) 1352 if (waitqueue_active(&tty->read_wait))
1387 wake_up_interruptible_poll(&tty->read_wait, POLLIN); 1353 wake_up_interruptible_poll(&tty->read_wait, POLLIN);
@@ -1531,7 +1497,7 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
1531 * 1497 *
1532 * n_tty_receive_buf()/producer path: 1498 * n_tty_receive_buf()/producer path:
1533 * claims non-exclusive termios_rwsem 1499 * claims non-exclusive termios_rwsem
1534 * publishes read_head and canon_head 1500 * publishes commit_head or canon_head
1535 */ 1501 */
1536 1502
1537static void 1503static void
@@ -1542,16 +1508,14 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
1542 size_t n, head; 1508 size_t n, head;
1543 1509
1544 head = ldata->read_head & (N_TTY_BUF_SIZE - 1); 1510 head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
1545 n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head); 1511 n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
1546 n = min_t(size_t, count, n);
1547 memcpy(read_buf_addr(ldata, head), cp, n); 1512 memcpy(read_buf_addr(ldata, head), cp, n);
1548 ldata->read_head += n; 1513 ldata->read_head += n;
1549 cp += n; 1514 cp += n;
1550 count -= n; 1515 count -= n;
1551 1516
1552 head = ldata->read_head & (N_TTY_BUF_SIZE - 1); 1517 head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
1553 n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head); 1518 n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
1554 n = min_t(size_t, count, n);
1555 memcpy(read_buf_addr(ldata, head), cp, n); 1519 memcpy(read_buf_addr(ldata, head), cp, n);
1556 ldata->read_head += n; 1520 ldata->read_head += n;
1557} 1521}
@@ -1681,8 +1645,13 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
1681 tty->ops->flush_chars(tty); 1645 tty->ops->flush_chars(tty);
1682 } 1646 }
1683 1647
1684 if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) || 1648 if (ldata->icanon && !L_EXTPROC(tty))
1685 L_EXTPROC(tty)) { 1649 return;
1650
1651 /* publish read_head to consumer */
1652 smp_store_release(&ldata->commit_head, ldata->read_head);
1653
1654 if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
1686 kill_fasync(&tty->fasync, SIGIO, POLL_IN); 1655 kill_fasync(&tty->fasync, SIGIO, POLL_IN);
1687 if (waitqueue_active(&tty->read_wait)) 1656 if (waitqueue_active(&tty->read_wait))
1688 wake_up_interruptible_poll(&tty->read_wait, POLLIN); 1657 wake_up_interruptible_poll(&tty->read_wait, POLLIN);
@@ -1699,7 +1668,31 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
1699 down_read(&tty->termios_rwsem); 1668 down_read(&tty->termios_rwsem);
1700 1669
1701 while (1) { 1670 while (1) {
1702 room = receive_room(tty); 1671 /*
1672 * When PARMRK is set, multiply read_cnt by 3, since each byte
1673 * might take up to three times as many spaces (depending on
1674 * its flags, e.g. parity error). [This calculation is wrong.]
1675 *
1676 * If we are doing input canonicalization, and there are no
1677 * pending newlines, let characters through without limit, so
1678 * that erase characters will be handled. Other excess
1679 * characters will be beeped.
1680 *
1681 * paired with store in *_copy_from_read_buf() -- guarantees
1682 * the consumer has loaded the data in read_buf up to the new
1683 * read_tail (so this producer will not overwrite unread data)
1684 */
1685 size_t tail = smp_load_acquire(&ldata->read_tail);
1686 size_t head = ldata->read_head;
1687
1688 if (I_PARMRK(tty))
1689 room = N_TTY_BUF_SIZE - (head - tail) * 3 - 1;
1690 else
1691 room = N_TTY_BUF_SIZE - (head - tail) - 1;
1692
1693 if (room <= 0)
1694 room = ldata->icanon && ldata->canon_head == tail;
1695
1703 n = min(count, room); 1696 n = min(count, room);
1704 if (!n) { 1697 if (!n) {
1705 if (flow && !room) 1698 if (flow && !room)
@@ -1769,6 +1762,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
1769 ldata->canon_head = ldata->read_head; 1762 ldata->canon_head = ldata->read_head;
1770 ldata->push = 1; 1763 ldata->push = 1;
1771 } 1764 }
1765 ldata->commit_head = ldata->read_head;
1772 ldata->erasing = 0; 1766 ldata->erasing = 0;
1773 ldata->lnext = 0; 1767 ldata->lnext = 0;
1774 } 1768 }
@@ -1909,7 +1903,7 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
1909 if (ldata->icanon && !L_EXTPROC(tty)) 1903 if (ldata->icanon && !L_EXTPROC(tty))
1910 return ldata->canon_head != ldata->read_tail; 1904 return ldata->canon_head != ldata->read_tail;
1911 else 1905 else
1912 return read_cnt(ldata) >= amt; 1906 return ldata->commit_head - ldata->read_tail >= amt;
1913} 1907}
1914 1908
1915/** 1909/**
@@ -1941,10 +1935,11 @@ static int copy_from_read_buf(struct tty_struct *tty,
1941 int retval; 1935 int retval;
1942 size_t n; 1936 size_t n;
1943 bool is_eof; 1937 bool is_eof;
1938 size_t head = smp_load_acquire(&ldata->commit_head);
1944 size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); 1939 size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
1945 1940
1946 retval = 0; 1941 retval = 0;
1947 n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail); 1942 n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
1948 n = min(*nr, n); 1943 n = min(*nr, n);
1949 if (n) { 1944 if (n) {
1950 retval = copy_to_user(*b, read_buf_addr(ldata, tail), n); 1945 retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
@@ -1952,9 +1947,10 @@ static int copy_from_read_buf(struct tty_struct *tty,
1952 is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty); 1947 is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
1953 tty_audit_add_data(tty, read_buf_addr(ldata, tail), n, 1948 tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
1954 ldata->icanon); 1949 ldata->icanon);
1955 ldata->read_tail += n; 1950 smp_store_release(&ldata->read_tail, ldata->read_tail + n);
1956 /* Turn single EOF into zero-length read */ 1951 /* Turn single EOF into zero-length read */
1957 if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata)) 1952 if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
1953 (head == ldata->read_tail))
1958 n = 0; 1954 n = 0;
1959 *b += n; 1955 *b += n;
1960 *nr -= n; 1956 *nr -= n;
@@ -1997,7 +1993,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
1997 bool eof_push = 0; 1993 bool eof_push = 0;
1998 1994
1999 /* N.B. avoid overrun if nr == 0 */ 1995 /* N.B. avoid overrun if nr == 0 */
2000 n = min(*nr, read_cnt(ldata)); 1996 n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
2001 if (!n) 1997 if (!n)
2002 return 0; 1998 return 0;
2003 1999
@@ -2047,8 +2043,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
2047 2043
2048 if (found) 2044 if (found)
2049 clear_bit(eol, ldata->read_flags); 2045 clear_bit(eol, ldata->read_flags);
2050 smp_mb__after_atomic(); 2046 smp_store_release(&ldata->read_tail, ldata->read_tail + c);
2051 ldata->read_tail += c;
2052 2047
2053 if (found) { 2048 if (found) {
2054 if (!ldata->push) 2049 if (!ldata->push)