diff options
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r-- | drivers/tty/tty_buffer.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 8ebd9f88a6f..143deb62467 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -60,6 +60,7 @@ void tty_buffer_lock_exclusive(struct tty_port *port) atomic_inc(&buf->priority); mutex_lock(&buf->lock); } +EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); void tty_buffer_unlock_exclusive(struct tty_port *port) { @@ -73,6 +74,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port) if (restart) queue_work(system_unbound_wq, &buf->work); } +EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); /** * tty_buffer_space_avail - return unused buffer space @@ -258,7 +260,11 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, n->flags = flags; buf->tail = n; b->commit = b->used; - smp_mb(); + /* 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; } else if (change) size = 0; @@ -444,17 +450,24 @@ static void flush_to_ldisc(struct work_struct *work) while (1) { 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; + 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) + if (next == NULL) break; - buf->head = head->next; + buf->head = next; tty_buffer_free(port, head); continue; } |