aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r--drivers/tty/tty_buffer.c29
1 files changed, 14 insertions, 15 deletions
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;