From: Martin Schwidefsky <schwidefsky@de.ibm.com>

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 <linux/slab.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <asm/uaccess.h>
 
 #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;

_