]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/tty/tty_buffer.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[mv-sheeva.git] / drivers / tty / tty_buffer.c
index cc1e9850d655fda3e700a8fe5b78b1218924424a..d8210ca007206628163efea3b2eb6dff473fadf7 100644 (file)
@@ -413,7 +413,8 @@ static void flush_to_ldisc(struct work_struct *work)
        spin_lock_irqsave(&tty->buf.lock, flags);
 
        if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
-               struct tty_buffer *head;
+               struct tty_buffer *head, *tail = tty->buf.tail;
+               int seen_tail = 0;
                while ((head = tty->buf.head) != NULL) {
                        int count;
                        char *char_buf;
@@ -423,6 +424,15 @@ static void flush_to_ldisc(struct work_struct *work)
                        if (!count) {
                                if (head->next == NULL)
                                        break;
+                               /*
+                                 There's a possibility tty might get new buffer
+                                 added during the unlock window below. We could
+                                 end up spinning in here forever hogging the CPU
+                                 completely. To avoid this let's have a rest each
+                                 time we processed the tail buffer.
+                               */
+                               if (tail == head)
+                                       seen_tail = 1;
                                tty->buf.head = head->next;
                                tty_buffer_free(tty, head);
                                continue;
@@ -432,7 +442,7 @@ static void flush_to_ldisc(struct work_struct *work)
                           line discipline as we want to empty the queue */
                        if (test_bit(TTY_FLUSHPENDING, &tty->flags))
                                break;
-                       if (!tty->receive_room) {
+                       if (!tty->receive_room || seen_tail) {
                                schedule_delayed_work(&tty->buf.work, 1);
                                break;
                        }