|
@@ -225,8 +225,6 @@ static void n_tty_check_throttle(struct tty_struct *tty)
|
|
|
{
|
|
|
struct n_tty_data *ldata = tty->disc_data;
|
|
|
|
|
|
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
|
|
|
- return;
|
|
|
/*
|
|
|
* Check the remaining room for the input canonicalization
|
|
|
* mode. We don't want to throttle the driver if we're in
|
|
@@ -1483,23 +1481,6 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
|
|
|
n_tty_receive_char_flagged(tty, c, flag);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * n_tty_receive_buf - data receive
|
|
|
- * @tty: terminal device
|
|
|
- * @cp: buffer
|
|
|
- * @fp: flag buffer
|
|
|
- * @count: characters
|
|
|
- *
|
|
|
- * Called by the terminal driver when a block of characters has
|
|
|
- * been received. This function must be called from soft contexts
|
|
|
- * not from interrupt context. The driver is responsible for making
|
|
|
- * calls one at a time and in order (or using flush_to_ldisc)
|
|
|
- *
|
|
|
- * n_tty_receive_buf()/producer path:
|
|
|
- * claims non-exclusive termios_rwsem
|
|
|
- * publishes commit_head or canon_head
|
|
|
- */
|
|
|
-
|
|
|
static void
|
|
|
n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
|
|
|
char *fp, int count)
|
|
@@ -1658,12 +1639,45 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * n_tty_receive_buf_common - process input
|
|
|
+ * @tty: device to receive input
|
|
|
+ * @cp: input chars
|
|
|
+ * @fp: flags for each char (if NULL, all chars are TTY_NORMAL)
|
|
|
+ * @count: number of input chars in @cp
|
|
|
+ *
|
|
|
+ * Called by the terminal driver when a block of characters has
|
|
|
+ * been received. This function must be called from soft contexts
|
|
|
+ * not from interrupt context. The driver is responsible for making
|
|
|
+ * calls one at a time and in order (or using flush_to_ldisc)
|
|
|
+ *
|
|
|
+ * Returns the # of input chars from @cp which were processed.
|
|
|
+ *
|
|
|
+ * In canonical mode, the maximum line length is 4096 chars (including
|
|
|
+ * the line termination char); lines longer than 4096 chars are
|
|
|
+ * truncated. After 4095 chars, input data is still processed but
|
|
|
+ * not stored. Overflow processing ensures the tty can always
|
|
|
+ * receive more input until at least one line can be read.
|
|
|
+ *
|
|
|
+ * In non-canonical mode, the read buffer will only accept 4095 chars;
|
|
|
+ * this provides the necessary space for a newline char if the input
|
|
|
+ * mode is switched to canonical.
|
|
|
+ *
|
|
|
+ * Note it is possible for the read buffer to _contain_ 4096 chars
|
|
|
+ * in non-canonical mode: the read buffer could already contain the
|
|
|
+ * maximum canon line of 4096 chars when the mode is switched to
|
|
|
+ * non-canonical.
|
|
|
+ *
|
|
|
+ * n_tty_receive_buf()/producer path:
|
|
|
+ * claims non-exclusive termios_rwsem
|
|
|
+ * publishes commit_head or canon_head
|
|
|
+ */
|
|
|
static int
|
|
|
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
|
|
char *fp, int count, int flow)
|
|
|
{
|
|
|
struct n_tty_data *ldata = tty->disc_data;
|
|
|
- int room, n, rcvd = 0;
|
|
|
+ int room, n, rcvd = 0, overflow;
|
|
|
|
|
|
down_read(&tty->termios_rwsem);
|
|
|
|
|
@@ -1683,19 +1697,27 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
|
|
*/
|
|
|
size_t tail = smp_load_acquire(&ldata->read_tail);
|
|
|
|
|
|
- room = N_TTY_BUF_SIZE - (ldata->read_head - tail) - 1;
|
|
|
+ room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
|
|
|
if (I_PARMRK(tty))
|
|
|
- room /= 3;
|
|
|
- if (room <= 0)
|
|
|
- room = ldata->icanon && ldata->canon_head == tail;
|
|
|
+ room = (room + 2) / 3;
|
|
|
+ room--;
|
|
|
+ if (room <= 0) {
|
|
|
+ overflow = ldata->icanon && ldata->canon_head == tail;
|
|
|
+ if (overflow && room < 0)
|
|
|
+ ldata->read_head--;
|
|
|
+ room = overflow;
|
|
|
+ ldata->no_room = flow && !room;
|
|
|
+ } else
|
|
|
+ overflow = 0;
|
|
|
|
|
|
n = min(count, room);
|
|
|
- if (!n) {
|
|
|
- if (flow && !room)
|
|
|
- ldata->no_room = 1;
|
|
|
+ if (!n)
|
|
|
break;
|
|
|
- }
|
|
|
- __receive_buf(tty, cp, fp, n);
|
|
|
+
|
|
|
+ /* ignore parity errors if handling overflow */
|
|
|
+ if (!overflow || !fp || *fp != TTY_PARITY)
|
|
|
+ __receive_buf(tty, cp, fp, n);
|
|
|
+
|
|
|
cp += n;
|
|
|
if (fp)
|
|
|
fp += n;
|
|
@@ -1704,7 +1726,17 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
|
|
|
}
|
|
|
|
|
|
tty->receive_room = room;
|
|
|
- n_tty_check_throttle(tty);
|
|
|
+
|
|
|
+ /* Unthrottle if handling overflow on pty */
|
|
|
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
|
|
|
+ if (overflow) {
|
|
|
+ tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
|
|
|
+ tty_unthrottle_safe(tty);
|
|
|
+ __tty_set_flow_change(tty, 0);
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ n_tty_check_throttle(tty);
|
|
|
+
|
|
|
up_read(&tty->termios_rwsem);
|
|
|
|
|
|
return rcvd;
|