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

Commit df862f62 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tty/serial fixes from Greg KH:
 "Here are some tty and serial driver fixes for things reported
  recently"

* tag 'tty-3.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: Fix lockless tty buffer race
  Revert "tty: Fix race condition between __tty_buffer_request_room and flush_to_ldisc"
  drivers/tty/hvc: don't free hvc_console_setup after init
  n_tty: Fix n_tty_write crash when echoing in raw mode
  tty: serial: 8250_core.c Bug fix for Exar chips.
parents a1e74464 62a0d8d7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ static struct tty_driver *hvc_console_device(struct console *c, int *index)
	return hvc_driver;
}

static int __init hvc_console_setup(struct console *co, char *options)
static int hvc_console_setup(struct console *co, char *options)
{	
	if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
		return -ENODEV;
+4 −0
Original line number Diff line number Diff line
@@ -2353,8 +2353,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
			if (tty->ops->flush_chars)
				tty->ops->flush_chars(tty);
		} else {
			struct n_tty_data *ldata = tty->disc_data;

			while (nr > 0) {
				mutex_lock(&ldata->output_lock);
				c = tty->ops->write(tty, b, nr);
				mutex_unlock(&ldata->output_lock);
				if (c < 0) {
					retval = c;
					goto break_out;
+1 −1
Original line number Diff line number Diff line
@@ -555,7 +555,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
	 */
	if ((p->port.type == PORT_XR17V35X) ||
	   (p->port.type == PORT_XR17D15X)) {
		serial_out(p, UART_EXAR_SLEEP, 0xff);
		serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);
		return;
	}

+14 −15
Original line number Diff line number Diff line
@@ -255,16 +255,15 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
	if (change || left < size) {
		/* This is the slow path - looking for new buffers to use */
		if ((n = tty_buffer_alloc(port, size)) != NULL) {
			unsigned long iflags;

			n->flags = flags;
			buf->tail = n;

			spin_lock_irqsave(&buf->flush_lock, iflags);
			b->commit = b->used;
			/* paired w/ barrier in flush_to_ldisc(); ensures the
			 * latest commit value can be read before the head is
			 * advanced to the next buffer
			 */
			smp_wmb();
			b->next = n;
			spin_unlock_irqrestore(&buf->flush_lock, iflags);

		} else if (change)
			size = 0;
		else
@@ -448,27 +447,28 @@ static void flush_to_ldisc(struct work_struct *work)
	mutex_lock(&buf->lock);

	while (1) {
		unsigned long flags;
		struct tty_buffer *head = buf->head;
		struct tty_buffer *next;
		int count;

		/* Ldisc or user is trying to gain exclusive access */
		if (atomic_read(&buf->priority))
			break;

		spin_lock_irqsave(&buf->flush_lock, flags);
		next = head->next;
		/* paired w/ barrier in __tty_buffer_request_room();
		 * ensures commit value read is not stale if the head
		 * is advancing to the next buffer
		 */
		smp_rmb();
		count = head->commit - head->read;
		if (!count) {
			if (head->next == NULL) {
				spin_unlock_irqrestore(&buf->flush_lock, flags);
			if (next == NULL)
				break;
			}
			buf->head = head->next;
			spin_unlock_irqrestore(&buf->flush_lock, flags);
			buf->head = next;
			tty_buffer_free(port, head);
			continue;
		}
		spin_unlock_irqrestore(&buf->flush_lock, flags);

		count = receive_buf(tty, head, count);
		if (!count)
@@ -523,7 +523,6 @@ void tty_buffer_init(struct tty_port *port)
	struct tty_bufhead *buf = &port->buf;

	mutex_init(&buf->lock);
	spin_lock_init(&buf->flush_lock);
	tty_buffer_reset(&buf->sentinel, 0);
	buf->head = &buf->sentinel;
	buf->tail = &buf->sentinel;
+0 −1
Original line number Diff line number Diff line
@@ -61,7 +61,6 @@ struct tty_bufhead {
	struct tty_buffer *head;	/* Queue head */
	struct work_struct work;
	struct mutex	   lock;
	spinlock_t	   flush_lock;
	atomic_t	   priority;
	struct tty_buffer sentinel;
	struct llist_head free;		/* Free queue head */