From: Martin Schwidefsky SCLP console/tty fixes: - Fix incorrect state change of SCLP_RUNNING flag in interrupt handler - Suppress emission of empty buffers to prevent stack overflow - Fix off by one error in sclp_write (used to return # of chars written + 1) - Prevent sclp_tty_write_string from waiting in interrupt (during flush) - Fix deadlock after TIOCSCLPSNL ioctl - Fix sclp_tty_chars_in_buffer calculation --- 25-akpm/drivers/s390/char/sclp.c | 5 +++-- 25-akpm/drivers/s390/char/sclp_con.c | 3 ++- 25-akpm/drivers/s390/char/sclp_rw.c | 2 +- 25-akpm/drivers/s390/char/sclp_tty.c | 24 ++++++++++++++++++------ 4 files changed, 24 insertions(+), 10 deletions(-) diff -puN drivers/s390/char/sclp.c~s390-sclp-fixes drivers/s390/char/sclp.c --- 25/drivers/s390/char/sclp.c~s390-sclp-fixes Wed Jan 28 13:13:06 2004 +++ 25-akpm/drivers/s390/char/sclp.c Wed Jan 28 13:13:06 2004 @@ -315,8 +315,9 @@ sclp_interrupt_handler(struct pt_regs *r /* Head queue a read sccb if an event buffer is pending */ if (evbuf_pending) __sclp_unconditional_read(); - /* Now clear the running bit */ - clear_bit(SCLP_RUNNING, &sclp_status); + /* Now clear the running bit if SCLP indicated a finished SCCB */ + if (finished_sccb != 0U) + clear_bit(SCLP_RUNNING, &sclp_status); spin_unlock(&sclp_lock); /* and start next request on the queue */ sclp_start_request(); diff -puN drivers/s390/char/sclp_con.c~s390-sclp-fixes drivers/s390/char/sclp_con.c --- 25/drivers/s390/char/sclp_con.c~s390-sclp-fixes Wed Jan 28 13:13:06 2004 +++ 25-akpm/drivers/s390/char/sclp_con.c Wed Jan 28 13:13:06 2004 @@ -149,7 +149,8 @@ sclp_console_write(struct console *conso count -= written; } while (count > 0); /* Setup timer to output current console buffer after 1/10 second */ - if (sclp_conbuf != NULL && !timer_pending(&sclp_con_timer)) { + if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 && + !timer_pending(&sclp_con_timer)) { init_timer(&sclp_con_timer); sclp_con_timer.function = sclp_console_timeout; sclp_con_timer.data = 0UL; diff -puN drivers/s390/char/sclp_rw.c~s390-sclp-fixes drivers/s390/char/sclp_rw.c --- 25/drivers/s390/char/sclp_rw.c~s390-sclp-fixes Wed Jan 28 13:13:06 2004 +++ 25-akpm/drivers/s390/char/sclp_rw.c Wed Jan 28 13:13:06 2004 @@ -274,7 +274,7 @@ sclp_write(struct sclp_buffer *buffer, c if (buffer->current_line != NULL) sclp_finalize_mto(buffer); /* skip the rest of the message including the 0 byte */ - i_msg = count; + i_msg = count - 1; break; default: /* no escape character */ /* do not output unprintable characters */ diff -puN drivers/s390/char/sclp_tty.c~s390-sclp-fixes drivers/s390/char/sclp_tty.c --- 25/drivers/s390/char/sclp_tty.c~s390-sclp-fixes Wed Jan 28 13:13:06 2004 +++ 25-akpm/drivers/s390/char/sclp_tty.c Wed Jan 28 13:13:06 2004 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "ctrlchar.h" @@ -337,8 +338,11 @@ sclp_tty_write_string(const unsigned cha if (sclp_ttybuf == NULL) { while (list_empty(&sclp_tty_pages)) { spin_unlock_irqrestore(&sclp_tty_lock, flags); - wait_event(sclp_tty_waitq, - !list_empty(&sclp_tty_pages)); + if (in_interrupt()) + sclp_sync_wait(); + else + wait_event(sclp_tty_waitq, + !list_empty(&sclp_tty_pages)); spin_lock_irqsave(&sclp_tty_lock, flags); } page = sclp_tty_pages.next; @@ -366,7 +370,9 @@ sclp_tty_write_string(const unsigned cha } while (count > 0); /* Setup timer to output current console buffer after 1/10 second */ if (sclp_ioctls.final_nl) { - if (sclp_ttybuf != NULL && !timer_pending(&sclp_tty_timer)) { + if (sclp_ttybuf != NULL && + sclp_chars_in_buffer(sclp_ttybuf) != 0 && + !timer_pending(&sclp_tty_timer)) { init_timer(&sclp_tty_timer); sclp_tty_timer.function = sclp_tty_timeout; sclp_tty_timer.data = 0UL; @@ -374,8 +380,14 @@ sclp_tty_write_string(const unsigned cha add_timer(&sclp_tty_timer); } } else { - __sclp_ttybuf_emit(sclp_ttybuf); - sclp_ttybuf = NULL; + if (sclp_ttybuf != NULL && + sclp_chars_in_buffer(sclp_ttybuf) != 0) { + buf = sclp_ttybuf; + sclp_ttybuf = NULL; + spin_unlock_irqrestore(&sclp_tty_lock, flags); + __sclp_ttybuf_emit(buf); + spin_lock_irqsave(&sclp_tty_lock, flags); + } } spin_unlock_irqrestore(&sclp_tty_lock, flags); } @@ -471,7 +483,7 @@ sclp_tty_chars_in_buffer(struct tty_stru count = sclp_chars_in_buffer(sclp_ttybuf); list_for_each(l, &sclp_tty_outqueue) { t = list_entry(l, struct sclp_buffer, list); - count += sclp_chars_in_buffer(sclp_ttybuf); + count += sclp_chars_in_buffer(t); } spin_unlock_irqrestore(&sclp_tty_lock, flags); return count; _