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.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 8ebd9f88a6f6..cf78d1985cd8 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -258,7 +258,11 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
258 n->flags = flags; 258 n->flags = flags;
259 buf->tail = n; 259 buf->tail = n;
260 b->commit = b->used; 260 b->commit = b->used;
261 smp_mb(); 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();
262 b->next = n; 266 b->next = n;
263 } else if (change) 267 } else if (change)
264 size = 0; 268 size = 0;
@@ -444,17 +448,24 @@ static void flush_to_ldisc(struct work_struct *work)
444 448
445 while (1) { 449 while (1) {
446 struct tty_buffer *head = buf->head; 450 struct tty_buffer *head = buf->head;
451 struct tty_buffer *next;
447 int count; 452 int count;
448 453
449 /* Ldisc or user is trying to gain exclusive access */ 454 /* Ldisc or user is trying to gain exclusive access */
450 if (atomic_read(&buf->priority)) 455 if (atomic_read(&buf->priority))
451 break; 456 break;
452 457
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();
453 count = head->commit - head->read; 464 count = head->commit - head->read;
454 if (!count) { 465 if (!count) {
455 if (head->next == NULL) 466 if (next == NULL)
456 break; 467 break;
457 buf->head = head->next; 468 buf->head = next;
458 tty_buffer_free(port, head); 469 tty_buffer_free(port, head);
459 continue; 470 continue;
460 } 471 }