Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] add receive_room flow control to flush_to_ldisc

Flush data serially to line discipline in blocks no larger than
tty->receive_room to avoid losing data if line discipline is busy (such as
N_TTY operating at high speed on heavily loaded system) or does not accept
data in large blocks (such as N_MOUSE).

Signed-off-by: Paul Fulghum <paulkf@microgate.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Paul Fulghum and committed by
Linus Torvalds
2c3bb20f 817d6d3b

+24 -13
+24 -13
drivers/char/tty_io.c
··· 2771 2771 struct tty_struct *tty = (struct tty_struct *) private_; 2772 2772 unsigned long flags; 2773 2773 struct tty_ldisc *disc; 2774 - struct tty_buffer *tbuf; 2775 - int count; 2774 + struct tty_buffer *tbuf, *head; 2776 2775 char *char_buf; 2777 2776 unsigned char *flag_buf; 2778 2777 ··· 2780 2781 return; 2781 2782 2782 2783 spin_lock_irqsave(&tty->buf.lock, flags); 2783 - while((tbuf = tty->buf.head) != NULL) { 2784 - while ((count = tbuf->commit - tbuf->read) != 0) { 2785 - char_buf = tbuf->char_buf_ptr + tbuf->read; 2786 - flag_buf = tbuf->flag_buf_ptr + tbuf->read; 2787 - tbuf->read += count; 2784 + head = tty->buf.head; 2785 + if (head != NULL) { 2786 + tty->buf.head = NULL; 2787 + for (;;) { 2788 + int count = head->commit - head->read; 2789 + if (!count) { 2790 + if (head->next == NULL) 2791 + break; 2792 + tbuf = head; 2793 + head = head->next; 2794 + tty_buffer_free(tty, tbuf); 2795 + continue; 2796 + } 2797 + if (!tty->receive_room) { 2798 + schedule_delayed_work(&tty->buf.work, 1); 2799 + break; 2800 + } 2801 + if (count > tty->receive_room) 2802 + count = tty->receive_room; 2803 + char_buf = head->char_buf_ptr + head->read; 2804 + flag_buf = head->flag_buf_ptr + head->read; 2805 + head->read += count; 2788 2806 spin_unlock_irqrestore(&tty->buf.lock, flags); 2789 2807 disc->receive_buf(tty, char_buf, flag_buf, count); 2790 2808 spin_lock_irqsave(&tty->buf.lock, flags); 2791 2809 } 2792 - if (tbuf->active) 2793 - break; 2794 - tty->buf.head = tbuf->next; 2795 - if (tty->buf.head == NULL) 2796 - tty->buf.tail = NULL; 2797 - tty_buffer_free(tty, tbuf); 2810 + tty->buf.head = head; 2798 2811 } 2799 2812 spin_unlock_irqrestore(&tty->buf.lock, flags); 2800 2813