Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit addaebcc authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman
Browse files

n_tty: Use separate head and tail indices for echo_buf



Instead of using a single index to track the current echo_buf position,
use a head index when adding to the buffer and a tail index when
consuming from the buffer. Allow these head and tail indices to wrap
at max representable value; perform modulo reduction via helper
functions when accessing the buffer.

Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ae56f330
Loading
Loading
Loading
Loading
+35 −53
Original line number Diff line number Diff line
@@ -108,7 +108,8 @@ struct n_tty_data {

	/* protected by echo_lock */
	unsigned char *echo_buf;
	unsigned int echo_pos;
	size_t echo_head;
	size_t echo_tail;
	unsigned int echo_cnt;

	/* protected by output lock */
@@ -135,6 +136,16 @@ static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i)
	return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
}

static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
{
	return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
}

static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
{
	return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
}

static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
			       unsigned char __user *ptr)
{
@@ -325,7 +336,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;

	mutex_lock(&ldata->echo_lock);
	ldata->echo_pos = ldata->echo_cnt = 0;
	ldata->echo_head = ldata->echo_tail = ldata->echo_cnt = 0;
	mutex_unlock(&ldata->echo_lock);

	ldata->erasing = 0;
@@ -640,8 +651,8 @@ static void process_echoes(struct tty_struct *tty)
{
	struct n_tty_data *ldata = tty->disc_data;
	int	space, nr;
	size_t tail;
	unsigned char c;
	unsigned char *cp, *buf_end;

	if (!ldata->echo_cnt)
		return;
@@ -651,14 +662,12 @@ static void process_echoes(struct tty_struct *tty)

	space = tty_write_room(tty);

	buf_end = ldata->echo_buf + N_TTY_BUF_SIZE;
	cp = ldata->echo_buf + ldata->echo_pos;
	tail = ldata->echo_tail;
	nr = ldata->echo_cnt;
	while (nr > 0) {
		c = *cp;
		c = echo_buf(ldata, tail);
		if (c == ECHO_OP_START) {
			unsigned char op;
			unsigned char *opp;
			int no_space_left = 0;

			/*
@@ -666,18 +675,13 @@ static void process_echoes(struct tty_struct *tty)
			 * operation, get the next byte, which is either the
			 * op code or a control character value.
			 */
			opp = cp + 1;
			if (opp == buf_end)
				opp -= N_TTY_BUF_SIZE;
			op = *opp;
			op = echo_buf(ldata, tail + 1);

			switch (op) {
				unsigned int num_chars, num_bs;

			case ECHO_OP_ERASE_TAB:
				if (++opp == buf_end)
					opp -= N_TTY_BUF_SIZE;
				num_chars = *opp;
				num_chars = echo_buf(ldata, tail + 2);

				/*
				 * Determine how many columns to go back
@@ -703,20 +707,20 @@ static void process_echoes(struct tty_struct *tty)
					if (ldata->column > 0)
						ldata->column--;
				}
				cp += 3;
				tail += 3;
				nr -= 3;
				break;

			case ECHO_OP_SET_CANON_COL:
				ldata->canon_column = ldata->column;
				cp += 2;
				tail += 2;
				nr -= 2;
				break;

			case ECHO_OP_MOVE_BACK_COL:
				if (ldata->column > 0)
					ldata->column--;
				cp += 2;
				tail += 2;
				nr -= 2;
				break;

@@ -729,7 +733,7 @@ static void process_echoes(struct tty_struct *tty)
				tty_put_char(tty, ECHO_OP_START);
				ldata->column++;
				space--;
				cp += 2;
				tail += 2;
				nr -= 2;
				break;

@@ -751,7 +755,7 @@ static void process_echoes(struct tty_struct *tty)
				tty_put_char(tty, op ^ 0100);
				ldata->column += 2;
				space -= 2;
				cp += 2;
				tail += 2;
				nr -= 2;
			}

@@ -769,24 +773,13 @@ static void process_echoes(struct tty_struct *tty)
				tty_put_char(tty, c);
				space -= 1;
			}
			cp += 1;
			tail += 1;
			nr -= 1;
		}

		/* When end of circular buffer reached, wrap around */
		if (cp >= buf_end)
			cp -= N_TTY_BUF_SIZE;
	}

	if (nr == 0) {
		ldata->echo_pos = 0;
		ldata->echo_cnt = 0;
	} else {
		int num_processed = ldata->echo_cnt - nr;
		ldata->echo_pos += num_processed;
		ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
	ldata->echo_tail = tail;
	ldata->echo_cnt = nr;
	}

	mutex_unlock(&ldata->echo_lock);
	mutex_unlock(&ldata->output_lock);
@@ -807,37 +800,26 @@ static void process_echoes(struct tty_struct *tty)

static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
{
	int	new_byte_pos;

	if (ldata->echo_cnt == N_TTY_BUF_SIZE) {
		/* Circular buffer is already at capacity */
		new_byte_pos = ldata->echo_pos;

		size_t head = ldata->echo_head;
		/*
		 * Since the buffer start position needs to be advanced,
		 * be sure to step by a whole operation byte group.
		 */
		if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) {
			if (ldata->echo_buf[(ldata->echo_pos + 1) &
					  (N_TTY_BUF_SIZE - 1)] ==
						ECHO_OP_ERASE_TAB) {
				ldata->echo_pos += 3;
		if (echo_buf(ldata, head) == ECHO_OP_START) {
			if (echo_buf(ldata, head + 1) == ECHO_OP_ERASE_TAB) {
				ldata->echo_tail += 3;
				ldata->echo_cnt -= 2;
			} else {
				ldata->echo_pos += 2;
				ldata->echo_tail += 2;
				ldata->echo_cnt -= 1;
			}
		} else {
			ldata->echo_pos++;
		}
		ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
	} else {
		new_byte_pos = ldata->echo_pos + ldata->echo_cnt;
		new_byte_pos &= N_TTY_BUF_SIZE - 1;
		} else
			ldata->echo_tail++;
	} else
		ldata->echo_cnt++;
	}

	ldata->echo_buf[new_byte_pos] = c;
	*echo_buf_addr(ldata, ldata->echo_head++) = c;
}

/**