Commit e7d1d6cd authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: sclp bug fixes.

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
parent e4f06bee
......@@ -315,7 +315,8 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
/* Head queue a read sccb if an event buffer is pending */
if (evbuf_pending)
__sclp_unconditional_read();
/* Now clear the running bit */
/* 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 */
......
......@@ -149,7 +149,8 @@ sclp_console_write(struct console *console, const char *message,
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;
......
......@@ -274,7 +274,7 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
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 */
......
......@@ -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,6 +338,9 @@ sclp_tty_write_string(const unsigned char *str, int count)
if (sclp_ttybuf == NULL) {
while (list_empty(&sclp_tty_pages)) {
spin_unlock_irqrestore(&sclp_tty_lock, flags);
if (in_interrupt())
sclp_sync_wait();
else
wait_event(sclp_tty_waitq,
!list_empty(&sclp_tty_pages));
spin_lock_irqsave(&sclp_tty_lock, flags);
......@@ -366,7 +370,9 @@ sclp_tty_write_string(const unsigned char *str, int count)
} 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 char *str, int count)
add_timer(&sclp_tty_timer);
}
} else {
__sclp_ttybuf_emit(sclp_ttybuf);
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_struct *tty)
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment