diff options
Diffstat (limited to 'drivers/tty/n_tty.c')
| -rw-r--r-- | drivers/tty/n_tty.c | 79 | 
1 files changed, 37 insertions, 42 deletions
| diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 13844261cd5f..d9a5fc28fef4 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -162,14 +162,25 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,  	return put_user(x, ptr);  } -static inline int tty_copy_to_user(struct tty_struct *tty, -					void __user *to, -					const void *from, -					unsigned long n) +static int tty_copy_to_user(struct tty_struct *tty, void __user *to, +			    size_t tail, size_t n)  {  	struct n_tty_data *ldata = tty->disc_data; +	size_t size = N_TTY_BUF_SIZE - tail; +	const void *from = read_buf_addr(ldata, tail); +	int uncopied; -	tty_audit_add_data(tty, to, n, ldata->icanon); +	if (n > size) { +		tty_audit_add_data(tty, from, size, ldata->icanon); +		uncopied = copy_to_user(to, from, size); +		if (uncopied) +			return uncopied; +		to += size; +		n -= size; +		from = ldata->read_buf; +	} + +	tty_audit_add_data(tty, from, n, ldata->icanon);  	return copy_to_user(to, from, n);  } @@ -1201,9 +1212,7 @@ static void n_tty_receive_overrun(struct tty_struct *tty)  	ldata->num_overrun++;  	if (time_after(jiffies, ldata->overrun_time + HZ) ||  			time_after(ldata->overrun_time, jiffies)) { -		printk(KERN_WARNING "%s: %d input overrun(s)\n", -			tty_name(tty), -			ldata->num_overrun); +		tty_warn(tty, "%d input overrun(s)\n", ldata->num_overrun);  		ldata->overrun_time = jiffies;  		ldata->num_overrun = 0;  	} @@ -1486,8 +1495,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)  		n_tty_receive_overrun(tty);  		break;  	default: -		printk(KERN_ERR "%s: unknown flag %d\n", -		       tty_name(tty), flag); +		tty_err(tty, "unknown flag %d\n", flag);  		break;  	}  } @@ -2006,11 +2014,11 @@ static int copy_from_read_buf(struct tty_struct *tty,  	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); +		const unsigned char *from = read_buf_addr(ldata, tail); +		retval = copy_to_user(*b, from, n);  		n -= retval; -		is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty); -		tty_audit_add_data(tty, read_buf_addr(ldata, tail), n, -				ldata->icanon); +		is_eof = n == 1 && *from == EOF_CHAR(tty); +		tty_audit_add_data(tty, from, n, ldata->icanon);  		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 && @@ -2054,13 +2062,13 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,  	size_t eol;  	size_t tail;  	int ret, found = 0; -	bool eof_push = 0;  	/* N.B. avoid overrun if nr == 0 */ -	n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); -	if (!n) +	if (!*nr)  		return 0; +	n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); +  	tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);  	size = min_t(size_t, tail + n, N_TTY_BUF_SIZE); @@ -2072,34 +2080,24 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,  	if (eol == N_TTY_BUF_SIZE && more) {  		/* scan wrapped without finding set bit */  		eol = find_next_bit(ldata->read_flags, more, 0); -		if (eol != more) -			found = 1; -	} else if (eol != size) -		found = 1; +		found = eol != more; +	} else +		found = eol != size; -	size = N_TTY_BUF_SIZE - tail;  	n = eol - tail;  	if (n > N_TTY_BUF_SIZE)  		n += N_TTY_BUF_SIZE; -	n += found; -	c = n; +	c = n + found; -	if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) { -		n--; -		eof_push = !n && ldata->read_tail != ldata->line_start; +	if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) { +		c = min(*nr, c); +		n = c;  	} -	n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n", -		    __func__, eol, found, n, c, size, more); - -	if (n > size) { -		ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), size); -		if (ret) -			return -EFAULT; -		ret = tty_copy_to_user(tty, *b + size, ldata->read_buf, n - size); -	} else -		ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), n); +	n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n", +		    __func__, eol, found, n, c, tail, more); +	ret = tty_copy_to_user(tty, *b, tail, n);  	if (ret)  		return -EFAULT;  	*b += n; @@ -2116,7 +2114,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,  			ldata->push = 0;  		tty_audit_push(tty);  	} -	return eof_push ? -EAGAIN : 0; +	return 0;  }  extern ssize_t redirected_tty_write(struct file *, const char __user *, @@ -2273,10 +2271,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,  		if (ldata->icanon && !L_EXTPROC(tty)) {  			retval = canon_copy_from_read_buf(tty, &b, &nr); -			if (retval == -EAGAIN) { -				retval = 0; -				continue; -			} else if (retval) +			if (retval)  				break;  		} else {  			int uncopied; | 
