diff options
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/tty_buffer.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index cc1e9850d65..d8210ca0072 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c | |||
@@ -413,7 +413,8 @@ static void flush_to_ldisc(struct work_struct *work) | |||
413 | spin_lock_irqsave(&tty->buf.lock, flags); | 413 | spin_lock_irqsave(&tty->buf.lock, flags); |
414 | 414 | ||
415 | if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) { | 415 | if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) { |
416 | struct tty_buffer *head; | 416 | struct tty_buffer *head, *tail = tty->buf.tail; |
417 | int seen_tail = 0; | ||
417 | while ((head = tty->buf.head) != NULL) { | 418 | while ((head = tty->buf.head) != NULL) { |
418 | int count; | 419 | int count; |
419 | char *char_buf; | 420 | char *char_buf; |
@@ -423,6 +424,15 @@ static void flush_to_ldisc(struct work_struct *work) | |||
423 | if (!count) { | 424 | if (!count) { |
424 | if (head->next == NULL) | 425 | if (head->next == NULL) |
425 | break; | 426 | break; |
427 | /* | ||
428 | There's a possibility tty might get new buffer | ||
429 | added during the unlock window below. We could | ||
430 | end up spinning in here forever hogging the CPU | ||
431 | completely. To avoid this let's have a rest each | ||
432 | time we processed the tail buffer. | ||
433 | */ | ||
434 | if (tail == head) | ||
435 | seen_tail = 1; | ||
426 | tty->buf.head = head->next; | 436 | tty->buf.head = head->next; |
427 | tty_buffer_free(tty, head); | 437 | tty_buffer_free(tty, head); |
428 | continue; | 438 | continue; |
@@ -432,7 +442,7 @@ static void flush_to_ldisc(struct work_struct *work) | |||
432 | line discipline as we want to empty the queue */ | 442 | line discipline as we want to empty the queue */ |
433 | if (test_bit(TTY_FLUSHPENDING, &tty->flags)) | 443 | if (test_bit(TTY_FLUSHPENDING, &tty->flags)) |
434 | break; | 444 | break; |
435 | if (!tty->receive_room) { | 445 | if (!tty->receive_room || seen_tail) { |
436 | schedule_delayed_work(&tty->buf.work, 1); | 446 | schedule_delayed_work(&tty->buf.work, 1); |
437 | break; | 447 | break; |
438 | } | 448 | } |