Commit 464f3583 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: debug feature system control

From: Christian Borntraeger <cborntra@de.ibm.com>

Debug feature changes:
 - Add system control to stop the debug feature.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 40221738
...@@ -78,6 +78,23 @@ Example: ...@@ -78,6 +78,23 @@ Example:
> echo "-" > /proc/s390dbf/dasd/level > echo "-" > /proc/s390dbf/dasd/level
It is also possible to deactivate the debug feature globally for every
debug log. You can change the behavior using 2 sysctl parameters in
/proc/sys/s390dbf:
There are currently 2 possible triggers, which stop the debug feature
globally. The first possbility is to use the "debug_active" sysctl. If
set to 1 the debug feature is running. If "debug_active" is set to 0 the
debug feature is turned off.
The second trigger which stops the debug feature is an kernel oops.
That prevents the debug feature from overwriting debug information that
happened before the oops. After an oops you can reactivate the debug feature
by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not
suggested to use an oopsed kernel in an production environment.
If you want to disallow the deactivation of the debug feature, you can use
the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug
feature cannot be stopped. If the debug feature is already stopped, it
will stay deactivated.
Kernel Interfaces: Kernel Interfaces:
------------------ ------------------
...@@ -115,6 +132,17 @@ Parameter: id: handle for debug log ...@@ -115,6 +132,17 @@ Parameter: id: handle for debug log
Return Value: none Return Value: none
Description: Sets new actual debug level if new_level is valid. Description: Sets new actual debug level if new_level is valid.
---------------------------------------------------------------------------
+void debug_stop_all(void);
Parameter: none
Return Value: none
Description: stops the debug feature if stopping is allowed. Currently
used in case of a kernel oops.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
debug_entry_t* debug_event (debug_info_t* id, int level, void* data, debug_entry_t* debug_event (debug_info_t* id, int level, void* data,
int length); int length);
...@@ -377,6 +405,15 @@ Examples: ...@@ -377,6 +405,15 @@ Examples:
2. Flush all debug areas: 2. Flush all debug areas:
> echo "-" > /proc/s390dbf/dasd/flush > echo "-" > /proc/s390dbf/dasd/flush
Stooping the debug feature
--------------------------
Example:
1. Check if stopping is allowed
> cat /proc/sys/s390dbf/debug_stoppable
2. Stop debug feature
> echo 0 > /proc/sys/s390dbf/debug_active
lcrash Interface lcrash Interface
---------------- ----------------
It is planned that the dump analysis tool lcrash gets an additional command It is planned that the dump analysis tool lcrash gets an additional command
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/sysctl.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
...@@ -708,6 +709,70 @@ extern inline void debug_finish_entry(debug_info_t * id, debug_entry_t* active, ...@@ -708,6 +709,70 @@ extern inline void debug_finish_entry(debug_info_t * id, debug_entry_t* active,
proceed_active_area(id); proceed_active_area(id);
} }
static int debug_stoppable=1;
static int debug_active=1;
#define CTL_S390DBF 5677
#define CTL_S390DBF_STOPPABLE 5678
#define CTL_S390DBF_ACTIVE 5679
/*
* proc handler for the running debug_active sysctl
* always allow read, allow write only if debug_stoppable is set or
* if debug_active is already off
*/
static int s390dbf_procactive(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
if (!write || debug_stoppable || !debug_active)
return proc_dointvec(table, write, filp, buffer, lenp, ppos);
else
return 0;
}
static struct ctl_table s390dbf_table[] = {
{
.ctl_name = CTL_S390DBF_STOPPABLE,
.procname = "debug_stoppable",
.data = &debug_stoppable,
.maxlen = sizeof(int),
.mode = S_IRUGO | S_IWUSR,
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec,
},
{
.ctl_name = CTL_S390DBF_ACTIVE,
.procname = "debug_active",
.data = &debug_active,
.maxlen = sizeof(int),
.mode = S_IRUGO | S_IWUSR,
.proc_handler = &s390dbf_procactive,
.strategy = &sysctl_intvec,
},
{ .ctl_name = 0 }
};
static struct ctl_table s390dbf_dir_table[] = {
{
.ctl_name = CTL_S390DBF,
.procname = "s390dbf",
.maxlen = 0,
.mode = S_IRUGO | S_IXUGO,
.child = s390dbf_table,
},
{ .ctl_name = 0 }
};
struct ctl_table_header *s390dbf_sysctl_header;
void debug_stop_all(void)
{
if (debug_stoppable)
debug_active = 0;
}
/* /*
* debug_event_common: * debug_event_common:
* - write debug entry with given size * - write debug entry with given size
...@@ -719,6 +784,8 @@ debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf, ...@@ -719,6 +784,8 @@ debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
unsigned long flags; unsigned long flags;
debug_entry_t *active; debug_entry_t *active;
if (!debug_active)
return NULL;
spin_lock_irqsave(&id->lock, flags); spin_lock_irqsave(&id->lock, flags);
active = get_active_entry(id); active = get_active_entry(id);
memset(DEBUG_DATA(active), 0, id->buf_size); memset(DEBUG_DATA(active), 0, id->buf_size);
...@@ -740,6 +807,8 @@ debug_entry_t *debug_exception_common(debug_info_t * id, int level, ...@@ -740,6 +807,8 @@ debug_entry_t *debug_exception_common(debug_info_t * id, int level,
unsigned long flags; unsigned long flags;
debug_entry_t *active; debug_entry_t *active;
if (!debug_active)
return NULL;
spin_lock_irqsave(&id->lock, flags); spin_lock_irqsave(&id->lock, flags);
active = get_active_entry(id); active = get_active_entry(id);
memset(DEBUG_DATA(active), 0, id->buf_size); memset(DEBUG_DATA(active), 0, id->buf_size);
...@@ -780,7 +849,8 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id, ...@@ -780,7 +849,8 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id,
if((!id) || (level > id->level)) if((!id) || (level > id->level))
return NULL; return NULL;
if (!debug_active)
return NULL;
numargs=debug_count_numargs(string); numargs=debug_count_numargs(string);
spin_lock_irqsave(&id->lock, flags); spin_lock_irqsave(&id->lock, flags);
...@@ -812,6 +882,8 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id, ...@@ -812,6 +882,8 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
if((!id) || (level > id->level)) if((!id) || (level > id->level))
return NULL; return NULL;
if (!debug_active)
return NULL;
numargs=debug_count_numargs(string); numargs=debug_count_numargs(string);
...@@ -838,6 +910,7 @@ static int __init debug_init(void) ...@@ -838,6 +910,7 @@ static int __init debug_init(void)
{ {
int rc = 0; int rc = 0;
s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table, 1);
down(&debug_lock); down(&debug_lock);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL); debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
...@@ -1186,6 +1259,7 @@ void __exit debug_exit(void) ...@@ -1186,6 +1259,7 @@ void __exit debug_exit(void)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
remove_proc_entry(debug_proc_root_entry->name, NULL); remove_proc_entry(debug_proc_root_entry->name, NULL);
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
unregister_sysctl_table(s390dbf_sysctl_header);
return; return;
} }
...@@ -1199,6 +1273,7 @@ MODULE_LICENSE("GPL"); ...@@ -1199,6 +1273,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register); EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister); EXPORT_SYMBOL(debug_unregister);
EXPORT_SYMBOL(debug_set_level); EXPORT_SYMBOL(debug_set_level);
EXPORT_SYMBOL(debug_stop_all);
EXPORT_SYMBOL(debug_register_view); EXPORT_SYMBOL(debug_register_view);
EXPORT_SYMBOL(debug_unregister_view); EXPORT_SYMBOL(debug_unregister_view);
EXPORT_SYMBOL(debug_event_common); EXPORT_SYMBOL(debug_event_common);
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <asm/cpcmd.h> #include <asm/cpcmd.h>
#include <asm/s390_ext.h> #include <asm/s390_ext.h>
#include <asm/lowcore.h> #include <asm/lowcore.h>
#include <asm/debug.h>
/* Called from entry.S only */ /* Called from entry.S only */
extern void handle_per_exception(struct pt_regs *regs); extern void handle_per_exception(struct pt_regs *regs);
...@@ -277,6 +278,8 @@ spinlock_t die_lock = SPIN_LOCK_UNLOCKED; ...@@ -277,6 +278,8 @@ spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
void die(const char * str, struct pt_regs * regs, long err) void die(const char * str, struct pt_regs * regs, long err)
{ {
static int die_counter; static int die_counter;
debug_stop_all();
console_verbose(); console_verbose();
spin_lock_irq(&die_lock); spin_lock_irq(&die_lock);
bust_spinlocks(1); bust_spinlocks(1);
......
...@@ -127,6 +127,8 @@ void debug_unregister(debug_info_t* id); ...@@ -127,6 +127,8 @@ void debug_unregister(debug_info_t* id);
void debug_set_level(debug_info_t* id, int new_level); void debug_set_level(debug_info_t* id, int new_level);
void debug_stop_all(void);
extern inline debug_entry_t* extern inline debug_entry_t*
debug_event(debug_info_t* id, int level, void* data, int length) debug_event(debug_info_t* id, int level, void* data, int length)
{ {
......
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