Skip to content

Commit cbfd034

Browse files
peterhurleygregkh
authored andcommitted
n_tty: Process echoes in blocks
Byte-by-byte echo output is painfully slow, requiring a lock/unlock cycle for every input byte. Instead, perform the echo output in blocks of 256 characters, and at least once per flip buffer receive. Enough space is reserved in the echo buffer to guarantee a full block can be saved without overrunning the echo output. Overrun is prevented by discarding the oldest echoes until enough space exists in the echo buffer to receive at least a full block of new echoes. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 019ebdf commit cbfd034

File tree

1 file changed

+47
-23
lines changed

1 file changed

+47
-23
lines changed

drivers/tty/n_tty.c

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@
7474
#define ECHO_OP_SET_CANON_COL 0x81
7575
#define ECHO_OP_ERASE_TAB 0x82
7676

77+
#define ECHO_COMMIT_WATERMARK 256
78+
#define ECHO_BLOCK 256
79+
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
80+
81+
7782
#undef N_TTY_TRACE
7883
#ifdef N_TTY_TRACE
7984
# define n_tty_trace(f, args...) trace_printk(f, ##args)
@@ -766,15 +771,40 @@ static void __process_echoes(struct tty_struct *tty)
766771
}
767772
}
768773

774+
/* If the echo buffer is nearly full (so that the possibility exists
775+
* of echo overrun before the next commit), then discard enough
776+
* data at the tail to prevent a subsequent overrun */
777+
while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
778+
if (echo_buf(ldata, tail == ECHO_OP_START)) {
779+
if (echo_buf(ldata, tail) == ECHO_OP_ERASE_TAB)
780+
tail += 3;
781+
else
782+
tail += 2;
783+
} else
784+
tail++;
785+
}
786+
769787
ldata->echo_tail = tail;
770788
}
771789

772790
static void commit_echoes(struct tty_struct *tty)
773791
{
774792
struct n_tty_data *ldata = tty->disc_data;
793+
size_t nr, old;
794+
size_t head;
795+
796+
head = ldata->echo_head;
797+
old = ldata->echo_commit - ldata->echo_tail;
798+
799+
/* Process committed echoes if the accumulated # of bytes
800+
* is over the threshold (and try again each time another
801+
* block is accumulated) */
802+
nr = head - ldata->echo_tail;
803+
if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
804+
return;
775805

776806
mutex_lock(&ldata->output_lock);
777-
ldata->echo_commit = ldata->echo_head;
807+
ldata->echo_commit = head;
778808
__process_echoes(tty);
779809
mutex_unlock(&ldata->output_lock);
780810

@@ -797,37 +827,29 @@ static void process_echoes(struct tty_struct *tty)
797827
tty->ops->flush_chars(tty);
798828
}
799829

830+
static void flush_echoes(struct tty_struct *tty)
831+
{
832+
struct n_tty_data *ldata = tty->disc_data;
833+
834+
if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_head)
835+
return;
836+
837+
mutex_lock(&ldata->output_lock);
838+
ldata->echo_commit = ldata->echo_head;
839+
__process_echoes(tty);
840+
mutex_unlock(&ldata->output_lock);
841+
}
842+
800843
/**
801844
* add_echo_byte - add a byte to the echo buffer
802845
* @c: unicode byte to echo
803846
* @ldata: n_tty data
804847
*
805848
* Add a character or operation byte to the echo buffer.
806-
*
807-
* Locks: may claim output_lock to prevent concurrent modify of
808-
* echo_tail by process_echoes().
809849
*/
810850

811-
static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
851+
static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
812852
{
813-
if (ldata->echo_head - ldata->echo_tail == N_TTY_BUF_SIZE) {
814-
size_t head = ldata->echo_head;
815-
816-
mutex_lock(&ldata->output_lock);
817-
/*
818-
* Since the buffer start position needs to be advanced,
819-
* be sure to step by a whole operation byte group.
820-
*/
821-
if (echo_buf(ldata, head) == ECHO_OP_START) {
822-
if (echo_buf(ldata, head + 1) == ECHO_OP_ERASE_TAB)
823-
ldata->echo_tail += 3;
824-
else
825-
ldata->echo_tail += 2;
826-
} else
827-
ldata->echo_tail++;
828-
mutex_unlock(&ldata->output_lock);
829-
}
830-
831853
*echo_buf_addr(ldata, ldata->echo_head++) = c;
832854
}
833855

@@ -1515,6 +1537,8 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
15151537
break;
15161538
}
15171539
}
1540+
1541+
flush_echoes(tty);
15181542
if (tty->ops->flush_chars)
15191543
tty->ops->flush_chars(tty);
15201544
}

0 commit comments

Comments
 (0)