]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/tty/tty_buffer.c
Merge tag 'compress-3.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[karo-tx-linux.git] / drivers / tty / tty_buffer.c
index 8ebd9f88a6f69ff85f63139944fad2542c789483..143deb62467d57a1f1216d3f418c2bfccb72201c 100644 (file)
@@ -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;
                }