tty serialize flush_to_ldisc
authorPaul Fulghum <paulkf@microgate.com>
Wed, 26 Jul 2006 19:10:29 +0000 (14:10 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 7 Aug 2006 03:52:16 +0000 (20:52 -0700)
Serialize processing of tty buffers in flush_to_ldisc
to fix (very rare) corruption of tty buffer free list
on SMP systems.

Signed-off-by: Paul Fulghum <paulkf@microgate.com>
Acked-by: Alan Cox <alan@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/char/tty_io.c

index a88b94a82b140f42b24d68409f651392805e0465..832163c3e951911a3352cffbe2c29562ee2cf237 100644 (file)
@@ -2776,7 +2776,7 @@ static void flush_to_ldisc(void *private_)
        struct tty_struct *tty = (struct tty_struct *) private_;
        unsigned long   flags;
        struct tty_ldisc *disc;
-       struct tty_buffer *tbuf;
+       struct tty_buffer *tbuf, *head;
        int count;
        char *char_buf;
        unsigned char *flag_buf;
@@ -2793,7 +2793,9 @@ static void flush_to_ldisc(void *private_)
                goto out;
        }
        spin_lock_irqsave(&tty->buf.lock, flags);
-       while((tbuf = tty->buf.head) != NULL) {
+       head = tty->buf.head;
+       tty->buf.head = NULL;
+       while((tbuf = head) != NULL) {
                while ((count = tbuf->commit - tbuf->read) != 0) {
                        char_buf = tbuf->char_buf_ptr + tbuf->read;
                        flag_buf = tbuf->flag_buf_ptr + tbuf->read;
@@ -2802,10 +2804,12 @@ static void flush_to_ldisc(void *private_)
                        disc->receive_buf(tty, char_buf, flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
                }
-               if (tbuf->active)
+               if (tbuf->active) {
+                       tty->buf.head = head;
                        break;
-               tty->buf.head = tbuf->next;
-               if (tty->buf.head == NULL)
+               }
+               head = tbuf->next;
+               if (head == NULL)
                        tty->buf.tail = NULL;
                tty_buffer_free(tty, tbuf);
        }