[S390] console flush on panic / reboot
The s390 console drivers use the unblank callback of the console structure to flush the console buffer. In case of a panic or a reboot the CPU doing the callback can block on the console i/o. The other CPUs in the system continue to work. For panic this is not a good idea. Replace the unblank callback with proper panic/reboot notifier. These get called after all but one CPU have been stopped. Signed-off-by: Holger Smolinski <Holger.Smolinski@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
committed by
Martin Schwidefsky
parent
15e86b0c75
commit
2332ce1a97
@@ -21,6 +21,7 @@
|
|||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
@@ -775,11 +776,11 @@ static struct tty_driver *con3215_device(struct console *c, int *index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* panic() calls console_unblank before the system enters a
|
* panic() calls con3215_flush through a panic_notifier
|
||||||
* disabled, endless loop.
|
* before the system enters a disabled, endless loop.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
con3215_unblank(void)
|
con3215_flush(void)
|
||||||
{
|
{
|
||||||
struct raw3215_info *raw;
|
struct raw3215_info *raw;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -790,6 +791,23 @@ con3215_unblank(void)
|
|||||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int con3215_notify(struct notifier_block *self,
|
||||||
|
unsigned long event, void *data)
|
||||||
|
{
|
||||||
|
con3215_flush();
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block on_panic_nb = {
|
||||||
|
.notifier_call = con3215_notify,
|
||||||
|
.priority = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct notifier_block on_reboot_nb = {
|
||||||
|
.notifier_call = con3215_notify,
|
||||||
|
.priority = 0,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The console structure for the 3215 console
|
* The console structure for the 3215 console
|
||||||
*/
|
*/
|
||||||
@@ -797,7 +815,6 @@ static struct console con3215 = {
|
|||||||
.name = "ttyS",
|
.name = "ttyS",
|
||||||
.write = con3215_write,
|
.write = con3215_write,
|
||||||
.device = con3215_device,
|
.device = con3215_device,
|
||||||
.unblank = con3215_unblank,
|
|
||||||
.flags = CON_PRINTBUFFER,
|
.flags = CON_PRINTBUFFER,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -859,6 +876,8 @@ con3215_init(void)
|
|||||||
raw3215[0] = NULL;
|
raw3215[0] = NULL;
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
|
||||||
|
register_reboot_notifier(&on_reboot_nb);
|
||||||
register_console(&con3215);
|
register_console(&con3215);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
#include <asm/ccwdev.h>
|
#include <asm/ccwdev.h>
|
||||||
#include <asm/cio.h>
|
#include <asm/cio.h>
|
||||||
@@ -528,11 +529,11 @@ con3270_wait_write(struct con3270 *cp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* panic() calls console_unblank before the system enters a
|
* panic() calls con3270_flush through a panic_notifier
|
||||||
* disabled, endless loop.
|
* before the system enters a disabled, endless loop.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
con3270_unblank(void)
|
con3270_flush(void)
|
||||||
{
|
{
|
||||||
struct con3270 *cp;
|
struct con3270 *cp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -554,6 +555,23 @@ con3270_unblank(void)
|
|||||||
spin_unlock_irqrestore(&cp->view.lock, flags);
|
spin_unlock_irqrestore(&cp->view.lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int con3270_notify(struct notifier_block *self,
|
||||||
|
unsigned long event, void *data)
|
||||||
|
{
|
||||||
|
con3270_flush();
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block on_panic_nb = {
|
||||||
|
.notifier_call = con3270_notify,
|
||||||
|
.priority = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct notifier_block on_reboot_nb = {
|
||||||
|
.notifier_call = con3270_notify,
|
||||||
|
.priority = 0,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The console structure for the 3270 console
|
* The console structure for the 3270 console
|
||||||
*/
|
*/
|
||||||
@@ -561,7 +579,6 @@ static struct console con3270 = {
|
|||||||
.name = "tty3270",
|
.name = "tty3270",
|
||||||
.write = con3270_write,
|
.write = con3270_write,
|
||||||
.device = con3270_device,
|
.device = con3270_device,
|
||||||
.unblank = con3270_unblank,
|
|
||||||
.flags = CON_PRINTBUFFER,
|
.flags = CON_PRINTBUFFER,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -623,6 +640,8 @@ con3270_init(void)
|
|||||||
condev->cline->len = 0;
|
condev->cline->len = 0;
|
||||||
con3270_create_status(condev);
|
con3270_create_status(condev);
|
||||||
condev->input = alloc_string(&condev->freemem, 80);
|
condev->input = alloc_string(&condev->freemem, 80);
|
||||||
|
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
|
||||||
|
register_reboot_notifier(&on_reboot_nb);
|
||||||
register_console(&con3270);
|
register_console(&con3270);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
#include <linux/termios.h>
|
#include <linux/termios.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
#include "sclp.h"
|
#include "sclp.h"
|
||||||
#include "sclp_rw.h"
|
#include "sclp_rw.h"
|
||||||
@@ -172,7 +173,7 @@ sclp_console_device(struct console *c, int *index)
|
|||||||
* will be flushed to the SCLP.
|
* will be flushed to the SCLP.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sclp_console_unblank(void)
|
sclp_console_flush(void)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
@@ -188,6 +189,24 @@ sclp_console_unblank(void)
|
|||||||
spin_unlock_irqrestore(&sclp_con_lock, flags);
|
spin_unlock_irqrestore(&sclp_con_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sclp_console_notify(struct notifier_block *self,
|
||||||
|
unsigned long event, void *data)
|
||||||
|
{
|
||||||
|
sclp_console_flush();
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block on_panic_nb = {
|
||||||
|
.notifier_call = sclp_console_notify,
|
||||||
|
.priority = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct notifier_block on_reboot_nb = {
|
||||||
|
.notifier_call = sclp_console_notify,
|
||||||
|
.priority = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* used to register the SCLP console to the kernel and to
|
* used to register the SCLP console to the kernel and to
|
||||||
* give printk necessary information
|
* give printk necessary information
|
||||||
@@ -197,7 +216,6 @@ static struct console sclp_console =
|
|||||||
.name = sclp_console_name,
|
.name = sclp_console_name,
|
||||||
.write = sclp_console_write,
|
.write = sclp_console_write,
|
||||||
.device = sclp_console_device,
|
.device = sclp_console_device,
|
||||||
.unblank = sclp_console_unblank,
|
|
||||||
.flags = CON_PRINTBUFFER,
|
.flags = CON_PRINTBUFFER,
|
||||||
.index = 0 /* ttyS0 */
|
.index = 0 /* ttyS0 */
|
||||||
};
|
};
|
||||||
@@ -241,6 +259,8 @@ sclp_console_init(void)
|
|||||||
sclp_con_width_htab = 8;
|
sclp_con_width_htab = 8;
|
||||||
|
|
||||||
/* enable printk-access to this driver */
|
/* enable printk-access to this driver */
|
||||||
|
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
|
||||||
|
register_reboot_notifier(&on_reboot_nb);
|
||||||
register_console(&sclp_console);
|
register_console(&sclp_console);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,8 @@
|
|||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include "sclp.h"
|
#include "sclp.h"
|
||||||
|
|
||||||
@@ -743,24 +745,30 @@ sclp_vt220_con_device(struct console *c, int *index)
|
|||||||
return sclp_vt220_driver;
|
return sclp_vt220_driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int
|
||||||
* This routine is called from panic when the kernel is going to give up.
|
sclp_vt220_notify(struct notifier_block *self,
|
||||||
* We have to make sure that all buffers will be flushed to the SCLP.
|
unsigned long event, void *data)
|
||||||
* Note that this function may be called from within an interrupt context.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
sclp_vt220_con_unblank(void)
|
|
||||||
{
|
{
|
||||||
__sclp_vt220_flush_buffer();
|
__sclp_vt220_flush_buffer();
|
||||||
|
return NOTIFY_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct notifier_block on_panic_nb = {
|
||||||
|
.notifier_call = sclp_vt220_notify,
|
||||||
|
.priority = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct notifier_block on_reboot_nb = {
|
||||||
|
.notifier_call = sclp_vt220_notify,
|
||||||
|
.priority = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/* Structure needed to register with printk */
|
/* Structure needed to register with printk */
|
||||||
static struct console sclp_vt220_console =
|
static struct console sclp_vt220_console =
|
||||||
{
|
{
|
||||||
.name = SCLP_VT220_CONSOLE_NAME,
|
.name = SCLP_VT220_CONSOLE_NAME,
|
||||||
.write = sclp_vt220_con_write,
|
.write = sclp_vt220_con_write,
|
||||||
.device = sclp_vt220_con_device,
|
.device = sclp_vt220_con_device,
|
||||||
.unblank = sclp_vt220_con_unblank,
|
|
||||||
.flags = CON_PRINTBUFFER,
|
.flags = CON_PRINTBUFFER,
|
||||||
.index = SCLP_VT220_CONSOLE_INDEX
|
.index = SCLP_VT220_CONSOLE_INDEX
|
||||||
};
|
};
|
||||||
@@ -776,6 +784,8 @@ sclp_vt220_con_init(void)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
/* Attach linux console */
|
/* Attach linux console */
|
||||||
|
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
|
||||||
|
register_reboot_notifier(&on_reboot_nb);
|
||||||
register_console(&sclp_vt220_console);
|
register_console(&sclp_vt220_console);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user