aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hvc_console.c
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2008-10-13 19:12:50 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-21 19:59:55 -0400
commit3feebbb5492e9e463467cefb633e23a3dfcec132 (patch)
treeaab5c73bbcd799781b8b27f7173c3e726ea403be /drivers/char/hvc_console.c
parent56ce9e2b2463b3b257098aa966586701d9967f1e (diff)
hvc_console: Fix loop if put_char() returns 0
If put_char() routine of a hvc console backend returns 0, then the hvc console starts looping in the following scenarios: 1. hvc_console_print() If put_char() returns 0 then the while loop may loop forever. I have added the missing check for 0 to throw away console messages. 2. khvcd may loop: The thread calls hvc_poll() --> hvc_push()... if there are still buffered data then the HVC_POLL_WRITE bit is set and causes the khvcd thread to loop (if yield() returns immediately). However, instead of looping, the khvcd thread could sleep for MIN_TIMEOUT (doing the same as for get_chars()). The MIN_TIMEOUT is set if hvc_push() was not able to write data to the backend. If data has been written, the timeout is set to 0 to immediately re-schedule hvc_poll(). Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> Tested-by: Christian Borntraeger <borntraeger@de.ibm.com> (virtio_console) Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/char/hvc_console.c')
-rw-r--r--drivers/char/hvc_console.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index c9d16665c960..3650c904401e 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -161,7 +161,7 @@ static void hvc_console_print(struct console *co, const char *b,
161 } 161 }
162 } else { 162 } else {
163 r = cons_ops[index]->put_chars(vtermnos[index], c, i); 163 r = cons_ops[index]->put_chars(vtermnos[index], c, i);
164 if (r < 0) { 164 if (r <= 0) {
165 /* throw away chars on error */ 165 /* throw away chars on error */
166 i = 0; 166 i = 0;
167 } else if (r > 0) { 167 } else if (r > 0) {
@@ -431,7 +431,7 @@ static void hvc_hangup(struct tty_struct *tty)
431 * Push buffered characters whether they were just recently buffered or waiting 431 * Push buffered characters whether they were just recently buffered or waiting
432 * on a blocked hypervisor. Call this function with hp->lock held. 432 * on a blocked hypervisor. Call this function with hp->lock held.
433 */ 433 */
434static void hvc_push(struct hvc_struct *hp) 434static int hvc_push(struct hvc_struct *hp)
435{ 435{
436 int n; 436 int n;
437 437
@@ -439,7 +439,7 @@ static void hvc_push(struct hvc_struct *hp)
439 if (n <= 0) { 439 if (n <= 0) {
440 if (n == 0) { 440 if (n == 0) {
441 hp->do_wakeup = 1; 441 hp->do_wakeup = 1;
442 return; 442 return 0;
443 } 443 }
444 /* throw away output on error; this happens when 444 /* throw away output on error; this happens when
445 there is no session connected to the vterm. */ 445 there is no session connected to the vterm. */
@@ -450,6 +450,8 @@ static void hvc_push(struct hvc_struct *hp)
450 memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf); 450 memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
451 else 451 else
452 hp->do_wakeup = 1; 452 hp->do_wakeup = 1;
453
454 return n;
453} 455}
454 456
455static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) 457static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -538,16 +540,20 @@ int hvc_poll(struct hvc_struct *hp)
538 char buf[N_INBUF] __ALIGNED__; 540 char buf[N_INBUF] __ALIGNED__;
539 unsigned long flags; 541 unsigned long flags;
540 int read_total = 0; 542 int read_total = 0;
543 int written_total = 0;
541 544
542 spin_lock_irqsave(&hp->lock, flags); 545 spin_lock_irqsave(&hp->lock, flags);
543 546
544 /* Push pending writes */ 547 /* Push pending writes */
545 if (hp->n_outbuf > 0) 548 if (hp->n_outbuf > 0)
546 hvc_push(hp); 549 written_total = hvc_push(hp);
547 550
548 /* Reschedule us if still some write pending */ 551 /* Reschedule us if still some write pending */
549 if (hp->n_outbuf > 0) 552 if (hp->n_outbuf > 0) {
550 poll_mask |= HVC_POLL_WRITE; 553 poll_mask |= HVC_POLL_WRITE;
554 /* If hvc_push() was not able to write, sleep a few msecs */
555 timeout = (written_total) ? 0 : MIN_TIMEOUT;
556 }
551 557
552 /* No tty attached, just skip */ 558 /* No tty attached, just skip */
553 tty = hp->tty; 559 tty = hp->tty;
@@ -659,10 +665,6 @@ static int khvcd(void *unused)
659 poll_mask |= HVC_POLL_READ; 665 poll_mask |= HVC_POLL_READ;
660 if (hvc_kicked) 666 if (hvc_kicked)
661 continue; 667 continue;
662 if (poll_mask & HVC_POLL_WRITE) {
663 yield();
664 continue;
665 }
666 set_current_state(TASK_INTERRUPTIBLE); 668 set_current_state(TASK_INTERRUPTIBLE);
667 if (!hvc_kicked) { 669 if (!hvc_kicked) {
668 if (poll_mask == 0) 670 if (poll_mask == 0)