Loading drivers/tty/n_tty.c +27 −29 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ struct n_tty_data { /* producer-published */ size_t read_head; size_t commit_head; size_t canon_head; size_t echo_head; size_t echo_commit; Loading Loading @@ -165,14 +166,16 @@ static int receive_room(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; int left; size_t tail = smp_load_acquire(&ldata->read_tail); size_t head = ldata->read_head; if (I_PARMRK(tty)) { /* Multiply read_cnt by 3, since each byte might take up to * three times as many spaces when PARMRK is set (depending on * its flags, e.g. parity error). */ left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1; left = N_TTY_BUF_SIZE - (head - tail) * 3 - 1; } else left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1; left = N_TTY_BUF_SIZE - (head - tail) - 1; /* * If we are doing input canonicalization, and there are no Loading @@ -181,7 +184,7 @@ static int receive_room(struct tty_struct *tty) * characters will be beeped. */ if (left <= 0) left = ldata->icanon && ldata->canon_head == ldata->read_tail; left = ldata->icanon && ldata->canon_head == tail; return left; } Loading Loading @@ -235,7 +238,7 @@ static ssize_t chars_in_buffer(struct tty_struct *tty) ssize_t n = 0; if (!ldata->icanon) n = read_cnt(ldata); n = ldata->commit_head - ldata->read_tail; else n = ldata->canon_head - ldata->read_tail; return n; Loading Loading @@ -319,10 +322,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * modifies read_head * * read_head is only considered 'published' if canonical mode is * not active. */ static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) Loading @@ -346,6 +345,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata) { ldata->read_head = ldata->canon_head = ldata->read_tail = 0; ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; ldata->commit_head = 0; ldata->echo_mark = 0; ldata->line_start = 0; Loading Loading @@ -992,10 +992,6 @@ static inline void finish_erasing(struct n_tty_data *ldata) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * modifies read_head * * Modifying the read_head is not considered a publish in this context * because canonical mode is active -- only canon_head publishes */ static void eraser(unsigned char c, struct tty_struct *tty) Loading Loading @@ -1144,7 +1140,6 @@ static void isig(int sig, struct tty_struct *tty) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes read_head via put_tty_queue() * * Note: may get exclusive termios_rwsem if flushing input buffer */ Loading Loading @@ -1214,7 +1209,6 @@ static void n_tty_receive_overrun(struct tty_struct *tty) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes read_head via put_tty_queue() */ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { Loading Loading @@ -1268,7 +1262,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes canon_head if canonical mode is active * otherwise, publishes read_head via put_tty_queue() * * Returns 1 if LNEXT was received, else returns 0 */ Loading Loading @@ -1381,7 +1374,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) handle_newline: set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags); put_tty_queue(c, ldata); ldata->canon_head = ldata->read_head; smp_store_release(&ldata->canon_head, ldata->read_head); kill_fasync(&tty->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tty->read_wait, POLLIN); return 0; Loading Loading @@ -1524,16 +1517,14 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, size_t n, head; head = ldata->read_head & (N_TTY_BUF_SIZE - 1); n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head); n = min_t(size_t, count, n); n = min_t(size_t, count, N_TTY_BUF_SIZE - head); memcpy(read_buf_addr(ldata, head), cp, n); ldata->read_head += n; cp += n; count -= n; head = ldata->read_head & (N_TTY_BUF_SIZE - 1); n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head); n = min_t(size_t, count, n); n = min_t(size_t, count, N_TTY_BUF_SIZE - head); memcpy(read_buf_addr(ldata, head), cp, n); ldata->read_head += n; } Loading Loading @@ -1663,8 +1654,13 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, tty->ops->flush_chars(tty); } if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) || L_EXTPROC(tty)) { if (ldata->icanon && !L_EXTPROC(tty)) return; /* publish read_head to consumer */ smp_store_release(&ldata->commit_head, ldata->read_head); if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tty->read_wait, POLLIN); } Loading Loading @@ -1821,6 +1817,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) ldata->canon_head = ldata->read_head; ldata->push = 1; } ldata->commit_head = ldata->read_head; ldata->erasing = 0; ldata->lnext = 0; } Loading Loading @@ -1960,7 +1957,7 @@ static inline int input_available_p(struct tty_struct *tty, int poll) if (ldata->icanon && !L_EXTPROC(tty)) return ldata->canon_head != ldata->read_tail; else return read_cnt(ldata) >= amt; return ldata->commit_head - ldata->read_tail >= amt; } /** Loading Loading @@ -1992,10 +1989,11 @@ static int copy_from_read_buf(struct tty_struct *tty, int retval; size_t n; bool is_eof; size_t head = smp_load_acquire(&ldata->commit_head); size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); retval = 0; n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail); n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail); n = min(*nr, n); if (n) { retval = copy_to_user(*b, read_buf_addr(ldata, tail), n); Loading @@ -2003,9 +2001,10 @@ static int copy_from_read_buf(struct tty_struct *tty, is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty); tty_audit_add_data(tty, read_buf_addr(ldata, tail), n, ldata->icanon); ldata->read_tail += n; smp_store_release(&ldata->read_tail, ldata->read_tail + n); /* Turn single EOF into zero-length read */ if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata)) if (L_EXTPROC(tty) && ldata->icanon && is_eof && (head == ldata->read_tail)) n = 0; *b += n; *nr -= n; Loading Loading @@ -2048,7 +2047,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, bool eof_push = 0; /* N.B. avoid overrun if nr == 0 */ n = min(*nr, read_cnt(ldata)); n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); if (!n) return 0; Loading Loading @@ -2098,8 +2097,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, if (found) clear_bit(eol, ldata->read_flags); smp_mb__after_atomic(); ldata->read_tail += c; smp_store_release(&ldata->read_tail, ldata->read_tail + c); if (found) { if (!ldata->push) Loading Loading
drivers/tty/n_tty.c +27 −29 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ struct n_tty_data { /* producer-published */ size_t read_head; size_t commit_head; size_t canon_head; size_t echo_head; size_t echo_commit; Loading Loading @@ -165,14 +166,16 @@ static int receive_room(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; int left; size_t tail = smp_load_acquire(&ldata->read_tail); size_t head = ldata->read_head; if (I_PARMRK(tty)) { /* Multiply read_cnt by 3, since each byte might take up to * three times as many spaces when PARMRK is set (depending on * its flags, e.g. parity error). */ left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1; left = N_TTY_BUF_SIZE - (head - tail) * 3 - 1; } else left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1; left = N_TTY_BUF_SIZE - (head - tail) - 1; /* * If we are doing input canonicalization, and there are no Loading @@ -181,7 +184,7 @@ static int receive_room(struct tty_struct *tty) * characters will be beeped. */ if (left <= 0) left = ldata->icanon && ldata->canon_head == ldata->read_tail; left = ldata->icanon && ldata->canon_head == tail; return left; } Loading Loading @@ -235,7 +238,7 @@ static ssize_t chars_in_buffer(struct tty_struct *tty) ssize_t n = 0; if (!ldata->icanon) n = read_cnt(ldata); n = ldata->commit_head - ldata->read_tail; else n = ldata->canon_head - ldata->read_tail; return n; Loading Loading @@ -319,10 +322,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * modifies read_head * * read_head is only considered 'published' if canonical mode is * not active. */ static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) Loading @@ -346,6 +345,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata) { ldata->read_head = ldata->canon_head = ldata->read_tail = 0; ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; ldata->commit_head = 0; ldata->echo_mark = 0; ldata->line_start = 0; Loading Loading @@ -992,10 +992,6 @@ static inline void finish_erasing(struct n_tty_data *ldata) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * modifies read_head * * Modifying the read_head is not considered a publish in this context * because canonical mode is active -- only canon_head publishes */ static void eraser(unsigned char c, struct tty_struct *tty) Loading Loading @@ -1144,7 +1140,6 @@ static void isig(int sig, struct tty_struct *tty) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes read_head via put_tty_queue() * * Note: may get exclusive termios_rwsem if flushing input buffer */ Loading Loading @@ -1214,7 +1209,6 @@ static void n_tty_receive_overrun(struct tty_struct *tty) * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes read_head via put_tty_queue() */ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { Loading Loading @@ -1268,7 +1262,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes canon_head if canonical mode is active * otherwise, publishes read_head via put_tty_queue() * * Returns 1 if LNEXT was received, else returns 0 */ Loading Loading @@ -1381,7 +1374,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) handle_newline: set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags); put_tty_queue(c, ldata); ldata->canon_head = ldata->read_head; smp_store_release(&ldata->canon_head, ldata->read_head); kill_fasync(&tty->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tty->read_wait, POLLIN); return 0; Loading Loading @@ -1524,16 +1517,14 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, size_t n, head; head = ldata->read_head & (N_TTY_BUF_SIZE - 1); n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head); n = min_t(size_t, count, n); n = min_t(size_t, count, N_TTY_BUF_SIZE - head); memcpy(read_buf_addr(ldata, head), cp, n); ldata->read_head += n; cp += n; count -= n; head = ldata->read_head & (N_TTY_BUF_SIZE - 1); n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head); n = min_t(size_t, count, n); n = min_t(size_t, count, N_TTY_BUF_SIZE - head); memcpy(read_buf_addr(ldata, head), cp, n); ldata->read_head += n; } Loading Loading @@ -1663,8 +1654,13 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, tty->ops->flush_chars(tty); } if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) || L_EXTPROC(tty)) { if (ldata->icanon && !L_EXTPROC(tty)) return; /* publish read_head to consumer */ smp_store_release(&ldata->commit_head, ldata->read_head); if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tty->read_wait, POLLIN); } Loading Loading @@ -1821,6 +1817,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) ldata->canon_head = ldata->read_head; ldata->push = 1; } ldata->commit_head = ldata->read_head; ldata->erasing = 0; ldata->lnext = 0; } Loading Loading @@ -1960,7 +1957,7 @@ static inline int input_available_p(struct tty_struct *tty, int poll) if (ldata->icanon && !L_EXTPROC(tty)) return ldata->canon_head != ldata->read_tail; else return read_cnt(ldata) >= amt; return ldata->commit_head - ldata->read_tail >= amt; } /** Loading Loading @@ -1992,10 +1989,11 @@ static int copy_from_read_buf(struct tty_struct *tty, int retval; size_t n; bool is_eof; size_t head = smp_load_acquire(&ldata->commit_head); size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); retval = 0; n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail); n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail); n = min(*nr, n); if (n) { retval = copy_to_user(*b, read_buf_addr(ldata, tail), n); Loading @@ -2003,9 +2001,10 @@ static int copy_from_read_buf(struct tty_struct *tty, is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty); tty_audit_add_data(tty, read_buf_addr(ldata, tail), n, ldata->icanon); ldata->read_tail += n; smp_store_release(&ldata->read_tail, ldata->read_tail + n); /* Turn single EOF into zero-length read */ if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata)) if (L_EXTPROC(tty) && ldata->icanon && is_eof && (head == ldata->read_tail)) n = 0; *b += n; *nr -= n; Loading Loading @@ -2048,7 +2047,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, bool eof_push = 0; /* N.B. avoid overrun if nr == 0 */ n = min(*nr, read_cnt(ldata)); n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); if (!n) return 0; Loading Loading @@ -2098,8 +2097,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, if (found) clear_bit(eol, ldata->read_flags); smp_mb__after_atomic(); ldata->read_tail += c; smp_store_release(&ldata->read_tail, ldata->read_tail + c); if (found) { if (!ldata->push) Loading