aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-05-05 18:50:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-05-05 18:50:16 -0400
commitdf862f625d62c8d5aef41361a8d21e4f55a0e748 (patch)
tree53dcd0ee8d44c9d186461dfd2d5cb4caa594e70d
parenta1e74464ffddf47e9a18f99a54242122bfd0997b (diff)
parent62a0d8d7c2b29f92850e4ee3c38e5dfd936e92b2 (diff)
Merge tag 'tty-3.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
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.
-rw-r--r--drivers/tty/hvc/hvc_console.c2
-rw-r--r--drivers/tty/n_tty.c4
-rw-r--r--drivers/tty/serial/8250/8250_core.c2
-rw-r--r--drivers/tty/tty_buffer.c29
-rw-r--r--include/linux/tty.h1
5 files changed, 20 insertions, 18 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 94f9e3a38412..0ff7fda0742f 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -190,7 +190,7 @@ static struct tty_driver *hvc_console_device(struct console *c, int *index)
190 return hvc_driver; 190 return hvc_driver;
191} 191}
192 192
193static int __init hvc_console_setup(struct console *co, char *options) 193static int hvc_console_setup(struct console *co, char *options)
194{ 194{
195 if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES) 195 if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
196 return -ENODEV; 196 return -ENODEV;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 41fe8a047d37..fe9d129c8735 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2353,8 +2353,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
2353 if (tty->ops->flush_chars) 2353 if (tty->ops->flush_chars)
2354 tty->ops->flush_chars(tty); 2354 tty->ops->flush_chars(tty);
2355 } else { 2355 } else {
2356 struct n_tty_data *ldata = tty->disc_data;
2357
2356 while (nr > 0) { 2358 while (nr > 0) {
2359 mutex_lock(&ldata->output_lock);
2357 c = tty->ops->write(tty, b, nr); 2360 c = tty->ops->write(tty, b, nr);
2361 mutex_unlock(&ldata->output_lock);
2358 if (c < 0) { 2362 if (c < 0) {
2359 retval = c; 2363 retval = c;
2360 goto break_out; 2364 goto break_out;
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 0e1bf8858431..2d4bd3929e50 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -555,7 +555,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
555 */ 555 */
556 if ((p->port.type == PORT_XR17V35X) || 556 if ((p->port.type == PORT_XR17V35X) ||
557 (p->port.type == PORT_XR17D15X)) { 557 (p->port.type == PORT_XR17D15X)) {
558 serial_out(p, UART_EXAR_SLEEP, 0xff); 558 serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);
559 return; 559 return;
560 } 560 }
561 561
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index f1d30f6945af..cf78d1985cd8 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -255,16 +255,15 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
255 if (change || left < size) { 255 if (change || left < size) {
256 /* This is the slow path - looking for new buffers to use */ 256 /* This is the slow path - looking for new buffers to use */
257 if ((n = tty_buffer_alloc(port, size)) != NULL) { 257 if ((n = tty_buffer_alloc(port, size)) != NULL) {
258 unsigned long iflags;
259
260 n->flags = flags; 258 n->flags = flags;
261 buf->tail = n; 259 buf->tail = n;
262
263 spin_lock_irqsave(&buf->flush_lock, iflags);
264 b->commit = b->used; 260 b->commit = b->used;
261 /* paired w/ barrier in flush_to_ldisc(); ensures the
262 * latest commit value can be read before the head is
263 * advanced to the next buffer
264 */
265 smp_wmb();
265 b->next = n; 266 b->next = n;
266 spin_unlock_irqrestore(&buf->flush_lock, iflags);
267
268 } else if (change) 267 } else if (change)
269 size = 0; 268 size = 0;
270 else 269 else
@@ -448,27 +447,28 @@ static void flush_to_ldisc(struct work_struct *work)
448 mutex_lock(&buf->lock); 447 mutex_lock(&buf->lock);
449 448
450 while (1) { 449 while (1) {
451 unsigned long flags;
452 struct tty_buffer *head = buf->head; 450 struct tty_buffer *head = buf->head;
451 struct tty_buffer *next;
453 int count; 452 int count;
454 453
455 /* Ldisc or user is trying to gain exclusive access */ 454 /* Ldisc or user is trying to gain exclusive access */
456 if (atomic_read(&buf->priority)) 455 if (atomic_read(&buf->priority))
457 break; 456 break;
458 457
459 spin_lock_irqsave(&buf->flush_lock, flags); 458 next = head->next;
459 /* paired w/ barrier in __tty_buffer_request_room();
460 * ensures commit value read is not stale if the head
461 * is advancing to the next buffer
462 */
463 smp_rmb();
460 count = head->commit - head->read; 464 count = head->commit - head->read;
461 if (!count) { 465 if (!count) {
462 if (head->next == NULL) { 466 if (next == NULL)
463 spin_unlock_irqrestore(&buf->flush_lock, flags);
464 break; 467 break;
465 } 468 buf->head = next;
466 buf->head = head->next;
467 spin_unlock_irqrestore(&buf->flush_lock, flags);
468 tty_buffer_free(port, head); 469 tty_buffer_free(port, head);
469 continue; 470 continue;
470 } 471 }
471 spin_unlock_irqrestore(&buf->flush_lock, flags);
472 472
473 count = receive_buf(tty, head, count); 473 count = receive_buf(tty, head, count);
474 if (!count) 474 if (!count)
@@ -523,7 +523,6 @@ void tty_buffer_init(struct tty_port *port)
523 struct tty_bufhead *buf = &port->buf; 523 struct tty_bufhead *buf = &port->buf;
524 524
525 mutex_init(&buf->lock); 525 mutex_init(&buf->lock);
526 spin_lock_init(&buf->flush_lock);
527 tty_buffer_reset(&buf->sentinel, 0); 526 tty_buffer_reset(&buf->sentinel, 0);
528 buf->head = &buf->sentinel; 527 buf->head = &buf->sentinel;
529 buf->tail = &buf->sentinel; 528 buf->tail = &buf->sentinel;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 036cccd80d9f..1c3316a47d7e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -61,7 +61,6 @@ struct tty_bufhead {
61 struct tty_buffer *head; /* Queue head */ 61 struct tty_buffer *head; /* Queue head */
62 struct work_struct work; 62 struct work_struct work;
63 struct mutex lock; 63 struct mutex lock;
64 spinlock_t flush_lock;
65 atomic_t priority; 64 atomic_t priority;
66 struct tty_buffer sentinel; 65 struct tty_buffer sentinel;
67 struct llist_head free; /* Free queue head */ 66 struct llist_head free; /* Free queue head */