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) ...@@ -315,7 +315,8 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
/* Head queue a read sccb if an event buffer is pending */ /* Head queue a read sccb if an event buffer is pending */
if (evbuf_pending) if (evbuf_pending)
__sclp_unconditional_read(); __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); clear_bit(SCLP_RUNNING, &sclp_status);
spin_unlock(&sclp_lock); spin_unlock(&sclp_lock);
/* and start next request on the queue */ /* and start next request on the queue */
......
...@@ -149,7 +149,8 @@ sclp_console_write(struct console *console, const char *message, ...@@ -149,7 +149,8 @@ sclp_console_write(struct console *console, const char *message,
count -= written; count -= written;
} while (count > 0); } while (count > 0);
/* Setup timer to output current console buffer after 1/10 second */ /* 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); init_timer(&sclp_con_timer);
sclp_con_timer.function = sclp_console_timeout; sclp_con_timer.function = sclp_console_timeout;
sclp_con_timer.data = 0UL; sclp_con_timer.data = 0UL;
......
...@@ -274,7 +274,7 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count) ...@@ -274,7 +274,7 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
if (buffer->current_line != NULL) if (buffer->current_line != NULL)
sclp_finalize_mto(buffer); sclp_finalize_mto(buffer);
/* skip the rest of the message including the 0 byte */ /* skip the rest of the message including the 0 byte */
i_msg = count; i_msg = count - 1;
break; break;
default: /* no escape character */ default: /* no escape character */
/* do not output unprintable characters */ /* do not output unprintable characters */
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "ctrlchar.h" #include "ctrlchar.h"
...@@ -337,6 +338,9 @@ sclp_tty_write_string(const unsigned char *str, int count) ...@@ -337,6 +338,9 @@ sclp_tty_write_string(const unsigned char *str, int count)
if (sclp_ttybuf == NULL) { if (sclp_ttybuf == NULL) {
while (list_empty(&sclp_tty_pages)) { while (list_empty(&sclp_tty_pages)) {
spin_unlock_irqrestore(&sclp_tty_lock, flags); spin_unlock_irqrestore(&sclp_tty_lock, flags);
if (in_interrupt())
sclp_sync_wait();
else
wait_event(sclp_tty_waitq, wait_event(sclp_tty_waitq,
!list_empty(&sclp_tty_pages)); !list_empty(&sclp_tty_pages));
spin_lock_irqsave(&sclp_tty_lock, flags); spin_lock_irqsave(&sclp_tty_lock, flags);
...@@ -366,7 +370,9 @@ sclp_tty_write_string(const unsigned char *str, int count) ...@@ -366,7 +370,9 @@ sclp_tty_write_string(const unsigned char *str, int count)
} while (count > 0); } while (count > 0);
/* Setup timer to output current console buffer after 1/10 second */ /* Setup timer to output current console buffer after 1/10 second */
if (sclp_ioctls.final_nl) { 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); init_timer(&sclp_tty_timer);
sclp_tty_timer.function = sclp_tty_timeout; sclp_tty_timer.function = sclp_tty_timeout;
sclp_tty_timer.data = 0UL; sclp_tty_timer.data = 0UL;
...@@ -374,8 +380,14 @@ sclp_tty_write_string(const unsigned char *str, int count) ...@@ -374,8 +380,14 @@ sclp_tty_write_string(const unsigned char *str, int count)
add_timer(&sclp_tty_timer); add_timer(&sclp_tty_timer);
} }
} else { } else {
__sclp_ttybuf_emit(sclp_ttybuf); if (sclp_ttybuf != NULL &&
sclp_chars_in_buffer(sclp_ttybuf) != 0) {
buf = sclp_ttybuf;
sclp_ttybuf = NULL; 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); spin_unlock_irqrestore(&sclp_tty_lock, flags);
} }
...@@ -471,7 +483,7 @@ sclp_tty_chars_in_buffer(struct tty_struct *tty) ...@@ -471,7 +483,7 @@ sclp_tty_chars_in_buffer(struct tty_struct *tty)
count = sclp_chars_in_buffer(sclp_ttybuf); count = sclp_chars_in_buffer(sclp_ttybuf);
list_for_each(l, &sclp_tty_outqueue) { list_for_each(l, &sclp_tty_outqueue) {
t = list_entry(l, struct sclp_buffer, list); 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); spin_unlock_irqrestore(&sclp_tty_lock, flags);
return count; 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