aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorPaul Fulghum <paulkf@microgate.com>2006-02-10 04:51:14 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-10 11:13:12 -0500
commit8977d929e49021d9a6e031310aab01fa72f849c2 (patch)
tree13697e607b1153666139114242964f9982acc328 /drivers/char
parentf0188f47482efdbd2e005103bb4f0224a835dfad (diff)
[PATCH] tty buffering stall fix
Prevent stalled processing of received data when a driver allocates tty buffer space but does not immediately follow the allocation with more data and a call to schedule receive tty processing. (example: hvc_console) This bug was introduced by the first locking patch for the new tty buffering. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/tty_io.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 076e07c1da38..a23816d3e9a1 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -268,6 +268,8 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
268 p->size = size; 268 p->size = size;
269 p->next = NULL; 269 p->next = NULL;
270 p->active = 0; 270 p->active = 0;
271 p->commit = 0;
272 p->read = 0;
271 p->char_buf_ptr = (char *)(p->data); 273 p->char_buf_ptr = (char *)(p->data);
272 p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; 274 p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
273/* printk("Flip create %p\n", p); */ 275/* printk("Flip create %p\n", p); */
@@ -298,6 +300,8 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
298 *tbh = t->next; 300 *tbh = t->next;
299 t->next = NULL; 301 t->next = NULL;
300 t->used = 0; 302 t->used = 0;
303 t->commit = 0;
304 t->read = 0;
301 /* DEBUG ONLY */ 305 /* DEBUG ONLY */
302 memset(t->data, '*', size); 306 memset(t->data, '*', size);
303/* printk("Flip recycle %p\n", t); */ 307/* printk("Flip recycle %p\n", t); */
@@ -335,6 +339,7 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
335 if (b != NULL) { 339 if (b != NULL) {
336 b->next = n; 340 b->next = n;
337 b->active = 0; 341 b->active = 0;
342 b->commit = b->used;
338 } else 343 } else
339 tty->buf.head = n; 344 tty->buf.head = n;
340 tty->buf.tail = n; 345 tty->buf.tail = n;
@@ -2752,6 +2757,9 @@ static void flush_to_ldisc(void *private_)
2752 unsigned long flags; 2757 unsigned long flags;
2753 struct tty_ldisc *disc; 2758 struct tty_ldisc *disc;
2754 struct tty_buffer *tbuf; 2759 struct tty_buffer *tbuf;
2760 int count;
2761 char *char_buf;
2762 unsigned char *flag_buf;
2755 2763
2756 disc = tty_ldisc_ref(tty); 2764 disc = tty_ldisc_ref(tty);
2757 if (disc == NULL) /* !TTY_LDISC */ 2765 if (disc == NULL) /* !TTY_LDISC */
@@ -2765,16 +2773,20 @@ static void flush_to_ldisc(void *private_)
2765 goto out; 2773 goto out;
2766 } 2774 }
2767 spin_lock_irqsave(&tty->buf.lock, flags); 2775 spin_lock_irqsave(&tty->buf.lock, flags);
2768 while((tbuf = tty->buf.head) != NULL && !tbuf->active) { 2776 while((tbuf = tty->buf.head) != NULL) {
2777 while ((count = tbuf->commit - tbuf->read) != 0) {
2778 char_buf = tbuf->char_buf_ptr + tbuf->read;
2779 flag_buf = tbuf->flag_buf_ptr + tbuf->read;
2780 tbuf->read += count;
2781 spin_unlock_irqrestore(&tty->buf.lock, flags);
2782 disc->receive_buf(tty, char_buf, flag_buf, count);
2783 spin_lock_irqsave(&tty->buf.lock, flags);
2784 }
2785 if (tbuf->active)
2786 break;
2769 tty->buf.head = tbuf->next; 2787 tty->buf.head = tbuf->next;
2770 if (tty->buf.head == NULL) 2788 if (tty->buf.head == NULL)
2771 tty->buf.tail = NULL; 2789 tty->buf.tail = NULL;
2772 spin_unlock_irqrestore(&tty->buf.lock, flags);
2773 /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */
2774 disc->receive_buf(tty, tbuf->char_buf_ptr,
2775 tbuf->flag_buf_ptr,
2776 tbuf->used);
2777 spin_lock_irqsave(&tty->buf.lock, flags);
2778 tty_buffer_free(tty, tbuf); 2790 tty_buffer_free(tty, tbuf);
2779 } 2791 }
2780 spin_unlock_irqrestore(&tty->buf.lock, flags); 2792 spin_unlock_irqrestore(&tty->buf.lock, flags);
@@ -2871,8 +2883,10 @@ void tty_flip_buffer_push(struct tty_struct *tty)
2871{ 2883{
2872 unsigned long flags; 2884 unsigned long flags;
2873 spin_lock_irqsave(&tty->buf.lock, flags); 2885 spin_lock_irqsave(&tty->buf.lock, flags);
2874 if (tty->buf.tail != NULL) 2886 if (tty->buf.tail != NULL) {
2875 tty->buf.tail->active = 0; 2887 tty->buf.tail->active = 0;
2888 tty->buf.tail->commit = tty->buf.tail->used;
2889 }
2876 spin_unlock_irqrestore(&tty->buf.lock, flags); 2890 spin_unlock_irqrestore(&tty->buf.lock, flags);
2877 2891
2878 if (tty->low_latency) 2892 if (tty->low_latency)