* [PATCH 01/14] KDB: fix the interrupt of the KDB btc command
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 02/14] KDB: fix errant character in KDB show regs Mike Travis
` (12 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, David Howells
[-- Attachment #1: kdb-fix-bt-break.patch --]
[-- Type: text/plain, Size: 798 bytes --]
The KDB 'btc' (backtrace cpus) command ignores the 'quit' reply
to the 'more>' prompt. This is quite annoying when you have a
large number of processors and thousands of lines are being
printed. This fixes that problem.
Cc: David Howells <dhowells@redhat.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
kernel/debug/kdb/kdb_bt.c | 2 ++
1 file changed, 2 insertions(+)
--- linux.orig/kernel/debug/kdb/kdb_bt.c
+++ linux/kernel/debug/kdb/kdb_bt.c
@@ -123,6 +123,8 @@ kdb_bt(int argc, const char **argv)
kdb_ps_suppressed();
/* Run the active tasks first */
for_each_online_cpu(cpu) {
+ if (KDB_FLAG(CMD_INTERRUPT))
+ return 0;
p = kdb_curr_task(cpu);
if (kdb_bt1(p, mask, argcount, btaprompt))
return 0;
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 02/14] KDB: fix errant character in KDB show regs
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
2013-03-12 19:38 ` [PATCH 01/14] KDB: fix the interrupt of the KDB btc command Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 03/14] KDB: up the default LINES value Mike Travis
` (11 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Tim Bird
[-- Attachment #1: kdb-fix-show-regs.patch --]
[-- Type: text/plain, Size: 2290 bytes --]
When KDB prints the process regs and backtrace, every line is preceeded
with the character 'd'. This is the level argument to printk which
is not interpreted when KDB is printing. Skip over this possible
printk level in the outgoing string to fix this.
Here is a small sample:
dRIP: 0010:[<ffffffff814e96ca>] [<ffffffff814e96ca>] poll_idle+0x4a/0x90
dRSP: 0018:ffff88081d5eddd8 EFLAGS: 00000246
dRAX: 0000000400000000 RBX: 00000216ae7fbf5d RCX: 0000021658a8e600
dRDX: ffff88081d5ec010 RSI: ffffffff819a7d20 RDI: ffffffff8193c140
Cc: Tim Bird <tim.bird@am.sony.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
kernel/debug/kdb/kdb_io.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
--- linux.orig/kernel/debug/kdb/kdb_io.c
+++ linux/kernel/debug/kdb/kdb_io.c
@@ -559,6 +559,7 @@ int vkdb_printf(const char *fmt, va_list
int retlen = 0;
int fnd, len;
char *cp, *cp2, *cphold = NULL, replaced_byte = ' ';
+ const char *ostring;
char *moreprompt = "more> ";
struct console *c = console_drivers;
static DEFINE_SPINLOCK(kdb_printf_lock);
@@ -690,20 +691,21 @@ kdb_printit:
/*
* Write to all consoles.
*/
- retlen = strlen(kdb_buffer);
+ ostring = printk_skip_level(kdb_buffer);
+ retlen = strlen(ostring);
if (!dbg_kdb_mode && kgdb_connected) {
- gdbstub_msg_write(kdb_buffer, retlen);
+ gdbstub_msg_write(ostring, retlen);
} else {
if (dbg_io_ops && !dbg_io_ops->is_console) {
len = retlen;
- cp = kdb_buffer;
+ cp = (char *)ostring;
while (len--) {
dbg_io_ops->write_char(*cp);
cp++;
}
}
while (c) {
- c->write(c, kdb_buffer, retlen);
+ c->write(c, ostring, retlen);
touch_nmi_watchdog();
c = c->next;
}
@@ -711,7 +713,7 @@ kdb_printit:
if (logging) {
saved_loglevel = console_loglevel;
console_loglevel = 0;
- printk(KERN_INFO "%s", kdb_buffer);
+ pr_info("%s", ostring);
}
if (KDB_STATE(PAGER)) {
@@ -723,10 +725,10 @@ kdb_printit:
int got = 0;
len = retlen;
while (len--) {
- if (kdb_buffer[len] == '\n') {
+ if (ostring[len] == '\n') {
kdb_nextline++;
got = 0;
- } else if (kdb_buffer[len] == '\r') {
+ } else if (ostring[len] == '\r') {
got = 0;
} else {
got++;
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 03/14] KDB: up the default LINES value
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
2013-03-12 19:38 ` [PATCH 01/14] KDB: fix the interrupt of the KDB btc command Mike Travis
2013-03-12 19:38 ` [PATCH 02/14] KDB: fix errant character in KDB show regs Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 04/14] KDB: allow KDB modules to be external modules Mike Travis
` (10 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Tim Bird
[-- Attachment #1: kdb-up-default-lines.patch --]
[-- Type: text/plain, Size: 760 bytes --]
Currently the default for the # of lines displayed by the KDB pager
is 24. This does not allow all of the lines for the entry messages,
reg dump and process trace. Increase it to something more reasonable.
Cc: Tim Bird <tim.bird@am.sony.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
kernel/debug/kdb/kdb_io.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- linux.orig/kernel/debug/kdb/kdb_io.c
+++ linux/kernel/debug/kdb/kdb_io.c
@@ -586,7 +586,7 @@ int vkdb_printf(const char *fmt, va_list
diag = kdbgetintenv("LINES", &linecount);
if (diag || linecount <= 1)
- linecount = 24;
+ linecount = 60;
diag = kdbgetintenv("COLUMNS", &colcount);
if (diag || colcount <= 1)
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 04/14] KDB: allow KDB modules to be external modules
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (2 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 03/14] KDB: up the default LINES value Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 05/14] KDB: add more exports for supporting KDB modules Mike Travis
` (9 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Vincent Stehle,
Andrei Warkentin, Anton Vorontsov
[-- Attachment #1: kdb-allow-ext-modules.patch --]
[-- Type: text/plain, Size: 9335 bytes --]
Since KDB modules are not built within the Linux kernel build domain,
symbols needed by them must be available in a header file that is
accessible. This patch moves the significant routines used by KDB
modules to the external kdb.h header file.
Cc: Vincent Stehle <vincent.stehle@laposte.net>
Cc: Andrei Warkentin <andrey.warkentin@gmail.com>
Cc: Anton Vorontsov <anton.vorontsov@linaro.org>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
include/linux/kdb.h | 89 +++++++++++++++++++++++++++++++++++++++++
kernel/debug/debug_core.h | 1
kernel/debug/kdb/kdb_private.h | 79 ------------------------------------
3 files changed, 89 insertions(+), 80 deletions(-)
--- linux.orig/include/linux/kdb.h
+++ linux/include/linux/kdb.h
@@ -25,6 +25,7 @@ typedef int (*kdb_func_t)(int, const cha
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/atomic.h>
+#include <linux/hardirq.h>
#define KDB_POLL_FUNC_MAX 5
extern int kdb_poll_idx;
@@ -148,6 +149,93 @@ extern int kdb_register(char *, kdb_func
extern int kdb_register_repeat(char *, kdb_func_t, char *, char *,
short, kdb_repeat_t);
extern int kdb_unregister(char *);
+
+/*
+ * Exported Symbols for kernel loadable modules to use.
+ *
+ * (All of these need to be within an #ifdef CONFIG_KGDB_KDB domain)
+ */
+extern int kdb_parse(const char *cmdstr);
+extern int kdb_getarea_size(void *, unsigned long, size_t);
+extern int kdb_putarea_size(unsigned long, void *, size_t);
+
+/*
+ * Like get_user and put_user, kdb_getarea and kdb_putarea take variable
+ * names, not pointers. The underlying *_size functions take pointers.
+ */
+#define kdb_getarea(x, addr) kdb_getarea_size(&(x), addr, sizeof((x)))
+#define kdb_putarea(addr, x) kdb_putarea_size(addr, &(x), sizeof((x)))
+
+extern int kdb_getphysword(unsigned long *word,
+ unsigned long addr, size_t size);
+extern int kdb_getword(unsigned long *, unsigned long, size_t);
+extern int kdb_putword(unsigned long, unsigned long, size_t);
+
+extern int kdbgetularg(const char *, unsigned long *);
+extern int kdbgetu64arg(const char *, u64 *);
+extern char *kdbgetenv(const char *);
+extern int kdbgetaddrarg(int, const char **, int*, unsigned long *,
+ long *, char **);
+
+/* Symbol table format returned by kallsyms. */
+typedef struct __ksymtab {
+ unsigned long value; /* Address of symbol */
+ const char *mod_name; /* Module containing symbol or
+ * "kernel" */
+ unsigned long mod_start;
+ unsigned long mod_end;
+ const char *sec_name; /* Section containing symbol */
+ unsigned long sec_start;
+ unsigned long sec_end;
+ const char *sym_name; /* Full symbol name, including
+ * any version */
+ unsigned long sym_start;
+ unsigned long sym_end;
+} kdb_symtab_t;
+extern int kallsyms_symbol_next(char *prefix_name, int flag);
+extern int kallsyms_symbol_complete(char *prefix_name, int max_len);
+
+extern int kdbgetsymval(const char *, kdb_symtab_t *);
+extern int kdbnearsym(unsigned long, kdb_symtab_t *);
+extern void kdbnearsym_cleanup(void);
+extern char *kdb_strdup(const char *str, gfp_t type);
+extern void kdb_symbol_print(unsigned long, const kdb_symtab_t *, unsigned int);
+
+extern void kdb_ps_suppressed(void);
+extern void kdb_ps1(const struct task_struct *p);
+extern void kdb_print_nameval(const char *name, unsigned long val);
+extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info);
+extern void kdb_meminfo_proc_show(void);
+extern char *kdb_getstr(char *, size_t, char *);
+
+/* Defines for kdb_symbol_print */
+#define KDB_SP_SPACEB 0x0001 /* Space before string */
+#define KDB_SP_SPACEA 0x0002 /* Space after string */
+#define KDB_SP_PAREN 0x0004 /* Parenthesis around string */
+#define KDB_SP_VALUE 0x0008 /* Print the value of the address */
+#define KDB_SP_SYMSIZE 0x0010 /* Print the size of the symbol */
+#define KDB_SP_NEWLINE 0x0020 /* Newline after string */
+#define KDB_SP_DEFAULT (KDB_SP_VALUE|KDB_SP_PAREN)
+
+#define KDB_TSK(cpu) (kgdb_info[cpu].task)
+#define KDB_TSKREGS(cpu) (kgdb_info[cpu].debuggerinfo)
+
+extern struct task_struct *kdb_curr_task(int);
+
+#define kdb_task_has_cpu(p) (task_curr(p))
+
+/* Simplify coexistence with NPTL */
+#define kdb_do_each_thread(g, p) do_each_thread(g, p)
+#define kdb_while_each_thread(g, p) while_each_thread(g, p)
+
+#define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
+
+extern void *debug_kmalloc(size_t size, gfp_t flags);
+extern void debug_kfree(void *);
+extern void debug_kusage(void);
+
+extern void kdb_set_current_task(struct task_struct *);
+extern struct task_struct *kdb_current_task;
#else /* ! CONFIG_KGDB_KDB */
static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
static inline void kdb_init(int level) {}
@@ -157,6 +245,7 @@ static inline int kdb_register_repeat(ch
char *help, short minlen,
kdb_repeat_t repeat) { return 0; }
static inline int kdb_unregister(char *cmd) { return 0; }
+
#endif /* CONFIG_KGDB_KDB */
enum {
KDB_NOT_INITIALIZED,
--- linux.orig/kernel/debug/debug_core.h
+++ linux/kernel/debug/debug_core.h
@@ -71,7 +71,6 @@ extern int dbg_kdb_mode;
#ifdef CONFIG_KGDB_KDB
extern int kdb_stub(struct kgdb_state *ks);
-extern int kdb_parse(const char *cmdstr);
extern int kdb_common_init_state(struct kgdb_state *ks);
extern int kdb_common_deinit_state(void);
#else /* ! CONFIG_KGDB_KDB */
--- linux.orig/kernel/debug/kdb/kdb_private.h
+++ linux/kernel/debug/kdb/kdb_private.h
@@ -68,51 +68,6 @@
*/
#define KDB_MAXBPT 16
-/* Symbol table format returned by kallsyms. */
-typedef struct __ksymtab {
- unsigned long value; /* Address of symbol */
- const char *mod_name; /* Module containing symbol or
- * "kernel" */
- unsigned long mod_start;
- unsigned long mod_end;
- const char *sec_name; /* Section containing symbol */
- unsigned long sec_start;
- unsigned long sec_end;
- const char *sym_name; /* Full symbol name, including
- * any version */
- unsigned long sym_start;
- unsigned long sym_end;
- } kdb_symtab_t;
-extern int kallsyms_symbol_next(char *prefix_name, int flag);
-extern int kallsyms_symbol_complete(char *prefix_name, int max_len);
-
-/* Exported Symbols for kernel loadable modules to use. */
-extern int kdb_getarea_size(void *, unsigned long, size_t);
-extern int kdb_putarea_size(unsigned long, void *, size_t);
-
-/*
- * Like get_user and put_user, kdb_getarea and kdb_putarea take variable
- * names, not pointers. The underlying *_size functions take pointers.
- */
-#define kdb_getarea(x, addr) kdb_getarea_size(&(x), addr, sizeof((x)))
-#define kdb_putarea(addr, x) kdb_putarea_size(addr, &(x), sizeof((x)))
-
-extern int kdb_getphysword(unsigned long *word,
- unsigned long addr, size_t size);
-extern int kdb_getword(unsigned long *, unsigned long, size_t);
-extern int kdb_putword(unsigned long, unsigned long, size_t);
-
-extern int kdbgetularg(const char *, unsigned long *);
-extern int kdbgetu64arg(const char *, u64 *);
-extern char *kdbgetenv(const char *);
-extern int kdbgetaddrarg(int, const char **, int*, unsigned long *,
- long *, char **);
-extern int kdbgetsymval(const char *, kdb_symtab_t *);
-extern int kdbnearsym(unsigned long, kdb_symtab_t *);
-extern void kdbnearsym_cleanup(void);
-extern char *kdb_strdup(const char *str, gfp_t type);
-extern void kdb_symbol_print(unsigned long, const kdb_symtab_t *, unsigned int);
-
/* Routine for debugging the debugger state. */
extern void kdb_print_state(const char *, int);
@@ -205,42 +160,8 @@ extern unsigned long kdb_task_state_stri
extern char kdb_task_state_char (const struct task_struct *);
extern unsigned long kdb_task_state(const struct task_struct *p,
unsigned long mask);
-extern void kdb_ps_suppressed(void);
-extern void kdb_ps1(const struct task_struct *p);
-extern void kdb_print_nameval(const char *name, unsigned long val);
-extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info);
-extern void kdb_meminfo_proc_show(void);
-extern char *kdb_getstr(char *, size_t, char *);
extern void kdb_gdb_state_pass(char *buf);
-/* Defines for kdb_symbol_print */
-#define KDB_SP_SPACEB 0x0001 /* Space before string */
-#define KDB_SP_SPACEA 0x0002 /* Space after string */
-#define KDB_SP_PAREN 0x0004 /* Parenthesis around string */
-#define KDB_SP_VALUE 0x0008 /* Print the value of the address */
-#define KDB_SP_SYMSIZE 0x0010 /* Print the size of the symbol */
-#define KDB_SP_NEWLINE 0x0020 /* Newline after string */
-#define KDB_SP_DEFAULT (KDB_SP_VALUE|KDB_SP_PAREN)
-
-#define KDB_TSK(cpu) kgdb_info[cpu].task
-#define KDB_TSKREGS(cpu) kgdb_info[cpu].debuggerinfo
-
-extern struct task_struct *kdb_curr_task(int);
-
-#define kdb_task_has_cpu(p) (task_curr(p))
-
-/* Simplify coexistence with NPTL */
-#define kdb_do_each_thread(g, p) do_each_thread(g, p)
-#define kdb_while_each_thread(g, p) while_each_thread(g, p)
-
-#define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-
-extern void *debug_kmalloc(size_t size, gfp_t flags);
-extern void debug_kfree(void *);
-extern void debug_kusage(void);
-
-extern void kdb_set_current_task(struct task_struct *);
-extern struct task_struct *kdb_current_task;
#ifdef CONFIG_KDB_KEYBOARD
extern void kdb_kbd_cleanup_state(void);
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (3 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 04/14] KDB: allow KDB modules to be external modules Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 20:09 ` Eric W. Biederman
` (2 more replies)
2013-03-12 19:38 ` [PATCH 06/14] KDB: consolidate KDB grep code Mike Travis
` (8 subsequent siblings)
13 siblings, 3 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Tim Bird,
Anton Vorontsov, Sasha Levin, Rusty Russell, Greg Kroah-Hartman,
Cong Wang, Stephen Boyd, Al Viro, Oleg Nesterov,
Eric W. Biederman, Serge Hallyn
[-- Attachment #1: kdb-add-module-support.patch --]
[-- Type: text/plain, Size: 10701 bytes --]
This patch adds some important KDB functions to be externally
usable by loadable KDB modules. Note that often drivers bring
in KDB modules for debugging, and in the past KDB has not been
limited to use by GPL only modules. This patch restores KDB
usefullness to non-GPL modules.
Cc: Tim Bird <tim.bird@am.sony.com>
Cc: Anton Vorontsov <anton.vorontsov@linaro.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Cong Wang <amwang@redhat.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Serge Hallyn <serge.hallyn@canonical.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
kernel/debug/kdb/kdb_io.c | 5 ++++-
kernel/debug/kdb/kdb_main.c | 21 ++++++++++++++++++---
kernel/debug/kdb/kdb_support.c | 17 +++++++++++++++++
kernel/kallsyms.c | 9 +++++----
kernel/signal.c | 5 +++--
5 files changed, 47 insertions(+), 10 deletions(-)
--- linux.orig/kernel/debug/kdb/kdb_io.c
+++ linux/kernel/debug/kdb/kdb_io.c
@@ -30,6 +30,7 @@
char kdb_prompt_str[CMD_BUFLEN];
int kdb_trap_printk;
+EXPORT_SYMBOL(kdb_trap_printk);
static int kgdb_transition_check(char *buffer)
{
@@ -447,6 +448,7 @@ char *kdb_getstr(char *buffer, size_t bu
kdb_nextline = 1; /* Prompt and input resets line number */
return kdb_read(buffer, bufsize);
}
+EXPORT_SYMBOL(kdb_getstr);
/*
* kdb_input_flush
@@ -839,6 +841,7 @@ kdb_print_out:
preempt_enable();
return retlen;
}
+EXPORT_SYMBOL(vkdb_printf);
int kdb_printf(const char *fmt, ...)
{
@@ -851,4 +854,4 @@ int kdb_printf(const char *fmt, ...)
return r;
}
-EXPORT_SYMBOL_GPL(kdb_printf);
+EXPORT_SYMBOL(kdb_printf);
--- linux.orig/kernel/debug/kdb/kdb_main.c
+++ linux/kernel/debug/kdb/kdb_main.c
@@ -53,19 +53,23 @@ int kdb_grep_trailing;
* Kernel debugger state flags
*/
int kdb_flags;
+EXPORT_SYMBOL(kdb_flags);
atomic_t kdb_event;
+EXPORT_SYMBOL(kdb_event);
/*
* kdb_lock protects updates to kdb_initial_cpu. Used to
* single thread processors through the kernel debugger.
*/
int kdb_initial_cpu = -1; /* cpu number that owns kdb */
+EXPORT_SYMBOL(kdb_initial_cpu);
int kdb_nextline = 1;
int kdb_state; /* General KDB state */
struct task_struct *kdb_current_task;
EXPORT_SYMBOL(kdb_current_task);
struct pt_regs *kdb_current_regs;
+EXPORT_SYMBOL(kdb_current_regs);
const char *kdb_diemsg;
static int kdb_go_count;
@@ -186,6 +190,7 @@ struct task_struct *kdb_curr_task(int cp
#endif
return p;
}
+EXPORT_SYMBOL(kdb_curr_task);
/*
* kdbgetenv - This function will return the character string value of
@@ -217,6 +222,7 @@ char *kdbgetenv(const char *match)
}
return NULL;
}
+EXPORT_SYMBOL(kdbgetenv);
/*
* kdballocenv - This function is used to allocate bytes for
@@ -293,6 +299,7 @@ int kdbgetintenv(const char *match, int
*value = (int) val;
return diag;
}
+EXPORT_SYMBOL(kdbgetintenv);
/*
* kdbgetularg - This function will convert a numeric string into an
@@ -325,6 +332,7 @@ int kdbgetularg(const char *arg, unsigne
return 0;
}
+EXPORT_SYMBOL(kdbgetularg);
int kdbgetu64arg(const char *arg, u64 *value)
{
@@ -344,6 +352,7 @@ int kdbgetu64arg(const char *arg, u64 *v
return 0;
}
+EXPORT_SYMBOL(kdbgetu64arg);
/*
* kdb_set - This function implements the 'set' command. Alter an
@@ -425,6 +434,7 @@ int kdb_set(int argc, const char **argv)
return KDB_ENVFULL;
}
+EXPORT_SYMBOL(kdb_set);
static int kdb_check_regs(void)
{
@@ -585,6 +595,7 @@ int kdbgetaddrarg(int argc, const char *
return 0;
}
+EXPORT_SYMBOL(kdbgetaddrarg);
static void kdb_cmderror(int diag)
{
@@ -1049,6 +1060,7 @@ int kdb_parse(const char *cmdstr)
return 0;
}
}
+EXPORT_SYMBOL(kdb_parse);
static int handle_ctrl_cmd(char *cmd)
@@ -1109,6 +1121,7 @@ void kdb_set_current_task(struct task_st
}
kdb_current_regs = NULL;
}
+EXPORT_SYMBOL(kdb_set_current_task);
/*
* kdb_local - The main code for kdb. This routine is invoked on a
@@ -2249,6 +2262,7 @@ void kdb_ps_suppressed(void)
kdb_printf(" suppressed,\nuse 'ps A' to see all.\n");
}
}
+EXPORT_SYMBOL(kdb_ps_suppressed);
/*
* kdb_ps - This function implements the 'ps' command which shows a
@@ -2281,6 +2295,7 @@ void kdb_ps1(const struct task_struct *p
}
}
}
+EXPORT_SYMBOL(kdb_ps1);
static int kdb_ps(int argc, const char **argv)
{
@@ -2697,7 +2712,7 @@ int kdb_register_repeat(char *cmd,
return 0;
}
-EXPORT_SYMBOL_GPL(kdb_register_repeat);
+EXPORT_SYMBOL(kdb_register_repeat);
/*
@@ -2721,7 +2736,7 @@ int kdb_register(char *cmd,
return kdb_register_repeat(cmd, func, usage, help, minlen,
KDB_REPEAT_NONE);
}
-EXPORT_SYMBOL_GPL(kdb_register);
+EXPORT_SYMBOL(kdb_register);
/*
* kdb_unregister - This function is used to unregister a kernel
@@ -2750,7 +2765,7 @@ int kdb_unregister(char *cmd)
/* Couldn't find it. */
return 1;
}
-EXPORT_SYMBOL_GPL(kdb_unregister);
+EXPORT_SYMBOL(kdb_unregister);
/* Initialize the kdb command table. */
static void __init kdb_inittab(void)
--- linux.orig/kernel/debug/kdb/kdb_support.c
+++ linux/kernel/debug/kdb/kdb_support.c
@@ -157,6 +157,7 @@ out:
debug_kfree(knt1);
return ret;
}
+EXPORT_SYMBOL(kdbnearsym);
void kdbnearsym_cleanup(void)
{
@@ -168,6 +169,7 @@ void kdbnearsym_cleanup(void)
}
}
}
+EXPORT_SYMBOL(kdbnearsym_cleanup);
static char ks_namebuf[KSYM_NAME_LEN+1], ks_namebuf_prev[KSYM_NAME_LEN+1];
@@ -214,6 +216,7 @@ int kallsyms_symbol_complete(char *prefi
memcpy(prefix_name, ks_namebuf_prev, prev_len+1);
return number;
}
+EXPORT_SYMBOL(kallsyms_symbol_complete);
/*
* kallsyms_symbol_next
@@ -242,6 +245,7 @@ int kallsyms_symbol_next(char *prefix_na
}
return 0;
}
+EXPORT_SYMBOL(kallsyms_symbol_next);
/*
* kdb_symbol_print - Standard method for printing a symbol name and offset.
@@ -292,6 +296,7 @@ void kdb_symbol_print(unsigned long addr
if (punc & KDB_SP_NEWLINE)
kdb_printf("\n");
}
+EXPORT_SYMBOL(kdb_symbol_print);
/*
* kdb_strdup - kdb equivalent of strdup, for disasm code.
@@ -312,6 +317,7 @@ char *kdb_strdup(const char *str, gfp_t
return NULL;
return strcpy(s, str);
}
+EXPORT_SYMBOL(kdb_strdup);
/*
* kdb_getarea_size - Read an area of data. The kdb equivalent of
@@ -337,6 +343,7 @@ int kdb_getarea_size(void *res, unsigned
}
return ret;
}
+EXPORT_SYMBOL(kdb_getarea_size);
/*
* kdb_putarea_size - Write an area of data. The kdb equivalent of
@@ -362,6 +369,7 @@ int kdb_putarea_size(unsigned long addr,
}
return ret;
}
+EXPORT_SYMBOL(kdb_putarea_size);
/*
* kdb_getphys - Read data from a physical address. Validate the
@@ -439,6 +447,7 @@ int kdb_getphysword(unsigned long *word,
}
return diag;
}
+EXPORT_SYMBOL(kdb_getphysword);
/*
* kdb_getword - Read a binary value. Unlike kdb_getarea, this treats
@@ -488,6 +497,7 @@ int kdb_getword(unsigned long *word, uns
}
return diag;
}
+EXPORT_SYMBOL(kdb_getword);
/*
* kdb_putword - Write a binary value. Unlike kdb_putarea, this
@@ -532,6 +542,7 @@ int kdb_putword(unsigned long addr, unsi
}
return diag;
}
+EXPORT_SYMBOL(kdb_putword);
/*
* kdb_task_state_string - Convert a string containing any of the
@@ -681,6 +692,7 @@ void kdb_print_nameval(const char *name,
else
kdb_printf("0x%lx\n", val);
}
+EXPORT_SYMBOL(kdb_print_nameval);
/* Last ditch allocator for debugging, so we can still debug even when
* the GFP_ATOMIC pool has been exhausted. The algorithms are tuned
@@ -799,6 +811,7 @@ out:
spin_unlock(&dap_lock);
return p;
}
+EXPORT_SYMBOL(debug_kmalloc);
void debug_kfree(void *p)
{
@@ -858,6 +871,7 @@ void debug_kfree(void *p)
}
spin_unlock(&dap_lock);
}
+EXPORT_SYMBOL(debug_kfree);
void debug_kusage(void)
{
@@ -907,6 +921,7 @@ void debug_kusage(void)
out:
spin_unlock(&dap_lock);
}
+EXPORT_SYMBOL(debug_kusage);
/* Maintain a small stack of kdb_flags to allow recursion without disturbing
* the global kdb state.
@@ -919,9 +934,11 @@ void kdb_save_flags(void)
BUG_ON(kdb_flags_index >= ARRAY_SIZE(kdb_flags_stack));
kdb_flags_stack[kdb_flags_index++] = kdb_flags;
}
+EXPORT_SYMBOL(kdb_save_flags);
void kdb_restore_flags(void)
{
BUG_ON(kdb_flags_index <= 0);
kdb_flags = kdb_flags_stack[--kdb_flags_index];
}
+EXPORT_SYMBOL(kdb_restore_flags);
--- linux.orig/kernel/kallsyms.c
+++ linux/kernel/kallsyms.c
@@ -183,7 +183,7 @@ unsigned long kallsyms_lookup_name(const
}
return module_kallsyms_lookup_name(name);
}
-EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
+EXPORT_SYMBOL(kallsyms_lookup_name);
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
unsigned long),
@@ -202,7 +202,7 @@ int kallsyms_on_each_symbol(int (*fn)(vo
}
return module_kallsyms_on_each_symbol(fn, data);
}
-EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol);
+EXPORT_SYMBOL(kallsyms_on_each_symbol);
static unsigned long get_symbol_pos(unsigned long addr,
unsigned long *symbolsize,
@@ -384,7 +384,7 @@ int sprint_symbol(char *buffer, unsigned
{
return __sprint_symbol(buffer, address, 0, 1);
}
-EXPORT_SYMBOL_GPL(sprint_symbol);
+EXPORT_SYMBOL(sprint_symbol);
/**
* sprint_symbol_no_offset - Look up a kernel symbol and return it in a text buffer
@@ -401,7 +401,7 @@ int sprint_symbol_no_offset(char *buffer
{
return __sprint_symbol(buffer, address, 0, 0);
}
-EXPORT_SYMBOL_GPL(sprint_symbol_no_offset);
+EXPORT_SYMBOL(sprint_symbol_no_offset);
/**
* sprint_backtrace - Look up a backtrace symbol and return it in a text buffer
@@ -587,6 +587,7 @@ const char *kdb_walk_kallsyms(loff_t *po
return kdb_walk_kallsyms_iter.name;
}
}
+EXPORT_SYMBOL(kdb_walk_kallsyms);
#endif /* CONFIG_KGDB_KDB */
static const struct file_operations kallsyms_operations = {
--- linux.orig/kernel/signal.c
+++ linux/kernel/signal.c
@@ -1419,7 +1419,7 @@ out_unlock:
rcu_read_unlock();
return ret;
}
-EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
+EXPORT_SYMBOL(kill_pid_info_as_cred);
/*
* kill_something_info() interprets pid in interesting ways just like kill(2).
@@ -2491,7 +2491,7 @@ out:
}
EXPORT_SYMBOL(recalc_sigpending);
-EXPORT_SYMBOL_GPL(dequeue_signal);
+EXPORT_SYMBOL(dequeue_signal);
EXPORT_SYMBOL(flush_signals);
EXPORT_SYMBOL(force_sig);
EXPORT_SYMBOL(send_sig);
@@ -3661,4 +3661,5 @@ kdb_send_sig_info(struct task_struct *t,
else
kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid);
}
+EXPORT_SYMBOL(kdb_send_sig_info);
#endif /* CONFIG_KGDB_KDB */
--
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 19:38 ` [PATCH 05/14] KDB: add more exports for supporting KDB modules Mike Travis
@ 2013-03-12 20:09 ` Eric W. Biederman
2013-03-12 22:03 ` Mike Travis
2013-03-12 20:23 ` Greg Kroah-Hartman
2013-03-12 22:01 ` Thomas Gleixner
2 siblings, 1 reply; 28+ messages in thread
From: Eric W. Biederman @ 2013-03-12 20:09 UTC (permalink / raw)
To: Mike Travis
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Tim Bird, Anton Vorontsov, Sasha Levin, Rusty Russell,
Greg Kroah-Hartman, Cong Wang, Stephen Boyd, Al Viro,
Oleg Nesterov, Serge Hallyn
Mike Travis <travis@sgi.com> writes:
> This patch adds some important KDB functions to be externally
> usable by loadable KDB modules. Note that often drivers bring
> in KDB modules for debugging, and in the past KDB has not been
> limited to use by GPL only modules. This patch restores KDB
> usefullness to non-GPL modules.
It is not ok to change EXPORT_SYMBOL_GPL to EXPORT_SYMBOL.
The symbols you are changing to EXPORT_SYMBOL from EXPORT_SYMBOL_GPL you
should not even be messing with if your source code is not in the main
kernel tree.
This patch is totally not ok.
I don't know what past you are referring to but you are changing symbols
that have never been exported as anything other than EXPORT_SYMBOL_GPL
to EXPORT_SYMBOL. The past I remember is the past where kdb was not in
the kernel tree at all.
Please go back to the drawing board and come back with a solution where
you are working with the community instead of trying asking the rest of
us to support something you won't share.
Nacked-by: "Eric W. Biederman" <ebiederm@xmission.com>
> --- linux.orig/kernel/signal.c
> +++ linux/kernel/signal.c
> @@ -1419,7 +1419,7 @@ out_unlock:
> rcu_read_unlock();
> return ret;
> }
> -EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
> +EXPORT_SYMBOL(kill_pid_info_as_cred);
>
> /*
> * kill_something_info() interprets pid in interesting ways just like kill(2).
> @@ -2491,7 +2491,7 @@ out:
> }
>
> EXPORT_SYMBOL(recalc_sigpending);
> -EXPORT_SYMBOL_GPL(dequeue_signal);
> +EXPORT_SYMBOL(dequeue_signal);
> EXPORT_SYMBOL(flush_signals);
> EXPORT_SYMBOL(force_sig);
> EXPORT_SYMBOL(send_sig);
> @@ -3661,4 +3661,5 @@ kdb_send_sig_info(struct task_struct *t,
> else
> kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid);
> }
> +EXPORT_SYMBOL(kdb_send_sig_info);
> #endif /* CONFIG_KGDB_KDB */
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 20:09 ` Eric W. Biederman
@ 2013-03-12 22:03 ` Mike Travis
2013-03-12 22:13 ` Greg Kroah-Hartman
2013-03-12 22:39 ` Eric W. Biederman
0 siblings, 2 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 22:03 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Tim Bird, Anton Vorontsov, Sasha Levin, Rusty Russell,
Greg Kroah-Hartman, Cong Wang, Stephen Boyd, Al Viro,
Oleg Nesterov, Serge Hallyn
Let me see if I can understand the concept better. By denying
an external hardware vendor the use of KDB to support a significant
piece of proprietary hardware on Linux, I furthering the interests
of Linux and the community how?
Looking back at the KDB sources originally posted on oss.sgi.com I
did not see any restrictions on the use of KDB. How/why was that
restriction granted and by whom? Was SGI, the original copyright
owner of KDB, asked or even informed of that decision? I'm not
trying to be a lawyer here, but someone decided (perhaps wrongly)
that KDB should only be used by GPL modules.
I'm not married to this matter by any means and I will change them all
if that's what's needed for acceptance. But I do think that placing
unnecessary roadblocks in the path of developing more capabilities
for the Linux system, is causing a disservice to the the users of
Linux and the overall Linux community.
Thanks,
Mike
On 3/12/2013 1:09 PM, Eric W. Biederman wrote:
> Mike Travis <travis@sgi.com> writes:
>
>> This patch adds some important KDB functions to be externally
>> usable by loadable KDB modules. Note that often drivers bring
>> in KDB modules for debugging, and in the past KDB has not been
>> limited to use by GPL only modules. This patch restores KDB
>> usefullness to non-GPL modules.
>
> It is not ok to change EXPORT_SYMBOL_GPL to EXPORT_SYMBOL.
>
> The symbols you are changing to EXPORT_SYMBOL from EXPORT_SYMBOL_GPL you
> should not even be messing with if your source code is not in the main
> kernel tree.
>
> This patch is totally not ok.
>
> I don't know what past you are referring to but you are changing symbols
> that have never been exported as anything other than EXPORT_SYMBOL_GPL
> to EXPORT_SYMBOL. The past I remember is the past where kdb was not in
> the kernel tree at all.
>
> Please go back to the drawing board and come back with a solution where
> you are working with the community instead of trying asking the rest of
> us to support something you won't share.
>
> Nacked-by: "Eric W. Biederman" <ebiederm@xmission.com>
>
>> --- linux.orig/kernel/signal.c
>> +++ linux/kernel/signal.c
>> @@ -1419,7 +1419,7 @@ out_unlock:
>> rcu_read_unlock();
>> return ret;
>> }
>> -EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
>> +EXPORT_SYMBOL(kill_pid_info_as_cred);
>>
>> /*
>> * kill_something_info() interprets pid in interesting ways just like kill(2).
>> @@ -2491,7 +2491,7 @@ out:
>> }
>>
>> EXPORT_SYMBOL(recalc_sigpending);
>> -EXPORT_SYMBOL_GPL(dequeue_signal);
>> +EXPORT_SYMBOL(dequeue_signal);
>> EXPORT_SYMBOL(flush_signals);
>> EXPORT_SYMBOL(force_sig);
>> EXPORT_SYMBOL(send_sig);
>> @@ -3661,4 +3661,5 @@ kdb_send_sig_info(struct task_struct *t,
>> else
>> kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid);
>> }
>> +EXPORT_SYMBOL(kdb_send_sig_info);
>> #endif /* CONFIG_KGDB_KDB */
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 22:03 ` Mike Travis
@ 2013-03-12 22:13 ` Greg Kroah-Hartman
2013-03-12 22:26 ` Mike Travis
2013-03-12 22:39 ` Eric W. Biederman
1 sibling, 1 reply; 28+ messages in thread
From: Greg Kroah-Hartman @ 2013-03-12 22:13 UTC (permalink / raw)
To: Mike Travis
Cc: Eric W. Biederman, Jason Wessel, Dimitri Sivanich, Ingo Molnar,
H. Peter Anvin, Thomas Gleixner, Andrew Morton, kgdb-bugreport,
x86, linux-kernel, Tim Bird, Anton Vorontsov, Sasha Levin,
Rusty Russell, Cong Wang, Stephen Boyd, Al Viro, Oleg Nesterov,
Serge Hallyn
On Tue, Mar 12, 2013 at 03:03:17PM -0700, Mike Travis wrote:
> Let me see if I can understand the concept better. By denying
> an external hardware vendor the use of KDB to support a significant
> piece of proprietary hardware on Linux, I furthering the interests
> of Linux and the community how?
Did SGI lawyers really agree to this patch? I consider you running this
by them if you have any questions as to why we are objecting to this.
If, after discussing it with them, they still are asking for this
change, please resend it, with their signed-off-by: on it showing that
they really want this change.
greg k-h
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 22:13 ` Greg Kroah-Hartman
@ 2013-03-12 22:26 ` Mike Travis
0 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 22:26 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Eric W. Biederman, Jason Wessel, Dimitri Sivanich, Ingo Molnar,
H. Peter Anvin, Thomas Gleixner, Andrew Morton, kgdb-bugreport,
x86, linux-kernel, Tim Bird, Anton Vorontsov, Sasha Levin,
Rusty Russell, Cong Wang, Stephen Boyd, Al Viro, Oleg Nesterov,
Serge Hallyn
On 3/12/2013 3:13 PM, Greg Kroah-Hartman wrote:
> On Tue, Mar 12, 2013 at 03:03:17PM -0700, Mike Travis wrote:
>> Let me see if I can understand the concept better. By denying
>> an external hardware vendor the use of KDB to support a significant
>> piece of proprietary hardware on Linux, I furthering the interests
>> of Linux and the community how?
>
> Did SGI lawyers really agree to this patch? I consider you running this
> by them if you have any questions as to why we are objecting to this.
> If, after discussing it with them, they still are asking for this
> change, please resend it, with their signed-off-by: on it showing that
> they really want this change.
>
> greg k-h
>
There is nobody else involved believe me. I am just trying to do
the right thing. This is not that big an issue as it has absolutely
no relevance to anything within that patch set. I'm trying to
improve the overall experience of using KDB, which I've found most
helpful in the past to get around some very thorny issues, particularly
in regards to bringing up new hardware. If blocking that usage by
non-GPL modules is what's required, then by all means I'm for it.
But understanding more of why the restriction is in place, would be
very helpful the next time I encounter it.
Thanks,
Mike
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 22:03 ` Mike Travis
2013-03-12 22:13 ` Greg Kroah-Hartman
@ 2013-03-12 22:39 ` Eric W. Biederman
2013-03-12 23:03 ` Mike Travis
1 sibling, 1 reply; 28+ messages in thread
From: Eric W. Biederman @ 2013-03-12 22:39 UTC (permalink / raw)
To: Mike Travis
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Tim Bird, Anton Vorontsov, Sasha Levin, Rusty Russell,
Greg Kroah-Hartman, Cong Wang, Stephen Boyd, Al Viro,
Oleg Nesterov, Serge Hallyn
Mike Travis <travis@sgi.com> writes:
> Let me see if I can understand the concept better. By denying
> an external hardware vendor the use of KDB to support a significant
> piece of proprietary hardware on Linux, I furthering the interests
> of Linux and the community how?
By ignoring interests of someone who does not coopearte with the
community we encourage people to cooperate with the community.
> Looking back at the KDB sources originally posted on oss.sgi.com I
> did not see any restrictions on the use of KDB. How/why was that
> restriction granted and by whom? Was SGI, the original copyright
> owner of KDB, asked or even informed of that decision? I'm not
> trying to be a lawyer here, but someone decided (perhaps wrongly)
> that KDB should only be used by GPL modules.
The symbols quoted below are have absolutely nothing to do with KDB
ever. They are pieces of code that you should only use in very
exceptional circumpstances, or you risk breaking the kernel in strange
and mysterious ways.
Beyond that there are modules with GPL compatible licenses. That is the
only kind of module that the kernel license allows.
> I'm not married to this matter by any means and I will change them all
> if that's what's needed for acceptance. But I do think that placing
> unnecessary roadblocks in the path of developing more capabilities
> for the Linux system, is causing a disservice to the the users of
> Linux and the overall Linux community.
A capability that no one else can use, and that generates support
requests that can not be supported is not developing more capabilities
for the Linux system. It is denying those of us who ask for repayment
in code, our compensation. It is theft.
Eric
>>> --- linux.orig/kernel/signal.c
>>> +++ linux/kernel/signal.c
>>> @@ -1419,7 +1419,7 @@ out_unlock:
>>> rcu_read_unlock();
>>> return ret;
>>> }
>>> -EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
>>> +EXPORT_SYMBOL(kill_pid_info_as_cred);
>>>
>>> /*
>>> * kill_something_info() interprets pid in interesting ways just like kill(2).
>>> @@ -2491,7 +2491,7 @@ out:
>>> }
>>>
>>> EXPORT_SYMBOL(recalc_sigpending);
>>> -EXPORT_SYMBOL_GPL(dequeue_signal);
>>> +EXPORT_SYMBOL(dequeue_signal);
>>> EXPORT_SYMBOL(flush_signals);
>>> EXPORT_SYMBOL(force_sig);
>>> EXPORT_SYMBOL(send_sig);
>>> @@ -3661,4 +3661,5 @@ kdb_send_sig_info(struct task_struct *t,
>>> else
>>> kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid);
>>> }
>>> +EXPORT_SYMBOL(kdb_send_sig_info);
>>> #endif /* CONFIG_KGDB_KDB */
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 22:39 ` Eric W. Biederman
@ 2013-03-12 23:03 ` Mike Travis
0 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 23:03 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Tim Bird, Anton Vorontsov, Sasha Levin, Rusty Russell,
Greg Kroah-Hartman, Cong Wang, Stephen Boyd, Al Viro,
Oleg Nesterov, Serge Hallyn
On 3/12/2013 3:39 PM, Eric W. Biederman wrote:
> Mike Travis <travis@sgi.com> writes:
>
>> Let me see if I can understand the concept better. By denying
>> an external hardware vendor the use of KDB to support a significant
>> piece of proprietary hardware on Linux, I furthering the interests
>> of Linux and the community how?
>
> By ignoring interests of someone who does not cooperate with the
> community we encourage people to cooperate with the community.
I can see this point.
>
>> Looking back at the KDB sources originally posted on oss.sgi.com I
>> did not see any restrictions on the use of KDB. How/why was that
>> restriction granted and by whom? Was SGI, the original copyright
>> owner of KDB, asked or even informed of that decision? I'm not
>> trying to be a lawyer here, but someone decided (perhaps wrongly)
>> that KDB should only be used by GPL modules.
>
> The symbols quoted below are have absolutely nothing to do with KDB
> ever. They are pieces of code that you should only use in very
> exceptional circumpstances, or you risk breaking the kernel in strange
> and mysterious ways.
Yes, those below were indeed a mistake on my part. Thanks for catching that.
>
> Beyond that there are modules with GPL compatible licenses. That is the
> only kind of module that the kernel license allows.
Okay.
>
>> I'm not married to this matter by any means and I will change them all
>> if that's what's needed for acceptance. But I do think that placing
>> unnecessary roadblocks in the path of developing more capabilities
>> for the Linux system, is causing a disservice to the the users of
>> Linux and the overall Linux community.
>
> A capability that no one else can use, and that generates support
> requests that can not be supported is not developing more capabilities
> for the Linux system. It is denying those of us who ask for repayment
> in code, our compensation. It is theft.
Not sure I've ever looked at it this way, but again I can see your point.
>
> Eric
Thanks for the meaningful feedback Eric.
Mike
>
>>>> --- linux.orig/kernel/signal.c
>>>> +++ linux/kernel/signal.c
>>>> @@ -1419,7 +1419,7 @@ out_unlock:
>>>> rcu_read_unlock();
>>>> return ret;
>>>> }
>>>> -EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
>>>> +EXPORT_SYMBOL(kill_pid_info_as_cred);
>>>>
>>>> /*
>>>> * kill_something_info() interprets pid in interesting ways just like kill(2).
>>>> @@ -2491,7 +2491,7 @@ out:
>>>> }
>>>>
>>>> EXPORT_SYMBOL(recalc_sigpending);
>>>> -EXPORT_SYMBOL_GPL(dequeue_signal);
>>>> +EXPORT_SYMBOL(dequeue_signal);
>>>> EXPORT_SYMBOL(flush_signals);
>>>> EXPORT_SYMBOL(force_sig);
>>>> EXPORT_SYMBOL(send_sig);
>>>> @@ -3661,4 +3661,5 @@ kdb_send_sig_info(struct task_struct *t,
>>>> else
>>>> kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid);
>>>> }
>>>> +EXPORT_SYMBOL(kdb_send_sig_info);
>>>> #endif /* CONFIG_KGDB_KDB */
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 19:38 ` [PATCH 05/14] KDB: add more exports for supporting KDB modules Mike Travis
2013-03-12 20:09 ` Eric W. Biederman
@ 2013-03-12 20:23 ` Greg Kroah-Hartman
2013-03-12 22:01 ` Thomas Gleixner
2 siblings, 0 replies; 28+ messages in thread
From: Greg Kroah-Hartman @ 2013-03-12 20:23 UTC (permalink / raw)
To: Mike Travis
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Tim Bird, Anton Vorontsov, Sasha Levin, Rusty Russell, Cong Wang,
Stephen Boyd, Al Viro, Oleg Nesterov, Eric W. Biederman,
Serge Hallyn
On Tue, Mar 12, 2013 at 02:38:28PM -0500, Mike Travis wrote:
> This patch adds some important KDB functions to be externally
> usable by loadable KDB modules.
What modules would that be? Are they in this patch series?
> Note that often drivers bring in KDB modules for debugging, and in the
> past KDB has not been limited to use by GPL only modules.
It always has been, when was the in-kernel code any other way?
> This patch restores KDB usefullness to non-GPL modules.
As Eric says, you can't just do this, sorry.
greg k-h
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 19:38 ` [PATCH 05/14] KDB: add more exports for supporting KDB modules Mike Travis
2013-03-12 20:09 ` Eric W. Biederman
2013-03-12 20:23 ` Greg Kroah-Hartman
@ 2013-03-12 22:01 ` Thomas Gleixner
2013-03-12 22:08 ` Mike Travis
2 siblings, 1 reply; 28+ messages in thread
From: Thomas Gleixner @ 2013-03-12 22:01 UTC (permalink / raw)
To: Mike Travis
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Tim Bird,
Anton Vorontsov, Sasha Levin, Rusty Russell, Greg Kroah-Hartman,
Cong Wang, Stephen Boyd, Al Viro, Oleg Nesterov,
Eric W. Biederman, Serge Hallyn
On Tue, 12 Mar 2013, Mike Travis wrote:
> This patch adds some important KDB functions to be externally
> usable by loadable KDB modules. Note that often drivers bring
> in KDB modules for debugging, and in the past KDB has not been
> limited to use by GPL only modules. This patch restores KDB
> usefullness to non-GPL modules.
Which past? We only care about Linus git tree as THE past.
> -EXPORT_SYMBOL_GPL(kdb_register);
> +EXPORT_SYMBOL(kdb_register);
AFAICT that function has never been an non GPL symbol in Linus
tree. Whatever the original out of tree kdb stuff used is totally
irrelevant.
Stop trying to resolve your companys or your companys customers legal
issues by false claims.
The GPL is there for a reason.
Aside of that the whole attempt to export stuff which has been not
exported before without the _GPL extension is also:
Nacked-by: Thomas Gleixner <tglx@linutronix.de>
Thanks,
tglx
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 05/14] KDB: add more exports for supporting KDB modules
2013-03-12 22:01 ` Thomas Gleixner
@ 2013-03-12 22:08 ` Mike Travis
0 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 22:08 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Tim Bird,
Anton Vorontsov, Sasha Levin, Rusty Russell, Greg Kroah-Hartman,
Cong Wang, Stephen Boyd, Al Viro, Oleg Nesterov,
Eric W. Biederman, Serge Hallyn
On 3/12/2013 3:01 PM, Thomas Gleixner wrote:
> On Tue, 12 Mar 2013, Mike Travis wrote:
>> This patch adds some important KDB functions to be externally
>> usable by loadable KDB modules. Note that often drivers bring
>> in KDB modules for debugging, and in the past KDB has not been
>> limited to use by GPL only modules. This patch restores KDB
>> usefullness to non-GPL modules.
>
> Which past? We only care about Linus git tree as THE past.
>
>> -EXPORT_SYMBOL_GPL(kdb_register);
>> +EXPORT_SYMBOL(kdb_register);
>
> AFAICT that function has never been an non GPL symbol in Linus
> tree. Whatever the original out of tree kdb stuff used is totally
> irrelevant.
>
> Stop trying to resolve your companys or your companys customers legal
> issues by false claims.
>
> The GPL is there for a reason.
>
> Aside of that the whole attempt to export stuff which has been not
> exported before without the _GPL extension is also:
>
> Nacked-by: Thomas Gleixner <tglx@linutronix.de>
>
> Thanks,
>
> tglx
>
No problem, as I mentioned I don't care nor am I trying to resolve
anything except the problems of running Linux on the UV system.
There is no hidden agenda.
I will wait though for more feedback on the other patches before
submitting a 'v2' version.
Thanks,
Mike
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 06/14] KDB: consolidate KDB grep code
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (4 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 05/14] KDB: add more exports for supporting KDB modules Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 07/14] KDB: clean up KDB grep code, add some options Mike Travis
` (7 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Tim Bird,
Anton Vorontsov, Sasha Levin, Rusty Russell, Greg Kroah-Hartman,
Vincent Stehlé, Andrei Warkentin
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: kdb-consolidate-grep-cmd.patch --]
[-- Type: text/plain, Size: 10017 bytes --]
This patch consolidates various parts of the grep code in KDB
into a new file, kdb_grep.c, in preparation of various cleanups
and additions.
Cc: Tim Bird <tim.bird@am.sony.com>
Cc: Anton Vorontsov <anton.vorontsov@linaro.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Vincent Stehlé" <vincent.stehle@laposte.net>
Cc: Andrei Warkentin <andrey.warkentin@gmail.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
kernel/debug/kdb/Makefile | 2
kernel/debug/kdb/kdb_grep.c | 145 +++++++++++++++++++++++++++++++++++++++++
kernel/debug/kdb/kdb_io.c | 38 ----------
kernel/debug/kdb/kdb_main.c | 92 --------------------------
kernel/debug/kdb/kdb_private.h | 4 +
5 files changed, 152 insertions(+), 129 deletions(-)
--- linux.orig/kernel/debug/kdb/Makefile
+++ linux/kernel/debug/kdb/Makefile
@@ -7,7 +7,7 @@
#
CCVERSION := $(shell $(CC) -v 2>&1 | sed -ne '$$p')
-obj-y := kdb_io.o kdb_main.o kdb_support.o kdb_bt.o gen-kdb_cmds.o kdb_bp.o kdb_debugger.o
+obj-y := kdb_io.o kdb_main.o kdb_support.o kdb_bt.o gen-kdb_cmds.o kdb_bp.o kdb_grep.o kdb_debugger.o
obj-$(CONFIG_KDB_KEYBOARD) += kdb_keyboard.o
clean-files := gen-kdb_cmds.c
--- /dev/null
+++ linux/kernel/debug/kdb/kdb_grep.c
@@ -0,0 +1,145 @@
+/*
+ * Kernel Debugger Architecture Grep Support
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2004,2013 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
+ */
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/kdb.h>
+#include "kdb_private.h"
+
+#define GREP_LEN 256
+char kdb_grep_string[GREP_LEN];
+int kdb_grepping_flag;
+EXPORT_SYMBOL(kdb_grepping_flag);
+int kdb_grep_leading;
+int kdb_grep_trailing;
+
+/*
+ * The "str" argument may point to something like | grep xyz
+ */
+void kdb_grep_parse(const char *str)
+{
+ int len;
+ char *cp = (char *)str, *cp2;
+
+ /* sanity check: we should have been called with the \ first */
+ if (*cp != '|')
+ return;
+ cp++;
+ while (isspace(*cp))
+ cp++;
+ if (strncmp(cp, "grep ", 5)) {
+ kdb_printf("invalid 'pipe', see grephelp\n");
+ return;
+ }
+ cp += 5;
+ while (isspace(*cp))
+ cp++;
+ cp2 = strchr(cp, '\n');
+ if (cp2)
+ *cp2 = '\0'; /* remove the trailing newline */
+ len = strlen(cp);
+ if (len == 0) {
+ kdb_printf("invalid 'pipe', see grephelp\n");
+ return;
+ }
+ /* now cp points to a nonzero length search string */
+ if (*cp == '"') {
+ /* allow it be "x y z" by removing the "'s - there must
+ be two of them */
+ cp++;
+ cp2 = strchr(cp, '"');
+ if (!cp2) {
+ kdb_printf("invalid quoted string, see grephelp\n");
+ return;
+ }
+ *cp2 = '\0'; /* end the string where the 2nd " was */
+ }
+ kdb_grep_leading = 0;
+ if (*cp == '^') {
+ kdb_grep_leading = 1;
+ cp++;
+ }
+ len = strlen(cp);
+ kdb_grep_trailing = 0;
+ if (*(cp+len-1) == '$') {
+ kdb_grep_trailing = 1;
+ *(cp+len-1) = '\0';
+ }
+ len = strlen(cp);
+ if (!len)
+ return;
+ if (len >= GREP_LEN) {
+ kdb_printf("search string too long\n");
+ return;
+ }
+ strcpy(kdb_grep_string, cp);
+ kdb_grepping_flag++;
+ return;
+}
+
+
+/*
+ * search arg1 to see if it contains arg2
+ * (kdmain.c provides flags for ^pat and pat$)
+ *
+ * return 1 for found, 0 for not found
+ */
+int kdb_grep_search(char *searched)
+{
+ char firstchar, *cp;
+ char *searchfor = kdb_grep_string;
+ int len1, len2;
+
+ /* not counting the newline at the end of "searched" */
+ len1 = strlen(searched)-1;
+ len2 = strlen(searchfor);
+ if (len1 < len2)
+ return 0;
+ if (kdb_grep_leading && kdb_grep_trailing && len1 != len2)
+ return 0;
+ if (kdb_grep_leading) {
+ if (!strncmp(searched, searchfor, len2))
+ return 1;
+ } else if (kdb_grep_trailing) {
+ if (!strncmp(searched+len1-len2, searchfor, len2))
+ return 1;
+ } else {
+ firstchar = *searchfor;
+ cp = searched;
+ while ((cp = strchr(cp, firstchar))) {
+ if (!strncmp(cp, searchfor, len2))
+ return 1;
+ cp++;
+ }
+ }
+ return 0;
+}
+
+
+
+/*
+ * display help for the use of cmd | grep pattern
+ */
+int kdb_grep_help(int argc, const char **argv)
+{
+ kdb_printf("Usage of cmd args | grep pattern:\n");
+ kdb_printf(" Any command's output may be filtered through an ");
+ kdb_printf("emulated 'pipe'.\n");
+ kdb_printf(" 'grep' is just a key word.\n");
+ kdb_printf(
+ " The pattern may include a very limited set of metacharacters:\n");
+ kdb_printf(" pattern or ^pattern or pattern$ or ^pattern$\n");
+ kdb_printf(
+ " And if there are spaces in the pattern, you may quote it:\n");
+ kdb_printf(
+ " \"pat tern\" or \"^pat tern\" or \"pat tern$\" or \"^pat tern$\"\n");
+ return 0;
+}
--- linux.orig/kernel/debug/kdb/kdb_io.c
+++ linux/kernel/debug/kdb/kdb_io.c
@@ -514,42 +514,6 @@ static char *next_avail = kdb_buffer;
static int size_avail;
static int suspend_grep;
-/*
- * search arg1 to see if it contains arg2
- * (kdmain.c provides flags for ^pat and pat$)
- *
- * return 1 for found, 0 for not found
- */
-static int kdb_search_string(char *searched, char *searchfor)
-{
- char firstchar, *cp;
- int len1, len2;
-
- /* not counting the newline at the end of "searched" */
- len1 = strlen(searched)-1;
- len2 = strlen(searchfor);
- if (len1 < len2)
- return 0;
- if (kdb_grep_leading && kdb_grep_trailing && len1 != len2)
- return 0;
- if (kdb_grep_leading) {
- if (!strncmp(searched, searchfor, len2))
- return 1;
- } else if (kdb_grep_trailing) {
- if (!strncmp(searched+len1-len2, searchfor, len2))
- return 1;
- } else {
- firstchar = *searchfor;
- cp = searched;
- while ((cp = strchr(cp, firstchar))) {
- if (!strncmp(cp, searchfor, len2))
- return 1;
- cp++;
- }
- }
- return 0;
-}
-
int vkdb_printf(const char *fmt, va_list ap)
{
int diag;
@@ -668,7 +632,7 @@ int vkdb_printf(const char *fmt, va_list
* Only continue with this output if it contains the
* search string.
*/
- fnd = kdb_search_string(kdb_buffer, kdb_grep_string);
+ fnd = kdb_grep_search(kdb_buffer);
if (!fnd) {
/*
* At this point the complete line at the start
--- linux.orig/kernel/debug/kdb/kdb_main.c
+++ linux/kernel/debug/kdb/kdb_main.c
@@ -42,13 +42,6 @@
#include <linux/slab.h>
#include "kdb_private.h"
-#define GREP_LEN 256
-char kdb_grep_string[GREP_LEN];
-int kdb_grepping_flag;
-EXPORT_SYMBOL(kdb_grepping_flag);
-int kdb_grep_leading;
-int kdb_grep_trailing;
-
/*
* Kernel debugger state flags
*/
@@ -768,70 +761,6 @@ static char cmd_hist[KDB_CMD_HISTORY_COU
static char cmd_cur[CMD_BUFLEN];
/*
- * The "str" argument may point to something like | grep xyz
- */
-static void parse_grep(const char *str)
-{
- int len;
- char *cp = (char *)str, *cp2;
-
- /* sanity check: we should have been called with the \ first */
- if (*cp != '|')
- return;
- cp++;
- while (isspace(*cp))
- cp++;
- if (strncmp(cp, "grep ", 5)) {
- kdb_printf("invalid 'pipe', see grephelp\n");
- return;
- }
- cp += 5;
- while (isspace(*cp))
- cp++;
- cp2 = strchr(cp, '\n');
- if (cp2)
- *cp2 = '\0'; /* remove the trailing newline */
- len = strlen(cp);
- if (len == 0) {
- kdb_printf("invalid 'pipe', see grephelp\n");
- return;
- }
- /* now cp points to a nonzero length search string */
- if (*cp == '"') {
- /* allow it be "x y z" by removing the "'s - there must
- be two of them */
- cp++;
- cp2 = strchr(cp, '"');
- if (!cp2) {
- kdb_printf("invalid quoted string, see grephelp\n");
- return;
- }
- *cp2 = '\0'; /* end the string where the 2nd " was */
- }
- kdb_grep_leading = 0;
- if (*cp == '^') {
- kdb_grep_leading = 1;
- cp++;
- }
- len = strlen(cp);
- kdb_grep_trailing = 0;
- if (*(cp+len-1) == '$') {
- kdb_grep_trailing = 1;
- *(cp+len-1) = '\0';
- }
- len = strlen(cp);
- if (!len)
- return;
- if (len >= GREP_LEN) {
- kdb_printf("search string too long\n");
- return;
- }
- strcpy(kdb_grep_string, cp);
- kdb_grepping_flag++;
- return;
-}
-
-/*
* kdb_parse - Parse the command line, search the command table for a
* matching command and invoke the command function. This
* function may be called recursively, if it is, the second call
@@ -943,7 +872,7 @@ int kdb_parse(const char *cmdstr)
if (!argc)
return 0;
if (check_grep)
- parse_grep(cp);
+ kdb_grep_parse(cp);
if (defcmd_in_progress) {
int result = kdb_defcmd2(cmdstr, argv[0]);
if (!defcmd_in_progress) {
@@ -2680,25 +2609,6 @@ static int kdb_per_cpu(int argc, const c
return 0;
}
-/*
- * display help for the use of cmd | grep pattern
- */
-static int kdb_grep_help(int argc, const char **argv)
-{
- kdb_printf("Usage of cmd args | grep pattern:\n");
- kdb_printf(" Any command's output may be filtered through an ");
- kdb_printf("emulated 'pipe'.\n");
- kdb_printf(" 'grep' is just a key word.\n");
- kdb_printf(" The pattern may include a very limited set of "
- "metacharacters:\n");
- kdb_printf(" pattern or ^pattern or pattern$ or ^pattern$\n");
- kdb_printf(" And if there are spaces in the pattern, you may "
- "quote it:\n");
- kdb_printf(" \"pat tern\" or \"^pat tern\" or \"pat tern$\""
- " or \"^pat tern$\"\n");
- return 0;
-}
-
/*
* kdb_register_repeat - This function is used to register a kernel
* debugger command.
--- linux.orig/kernel/debug/kdb/kdb_private.h
+++ linux/kernel/debug/kdb/kdb_private.h
@@ -159,6 +159,10 @@ extern int kdb_grepping_flag;
extern char kdb_grep_string[];
extern int kdb_grep_leading;
extern int kdb_grep_trailing;
+extern void kdb_grep_parse(const char *str);
+extern int kdb_grep_search(char *searched);
+extern int kdb_grep_help(int argc, const char **argv);
+
extern char *kdb_cmds[];
extern unsigned long kdb_task_state_string(const char *);
extern char kdb_task_state_char (const struct task_struct *);
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 07/14] KDB: clean up KDB grep code, add some options
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (5 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 06/14] KDB: consolidate KDB grep code Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 08/14] KDB: Restore call to kdump from KDB Mike Travis
` (6 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Tim Bird,
Anton Vorontsov, Sasha Levin, Rusty Russell, Greg Kroah-Hartman,
Vincent Stehlé, Andrei Warkentin
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: kdb-update-grep-cmd.patch --]
[-- Type: text/plain, Size: 18912 bytes --]
This patch cleans up the grep 'pipe' code in KDB and adds some new options:
* allows multiple '| grep' options to be used.
* adds '-v' flag to invert the search.
* adds '-o' flag for optional ('OR') patterns.
* adds '-u' flag to delay printing until match found.
Options may be mixed in any combination.
Cc: Tim Bird <tim.bird@am.sony.com>
Cc: Anton Vorontsov <anton.vorontsov@linaro.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Vincent Stehlé" <vincent.stehle@laposte.net>
Cc: Andrei Warkentin <andrey.warkentin@gmail.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
kernel/debug/kdb/kdb_grep.c | 352 +++++++++++++++++++++++++++++++++--------
kernel/debug/kdb/kdb_io.c | 39 ++--
kernel/debug/kdb/kdb_main.c | 10 -
kernel/debug/kdb/kdb_private.h | 55 +++++-
4 files changed, 361 insertions(+), 95 deletions(-)
--- linux.orig/kernel/debug/kdb/kdb_grep.c
+++ linux/kernel/debug/kdb/kdb_grep.c
@@ -11,80 +11,224 @@
#include <linux/ctype.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <linux/kdb.h>
#include "kdb_private.h"
-#define GREP_LEN 256
-char kdb_grep_string[GREP_LEN];
-int kdb_grepping_flag;
+#define KDB_GREP_PATT_LEN 511
+#define KDB_GREP_MAX 8
+
+static char kdb_grep_patterns[KDB_GREP_PATT_LEN+1];
+static int kdb_grep_pattern_idx;
+
+/* Note: kdb_grep_stack[0] intentially left zero */
+struct kdb_grep_stack_s kdb_grep_stack[KDB_GREP_MAX+1];
+int kdb_grepping_flag; /* now kdb_grep_stack index */
EXPORT_SYMBOL(kdb_grepping_flag);
-int kdb_grep_leading;
-int kdb_grep_trailing;
-/*
- * The "str" argument may point to something like | grep xyz
- */
-void kdb_grep_parse(const char *str)
+static void kdb_grep_stack_clear(void)
{
- int len;
- char *cp = (char *)str, *cp2;
+ kdb_grep_stack[kdb_grepping_flag].flags = 0;
+ kdb_grep_stack[kdb_grepping_flag].pattern_idx = 0;
+}
+
+static int kdb_grep_push(void)
+{
+ if (kdb_grepping_flag < KDB_GREP_MAX) {
+ ++kdb_grepping_flag;
+ kdb_grep_stack_clear();
+ kdb_grep_set(enabled);
+ return 1;
+ }
+ return 0;
+}
+
+static void kdb_grep_pop(void)
+{
+ if (kdb_grepping_flag > 0) {
+ kdb_grep_pattern_idx =
+ kdb_grep_stack[kdb_grepping_flag].pattern_idx;
+
+ kdb_grep_patterns[kdb_grep_pattern_idx] = '\0';
+
+ if (kdb_grep(suspended))
+ kdb_grep_set_lvl(suspended, kdb_grepping_flag - 1);
+
+ kdb_grep_stack_clear();
+ --kdb_grepping_flag;
+
+ if (!kdb_grep(enabled))
+ kdb_grep_pop();
+ }
+}
+
+void kdb_grep_clear_all(void)
+{
+ kdb_grepping_flag = 0;
+ kdb_grep_pattern_idx = 0;
+ kdb_grep_patterns[0] = 0;
+ memset(kdb_grep_stack, 0, sizeof(kdb_grep_stack));
+}
+
+static int kdb_grep_error(const char *str)
+{
+ kdb_grep_clear_all();
+ kdb_printf("grep error: %s, see grephelp\n", str);
+ return -1;
+}
- /* sanity check: we should have been called with the \ first */
+static const char *kdb_grep_pattern(int lvl)
+{
+ return &kdb_grep_patterns[kdb_grep_stack[lvl].pattern_idx];
+}
+
+static int kdb_grep_add_pattern(char *str)
+{
+ int len = strlen(str);
+
+ if (!len) {
+ kdb_grep_error("empty search pattern");
+ return 0;
+ }
+
+ if ((kdb_grep_pattern_idx + len) >= KDB_GREP_PATT_LEN) {
+ kdb_grep_error("search string(s) too long");
+ return 0;
+ }
+
+ /* copy string into pattern(s) buffer */
+ kdb_grep_stack[kdb_grepping_flag].pattern_idx = kdb_grep_pattern_idx;
+ strcpy((char *)kdb_grep_pattern(kdb_grepping_flag), str);
+ kdb_grep_pattern_idx += len + 1;
+ kdb_grep_patterns[kdb_grep_pattern_idx] = '\0';
+ return 1;
+}
+
+static char *is_grep(const char *cp)
+{
+ /* sanity check: we should have been called with the | first */
if (*cp != '|')
- return;
+ return 0;
cp++;
while (isspace(*cp))
cp++;
+
if (strncmp(cp, "grep ", 5)) {
- kdb_printf("invalid 'pipe', see grephelp\n");
- return;
+ kdb_grep_error("invalid 'pipe'");
+ return NULL;
}
cp += 5;
+ return (char *)cp;
+}
+
+/*
+ * The "str" argument may point to something like | grep xyz
+ */
+int kdb_grep_parse(char *str)
+{
+ int len;
+ char *cp, *cp2;
+ char *newgrep;
+
+ cp = is_grep(str);
+ if (!cp)
+ return -1;
+repeat:
+ if (!kdb_grep_push())
+ return kdb_grep_error("too many grep's");
+
+ newgrep = NULL;
+
while (isspace(*cp))
cp++;
+
+ /* process possible options */
+ for (cp2 = cp; *cp2 == '-'; cp2 = cp) {
+ if (*++cp2 == '\0' || isspace(*cp2))
+ return kdb_grep_error("illegal option");
+
+ while (*cp2) {
+ switch (*cp2) {
+ case 'o':
+ kdb_grep_set(optional);
+ cp2++;
+ continue;
+ case 'u':
+ kdb_grep_set(until);
+ cp2++;
+ continue;
+ case 'v':
+ kdb_grep_set(inverted);
+ cp2++;
+ continue;
+ case ' ':
+ case '-':
+ break;
+ default:
+ return kdb_grep_error("illegal option");
+ }
+ break;
+ }
+ cp = cp2;
+ if (*cp == '-') {
+ cp++;
+ break;
+ }
+ while (isspace(*cp))
+ cp++;
+ }
+
+ cp2 = strchr(cp, '|');
+ if (cp2) { /* another '| grep' follows */
+ newgrep = is_grep(cp2);
+ if (!newgrep)
+ return -1;
+ *cp2 = '\0';
+ }
+
cp2 = strchr(cp, '\n');
- if (cp2)
- *cp2 = '\0'; /* remove the trailing newline */
+ if (cp2) /* remove the trailing newline */
+ *cp2 = '\0';
+
len = strlen(cp);
- if (len == 0) {
- kdb_printf("invalid 'pipe', see grephelp\n");
- return;
- }
+ while (len > 0 && isspace(cp[len-1])) /* trim trailing spaces */
+ cp[--len] = '\0';
+
+ if (len == 0)
+ return kdb_grep_error("pattern missing");
+
/* now cp points to a nonzero length search string */
if (*cp == '"') {
- /* allow it be "x y z" by removing the "'s - there must
- be two of them */
+ /*
+ * allow it be "x y z" by removing the "'s,
+ * - there must be two of them
+ */
cp++;
cp2 = strchr(cp, '"');
- if (!cp2) {
- kdb_printf("invalid quoted string, see grephelp\n");
- return;
- }
+ if (!cp2)
+ return kdb_grep_error("invalid quoted string");
+
*cp2 = '\0'; /* end the string where the 2nd " was */
}
- kdb_grep_leading = 0;
if (*cp == '^') {
- kdb_grep_leading = 1;
+ kdb_grep_set(leading);
cp++;
}
len = strlen(cp);
- kdb_grep_trailing = 0;
if (*(cp+len-1) == '$') {
- kdb_grep_trailing = 1;
+ kdb_grep_set(trailing);
*(cp+len-1) = '\0';
}
- len = strlen(cp);
- if (!len)
- return;
- if (len >= GREP_LEN) {
- kdb_printf("search string too long\n");
- return;
- }
- strcpy(kdb_grep_string, cp);
- kdb_grepping_flag++;
- return;
-}
+ if (!kdb_grep_add_pattern(cp))
+ return kdb_grep_error("too many pattern characters");
+ if (newgrep) {
+ cp = newgrep;
+ goto repeat;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(kdb_grep_parse);
/*
* search arg1 to see if it contains arg2
@@ -92,10 +236,11 @@ void kdb_grep_parse(const char *str)
*
* return 1 for found, 0 for not found
*/
-int kdb_grep_search(char *searched)
+static int kdb_search_string(const char *searched, int lvl)
{
- char firstchar, *cp;
- char *searchfor = kdb_grep_string;
+ char firstchar;
+ const char *cp;
+ const char *searchfor = kdb_grep_pattern(lvl);
int len1, len2;
/* not counting the newline at the end of "searched" */
@@ -103,12 +248,15 @@ int kdb_grep_search(char *searched)
len2 = strlen(searchfor);
if (len1 < len2)
return 0;
- if (kdb_grep_leading && kdb_grep_trailing && len1 != len2)
+ if (kdb_grep_lvl(leading, lvl)
+ && kdb_grep_lvl(trailing, lvl)
+ && len1 != len2)
return 0;
- if (kdb_grep_leading) {
+
+ if (kdb_grep_lvl(leading, lvl)) {
if (!strncmp(searched, searchfor, len2))
return 1;
- } else if (kdb_grep_trailing) {
+ } else if (kdb_grep_lvl(trailing, lvl)) {
if (!strncmp(searched+len1-len2, searchfor, len2))
return 1;
} else {
@@ -123,23 +271,105 @@ int kdb_grep_search(char *searched)
return 0;
}
+int kdb_grep_search(const char *searched)
+{
+ int lvl;
+ int pmatch;
+ int match = 1;
+ int oc = 0, om = 0;
+
+ if (!kdb_grepping_flag)
+ return 1;
+
+ for (lvl = 1; lvl <= kdb_grepping_flag; lvl++) {
+ if (!kdb_grep_lvl(enabled, lvl))
+ continue;
+
+ if (!kdb_grep_lvl(optional, lvl)) {
+ if (oc && !om)
+ break;
+ oc = om = 0;
+ }
+
+ pmatch = kdb_search_string(searched, lvl);
+ if (kdb_grep_lvl(inverted, lvl))
+ pmatch ^= 1;
+
+ if (kdb_grep_lvl(optional, lvl)) {
+ oc++;
+ if (pmatch)
+ om++;
+
+ } else if (!pmatch) {
+ match = 0;
+ break;
+ }
+
+ if (pmatch && kdb_grep_lvl(until, lvl)) {
+ if (lvl == kdb_grepping_flag)
+ kdb_grep_pop();
+ else
+ kdb_grep_clear_lvl(enabled, lvl);
+ }
+ }
+
+ if (oc && !om)
+ return 0;
+
+ return match;
+}
+EXPORT_SYMBOL(kdb_grep_search);
/*
- * display help for the use of cmd | grep pattern
+ * display help for the use of <cmd> <args> | grep <pattern>
*/
-int kdb_grep_help(int argc, const char **argv)
+static char *kdb_grep_help_list[] = {
+ "Usage of <cmd> <args> | grep <pattern> [| grep <pattern> ...]\n",
+ " Any command's output may be filtered through an emulated 'pipe'.\n",
+ " 'grep' is just a key word.\n",
+ " 'grep -v' to invert the search.\n",
+ " 'grep -o' for optional ('OR') <pattern>.\n",
+ " 'grep -u' to delay printing until <pattern> found.\n",
+ " Flags may be mixed and matched. Use '--' before patterns starting with '-'.\n",
+ " If consecutive patterns are 'optional' at least one must match.\n",
+ " The pattern may include a very limited set of metacharacters:\n",
+ " pattern or ^pattern or pattern$ or ^pattern$\n",
+ " And if there are spaces in the pattern, you may quote it:\n",
+ " \"pat tern\" or \"^pat tern\" or \"pat tern$\" or \"^pat tern$\"\n",
+ ""
+};
+
+static int kdb_grep_help(int argc, const char **argv)
{
- kdb_printf("Usage of cmd args | grep pattern:\n");
- kdb_printf(" Any command's output may be filtered through an ");
- kdb_printf("emulated 'pipe'.\n");
- kdb_printf(" 'grep' is just a key word.\n");
- kdb_printf(
- " The pattern may include a very limited set of metacharacters:\n");
- kdb_printf(" pattern or ^pattern or pattern$ or ^pattern$\n");
- kdb_printf(
- " And if there are spaces in the pattern, you may quote it:\n");
- kdb_printf(
- " \"pat tern\" or \"^pat tern\" or \"pat tern$\" or \"^pat tern$\"\n");
+ int i;
+
+ for (i = 0; *kdb_grep_help_list[i]; i++)
+ kdb_printf(kdb_grep_help_list[i]);
+
+ kdb_printf(" The '| grep' may be repeated up to %d times.\n",
+ KDB_GREP_MAX);
+
+ kdb_printf(" Max chars in all patterns (incl. NULLs) is %d.\n",
+ KDB_GREP_PATT_LEN);
return 0;
}
+
+static int __init kdb_grep_init(void)
+{
+ kdb_register_repeat("grephelp", kdb_grep_help, "",
+ "Display help on | grep", 0, KDB_REPEAT_NONE);
+
+ kdb_grep_clear_all();
+ pr_info("kdb_grep registered\n");
+ return 0;
+}
+
+static void __exit kdb_grep_exit(void)
+{
+ kdb_unregister("grephelp");
+}
+
+module_init(kdb_grep_init);
+module_exit(kdb_grep_exit);
+
--- linux.orig/kernel/debug/kdb/kdb_io.c
+++ linux/kernel/debug/kdb/kdb_io.c
@@ -504,7 +504,7 @@ empty:
* kdb output.
*
* If the user is doing a cmd args | grep srch
- * then kdb_grepping_flag is set.
+ * then kdb_grep(enabled) is set.
* In that case we need to accumulate full lines (ending in \n) before
* searching for the pattern.
*/
@@ -512,7 +512,6 @@ empty:
static char kdb_buffer[256]; /* A bit too big to go on stack */
static char *next_avail = kdb_buffer;
static int size_avail;
-static int suspend_grep;
int vkdb_printf(const char *fmt, va_list ap)
{
@@ -523,7 +522,7 @@ int vkdb_printf(const char *fmt, va_list
int saved_trap_printk;
int got_printf_lock = 0;
int retlen = 0;
- int fnd, len;
+ int len;
char *cp, *cp2, *cphold = NULL, replaced_byte = ' ';
const char *ostring;
char *moreprompt = "more> ";
@@ -560,7 +559,7 @@ int vkdb_printf(const char *fmt, va_list
if (diag)
logging = 0;
- if (!kdb_grepping_flag || suspend_grep) {
+ if (!kdb_grep(enabled) || kdb_grep(suspended)) {
/* normally, every vsnprintf starts a new buffer */
next_avail = kdb_buffer;
size_avail = sizeof(kdb_buffer);
@@ -568,15 +567,15 @@ int vkdb_printf(const char *fmt, va_list
vsnprintf(next_avail, size_avail, fmt, ap);
/*
- * If kdb_parse() found that the command was cmd xxx | grep yyy
- * then kdb_grepping_flag is set, and kdb_grep_string contains yyy
+ * If kdb_grep(enabled) is set, accumulate the print data up to a
+ * newline before 'kdb_grep_search'ing for it. kdb_grep(suspended)
+ * is disable it temporarily for kdb_printf to output prompts, etc.
*
- * Accumulate the print data up to a newline before searching it.
* (vsnprintf does null-terminate the string that it generates)
*/
/* skip the search if prints are temporarily unconditional */
- if (!suspend_grep && kdb_grepping_flag) {
+ if (!kdb_grep(suspended) && kdb_grep(enabled)) {
cp = strchr(kdb_buffer, '\n');
if (!cp) {
/*
@@ -588,7 +587,7 @@ int vkdb_printf(const char *fmt, va_list
* The "[nn]more " prompt should also be
* (MOREPROMPT -> moreprompt)
* written * but we print that ourselves,
- * we set the suspend_grep flag to make
+ * we set the kdb_grep(suspended) flag to make
* it unconditional.
*
*/
@@ -606,7 +605,7 @@ int vkdb_printf(const char *fmt, va_list
* command, so we can go back
* to normal mode.
*/
- kdb_grepping_flag = 0;
+ kdb_grep_clear_all();
goto kdb_printit;
}
}
@@ -632,8 +631,7 @@ int vkdb_printf(const char *fmt, va_list
* Only continue with this output if it contains the
* search string.
*/
- fnd = kdb_grep_search(kdb_buffer);
- if (!fnd) {
+ if (!kdb_grep_search(kdb_buffer)) {
/*
* At this point the complete line at the start
* of kdb_buffer can be discarded, as it does
@@ -753,23 +751,23 @@ kdb_printit:
KDB_FLAG_SET(CMD_INTERRUPT); /* command interrupted */
KDB_STATE_CLEAR(PAGER);
/* end of command output; back to normal mode */
- kdb_grepping_flag = 0;
+ kdb_grep_clear_all();
kdb_printf("\n");
} else if (buf1[0] == ' ') {
kdb_printf("\r");
- suspend_grep = 1; /* for this recursion */
+ kdb_grep_set(suspended); /* for this recursion */
} else if (buf1[0] == '\n') {
kdb_nextline = linecount - 1;
kdb_printf("\r");
- suspend_grep = 1; /* for this recursion */
+ kdb_grep_set(suspended); /* for this recursion */
} else if (buf1[0] && buf1[0] != '\n') {
/* user hit something other than enter */
- suspend_grep = 1; /* for this recursion */
+ kdb_grep_set(suspended); /* for this recursion */
kdb_printf("\nOnly 'q' or 'Q' are processed at more "
"prompt, input ignored\n");
- } else if (kdb_grepping_flag) {
+ } else if (kdb_grep(enabled)) {
/* user hit enter */
- suspend_grep = 1; /* for this recursion */
+ kdb_grep_set(suspended); /* for this recursion */
kdb_printf("\n");
}
kdb_input_flush();
@@ -781,7 +779,7 @@ kdb_printit:
* the terminating null, and cphold points to the null.
* Then adjust the notion of available space in the buffer.
*/
- if (kdb_grepping_flag && !suspend_grep) {
+ if (kdb_grep(enabled) && !kdb_grep(suspended)) {
*cphold = replaced_byte;
strcpy(kdb_buffer, cphold);
len = strlen(kdb_buffer);
@@ -790,7 +788,8 @@ kdb_printit:
}
kdb_print_out:
- suspend_grep = 0; /* end of what may have been a recursive call */
+ /* end of what may have been a recursive call */
+ kdb_grep_clear(suspended);
if (logging)
console_loglevel = saved_loglevel;
if (KDB_STATE(PRINTF_LOCK) && got_printf_lock) {
--- linux.orig/kernel/debug/kdb/kdb_main.c
+++ linux/kernel/debug/kdb/kdb_main.c
@@ -812,13 +812,13 @@ int kdb_parse(const char *cmdstr)
char *cp;
char *cpp, quoted;
kdbtab_t *tp;
- int i, escaped, ignore_errors = 0, check_grep;
+ int i, escaped, ignore_errors = 0, check_grep = 0;
/*
* First tokenize the command string.
*/
cp = (char *)cmdstr;
- kdb_grepping_flag = check_grep = 0;
+ kdb_grep_clear_all();
if (KDB_FLAG(CMD_INTERRUPT)) {
/* Previous command was interrupted, newline must not
@@ -887,8 +887,8 @@ int kdb_parse(const char *cmdstr)
}
if (!argc)
return 0;
- if (check_grep)
- kdb_grep_parse(cp);
+ if (check_grep && kdb_grep_parse(cp))
+ return KDB_NOTFOUND; /* '| grep' error */
if (defcmd_in_progress) {
int result = kdb_defcmd2(cmdstr, argv[0]);
if (!defcmd_in_progress) {
@@ -2758,8 +2758,6 @@ static void __init kdb_inittab(void)
"Summarize the system", 4, KDB_REPEAT_NONE);
kdb_register_repeat("per_cpu", kdb_per_cpu, "<sym> [<bytes>] [<cpu>]",
"Display per_cpu variables", 3, KDB_REPEAT_NONE);
- kdb_register_repeat("grephelp", kdb_grep_help, "",
- "Display help on | grep", 0, KDB_REPEAT_NONE);
}
/* Execute any commands defined in kdb_cmds. */
--- linux.orig/kernel/debug/kdb/kdb_private.h
+++ linux/kernel/debug/kdb/kdb_private.h
@@ -151,14 +151,6 @@ extern int kdb_main_loop(kdb_reason_t, k
int, kdb_dbtrap_t, struct pt_regs *);
/* Miscellaneous functions and data areas */
-extern int kdb_grepping_flag;
-extern char kdb_grep_string[];
-extern int kdb_grep_leading;
-extern int kdb_grep_trailing;
-extern void kdb_grep_parse(const char *str);
-extern int kdb_grep_search(char *searched);
-extern int kdb_grep_help(int argc, const char **argv);
-
extern char *kdb_cmds[];
extern unsigned long kdb_task_state_string(const char *);
extern char kdb_task_state_char (const struct task_struct *);
@@ -181,5 +173,52 @@ extern char kdb_prompt_str[];
#define KDB_WORD_SIZE ((int)sizeof(unsigned long))
+/* kdb grep options */
+enum kdb_grep_flags {
+ kdb_grep_enabled,
+ kdb_grep_suspended,
+ kdb_grep_leading,
+ kdb_grep_trailing,
+ kdb_grep_inverted,
+ kdb_grep_until,
+ kdb_grep_optional
+};
+
+struct kdb_grep_stack_s {
+ unsigned short flags;
+ unsigned short pattern_idx;
+};
+
+extern int kdb_grepping_flag;
+extern struct kdb_grep_stack_s kdb_grep_stack[];
+extern void kdb_grep_clear_all(void);
+extern int kdb_grep_search(const char *searched);
+extern int kdb_grep_parse(char *str);
+
+#define kdb_grep_flag(flag) (1 << kdb_grep_##flag)
+
+#define kdb_grep_lvl(f, l) __kdb_grep_lvl(kdb_grep_flag(f), l)
+#define kdb_grep_set_lvl(f, l) __kdb_grep_set_lvl(kdb_grep_flag(f), l)
+#define kdb_grep_clear_lvl(f, l) __kdb_grep_clear_lvl(kdb_grep_flag(f), l)
+
+#define kdb_grep(flag) kdb_grep_lvl(flag, kdb_grepping_flag)
+#define kdb_grep_set(flag) kdb_grep_set_lvl(flag, kdb_grepping_flag)
+#define kdb_grep_clear(flag) kdb_grep_clear_lvl(flag, kdb_grepping_flag)
+
+static inline int __kdb_grep_lvl(unsigned short flag, int lvl)
+{
+ return !!(kdb_grep_stack[lvl].flags & flag);
+}
+
+static inline void __kdb_grep_set_lvl(unsigned int flag, int lvl)
+{
+ kdb_grep_stack[lvl].flags |= flag;
+}
+
+static inline void __kdb_grep_clear_lvl(unsigned int flag, int lvl)
+{
+ kdb_grep_stack[lvl].flags &= ~flag;
+}
+
#endif /* CONFIG_KGDB_KDB */
#endif /* !_KDBPRIVATE_H */
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 08/14] KDB: Restore call to kdump from KDB
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (6 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 07/14] KDB: clean up KDB grep code, add some options Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 09/14] KDB: Add pshelp command Mike Travis
` (5 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Anton Vorontsov,
Sasha Levin, Rusty Russell, Greg Kroah-Hartman
[-- Attachment #1: kdb-add-kdump-cmd.patch --]
[-- Type: text/plain, Size: 3942 bytes --]
This patch restores the capability of calling kdump from inside
KDB. First it returns to the original CPU that KDB was called
by, and also verifies that the crash_kexec kernel has been loaded.
Both are better than just using the 'sr c' option and possibly
hanging the system.
Cc: Anton Vorontsov <anton.vorontsov@linaro.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
include/linux/kdb.h | 7 +++
kernel/debug/kdb/kdb_main.c | 79 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+)
--- linux.orig/include/linux/kdb.h
+++ linux/include/linux/kdb.h
@@ -144,6 +144,13 @@ static inline const char *kdb_walk_kalls
}
#endif /* ! CONFIG_KALLSYMS */
+#if defined(CONFIG_KEXEC)
+enum {
+ KDB_KDUMP_RESET,
+ KDB_KDUMP_KDUMP,
+};
+#endif
+
/* Dynamic kdb shell command registration */
extern int kdb_register(char *, kdb_func_t, char *, char *, short);
extern int kdb_register_repeat(char *, kdb_func_t, char *, char *,
--- linux.orig/kernel/debug/kdb/kdb_main.c
+++ linux/kernel/debug/kdb/kdb_main.c
@@ -42,6 +42,10 @@
#include <linux/slab.h>
#include "kdb_private.h"
+#if defined(CONFIG_KEXEC)
+#include <linux/kexec.h>
+#endif
+
/*
* Kernel debugger state flags
*/
@@ -1052,6 +1056,73 @@ void kdb_set_current_task(struct task_st
}
EXPORT_SYMBOL(kdb_set_current_task);
+#if defined(CONFIG_KEXEC)
+
+static int kdb_kdump_state = KDB_KDUMP_RESET; /* KDB kdump state */
+
+static int kdb_cpu(int argc, const char **argv);
+
+/*
+ * kdb_kdump_check
+ *
+ * This is where the kdump on monarch cpu is handled.
+ *
+ */
+void kdb_kdump_check(struct pt_regs *regs)
+{
+ if (kdb_kdump_state != KDB_KDUMP_RESET) {
+ crash_kexec(regs);
+
+ /*
+ * If the call above returned then something didn't work
+ */
+ kdb_printf("kdb_kdump_check: crash_kexec failed!\n");
+ kdb_printf
+ ("Please check if the kdump kernel has been properly loaded\n");
+ kdb_kdump_state = KDB_KDUMP_RESET;
+ }
+}
+
+
+/*
+ * kdb_kdump
+ * This function implements the 'kdump' command.
+ *
+ * Returns:
+ * zero for success, a kdb diagnostic if error
+ */
+
+static int
+kdb_kdump(int argc, const char **argv)
+{
+ char cpu_id[8];
+ const char *cpu_argv[] = {NULL, cpu_id, NULL};
+ int ret = KDB_CMD_CPU;
+
+ if (!kexec_crash_image) {
+ kdb_printf("kdump error: crash kernel not loaded\n");
+ return KDB_NOTFOUND;
+ }
+
+ kdb_kdump_state = KDB_KDUMP_KDUMP;
+
+ /* Switch back to the initial cpu before process kdump command */
+ if (smp_processor_id() != kdb_initial_cpu) {
+ scnprintf(cpu_id, sizeof(cpu_id), "%d", kdb_initial_cpu);
+ ret = kdb_cpu(1, cpu_argv);
+ if (ret != KDB_CMD_CPU) {
+ kdb_printf
+ ("kdump: Failed to switch to initial cpu %d; aborted\n",
+ kdb_initial_cpu);
+ kdb_kdump_state = KDB_KDUMP_RESET;
+ }
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_KEXEC */
+
/*
* kdb_local - The main code for kdb. This routine is invoked on a
* specific processor, it is not global. The main kdb() routine
@@ -1079,6 +1150,10 @@ static int kdb_local(kdb_reason_t reason
struct task_struct *kdb_current =
kdb_curr_task(raw_smp_processor_id());
+#if defined(CONFIG_KEXEC)
+ kdb_kdump_check(regs);
+#endif
+
KDB_DEBUG_STATE("kdb_local 1", reason);
kdb_go_count = 0;
if (reason == KDB_REASON_DEBUG) {
@@ -2726,6 +2801,10 @@ static void __init kdb_inittab(void)
"Display Help Message", 0, KDB_REPEAT_NONE);
kdb_register_repeat("cpu", kdb_cpu, "<cpunum>",
"Switch to new cpu", 0, KDB_REPEAT_NONE);
+#if defined(CONFIG_KEXEC)
+ kdb_register_repeat("kdump", kdb_kdump, "",
+ "Enter kdump crash kexec", 0, KDB_REPEAT_NONE);
+#endif
kdb_register_repeat("kgdb", kdb_kgdb, "",
"Enter kgdb mode", 0, KDB_REPEAT_NONE);
kdb_register_repeat("ps", kdb_ps, "[<flags>|A]",
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 09/14] KDB: Add pshelp command.
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (7 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 08/14] KDB: Restore call to kdump from KDB Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 10/14] KGDB/KDB: add support for external NMI handler to call KGDB/KDB Mike Travis
` (4 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Anton Vorontsov,
Sasha Levin, Rusty Russell, Greg Kroah-Hartman
[-- Attachment #1: kdb-add-pshelp.patch --]
[-- Type: text/plain, Size: 2043 bytes --]
This patch restores the capability for providing help with the
PS and BT arguments.
Cc: Anton Vorontsov <anton.vorontsov@linaro.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
kernel/debug/kdb/kdb_main.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
--- linux.orig/kernel/debug/kdb/kdb_main.c
+++ linux/kernel/debug/kdb/kdb_main.c
@@ -2787,6 +2787,32 @@ static int kdb_grep_help(int argc, const
}
/*
+ * display help for the ps and bt status flag
+ */
+static int kdb_ps_help(int argc, const char **argv)
+{
+ kdb_printf("The meaning of the State flag in ps command output:\n");
+ kdb_printf(" R RUNNING\n");
+ kdb_printf(" D TASK_UNINTERRUPTIBLE\n");
+ kdb_printf(" S TASK_INTERRUPTIBLE\n");
+ kdb_printf(" T TASK_STOPPED\n");
+ kdb_printf(" C TASK_TRACED\n");
+ kdb_printf(" Z EXIT_ZOMBIE\n");
+ kdb_printf(" E EXIT_DEAD\n");
+ kdb_printf(" U UNRUNNABLE\n");
+ kdb_printf(" M sleeping DAEMON\n");
+ kdb_printf(" I IDLE\n");
+ kdb_printf(" (note that most idles are named 'kworker/NN')\n");
+ kdb_printf("\n");
+ kdb_printf(
+ "The above can be specified to ps and bta to select tasks\n");
+ kdb_printf(" A all of above\n");
+ kdb_printf(" default is RDSTCZEU (not Idle or sleeping Daemon)\n");
+ return 0;
+}
+
+
+/*
* kdb_register_repeat - This function is used to register a kernel
* debugger command.
* Inputs:
@@ -2972,6 +2998,8 @@ static void __init kdb_inittab(void)
"Enter kgdb mode", 0, KDB_REPEAT_NONE);
kdb_register_repeat("ps", kdb_ps, "[<flags>|A]",
"Display active task list", 0, KDB_REPEAT_NONE);
+ kdb_register_repeat("pshelp", kdb_ps_help, "",
+ "Display help for the ps and bt task State flag", 0, KDB_REPEAT_NONE);
kdb_register_repeat("pid", kdb_pid, "<pidnum>",
"Switch to another task", 0, KDB_REPEAT_NONE);
kdb_register_repeat("reboot", kdb_reboot, "",
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 10/14] KGDB/KDB: add support for external NMI handler to call KGDB/KDB.
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (8 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 09/14] KDB: Add pshelp command Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 11/14] x86/UV: Move NMI support Mike Travis
` (3 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel
[-- Attachment #1: kgdb-add-nmi-callin.patch --]
[-- Type: text/plain, Size: 3021 bytes --]
This patch adds an interface (kgdb_nmicallin) that can be used by
external NMI handlers to call the KGDB/KDB handler. The primary need
for this is for those types of NMI interrupts where all the CPUs
have already received the NMI signal. Therefore no send_IPI(NMI)
is required, and in fact it will cause a 2nd unhandled NMI to occur.
Since all the CPUs are getting the NMI at roughly the same time, it's not
guaranteed that the first CPU that hits the NMI handler will manage to
enter KGDB and set the dbg_master_lock before the slaves start entering.
The new argument "send_ready" is used by KGDB to signal the NMI handler
to release the slave CPUs for entry into KGDB.
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
include/linux/kgdb.h | 1 +
kernel/debug/debug_core.c | 39 +++++++++++++++++++++++++++++++++++++++
kernel/debug/debug_core.h | 1 +
3 files changed, 41 insertions(+)
--- linux.orig/include/linux/kgdb.h
+++ linux/include/linux/kgdb.h
@@ -310,6 +310,7 @@ extern int
kgdb_handle_exception(int ex_vector, int signo, int err_code,
struct pt_regs *regs);
extern int kgdb_nmicallback(int cpu, void *regs);
+extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *snd_rdy);
extern void gdbstub_exit(int status);
extern int kgdb_single_step;
--- linux.orig/kernel/debug/debug_core.c
+++ linux/kernel/debug/debug_core.c
@@ -578,6 +578,10 @@ return_normal:
/* Signal the other CPUs to enter kgdb_wait() */
if ((!kgdb_single_step) && kgdb_do_roundup)
kgdb_roundup_cpus(flags);
+
+ /* If optional send ready pointer, signal CPUs to proceed */
+ if (kgdb_info[cpu].send_ready)
+ atomic_set(kgdb_info[cpu].send_ready, 1);
#endif
/*
@@ -729,6 +733,41 @@ int kgdb_nmicallback(int cpu, void *regs
return 0;
}
#endif
+ return 1;
+}
+
+int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *send_ready)
+{
+#ifdef CONFIG_SMP
+ if (!kgdb_io_ready(0))
+ return 1;
+
+ if (kgdb_info[cpu].enter_kgdb == 0) {
+ struct kgdb_state kgdb_var;
+ struct kgdb_state *ks = &kgdb_var;
+ int save_kgdb_do_roundup = kgdb_do_roundup;
+
+ memset(ks, 0, sizeof(struct kgdb_state));
+ ks->cpu = cpu;
+ ks->ex_vector = trapnr;
+ ks->signo = SIGTRAP;
+ ks->err_code = 0;
+ ks->kgdb_usethreadid = 0;
+ ks->linux_regs = regs;
+
+ /* Do not broadcast NMI */
+ kgdb_do_roundup = 0;
+ kgdb_info[cpu].send_ready = send_ready;
+ kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
+ kgdb_do_roundup = save_kgdb_do_roundup;
+ kgdb_info[cpu].send_ready = NULL;
+
+ /* Wait till all the CPUs have quit from the debugger. */
+ while (atomic_read(&slaves_in_kgdb))
+ cpu_relax();
+ return 0;
+ }
+#endif
return 1;
}
--- linux.orig/kernel/debug/debug_core.h
+++ linux/kernel/debug/debug_core.h
@@ -37,6 +37,7 @@ struct kgdb_state {
struct debuggerinfo_struct {
void *debuggerinfo;
struct task_struct *task;
+ atomic_t *send_ready;
int exception_state;
int ret_state;
int irq_depth;
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 11/14] x86/UV: Move NMI support
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (9 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 10/14] KGDB/KDB: add support for external NMI handler to call KGDB/KDB Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 12/14] x86/UV: Add uvtrace support Mike Travis
` (2 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Alex Shi,
Cliff Wickman, Alexander Gordeev, Suresh Siddha,
Michael S. Tsirkin, Steffen Persvold
[-- Attachment #1: uv-move-nmi-support.patch --]
[-- Type: text/plain, Size: 7738 bytes --]
This patch moves the UV NMI support from the x2apic file to a
new separate uv_nmi.c file in preparation for the next sequence
of patches. It minimizes bloat of the x2apic file, and has the
added benefit of putting the upcoming /sys/module parameters under
the name 'uv_nmi' instead of 'x2apic_uv_x', which was obscure.
Cc: Alex Shi <alex.shi@intel.com>
Cc: Cliff Wickman <cpw@sgi.com>
Cc: Alexander Gordeev <agordeev@redhat.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Steffen Persvold <sp@numascale.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
arch/x86/include/asm/uv/uv.h | 2
arch/x86/kernel/apic/x2apic_uv_x.c | 69 -------------------------
arch/x86/platform/uv/Makefile | 2
arch/x86/platform/uv/uv_nmi.c | 101 +++++++++++++++++++++++++++++++++++++
4 files changed, 104 insertions(+), 70 deletions(-)
--- linux.orig/arch/x86/include/asm/uv/uv.h
+++ linux/arch/x86/include/asm/uv/uv.h
@@ -12,6 +12,7 @@ extern enum uv_system_type get_uv_system
extern int is_uv_system(void);
extern void uv_cpu_init(void);
extern void uv_nmi_init(void);
+extern void uv_register_nmi_notifier(void);
extern void uv_system_init(void);
extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
struct mm_struct *mm,
@@ -25,6 +26,7 @@ static inline enum uv_system_type get_uv
static inline int is_uv_system(void) { return 0; }
static inline void uv_cpu_init(void) { }
static inline void uv_system_init(void) { }
+static inline void uv_register_nmi_notifier(void) { }
static inline const struct cpumask *
uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm,
unsigned long start, unsigned long end, unsigned int cpu)
--- linux.orig/arch/x86/kernel/apic/x2apic_uv_x.c
+++ linux/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -39,12 +39,6 @@
#include <asm/emergency-restart.h>
#include <asm/nmi.h>
-/* BMC sets a bit this MMR non-zero before sending an NMI */
-#define UVH_NMI_MMR UVH_SCRATCH5
-#define UVH_NMI_MMR_CLEAR (UVH_NMI_MMR + 8)
-#define UV_NMI_PENDING_MASK (1UL << 63)
-DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count);
-
DEFINE_PER_CPU(int, x2apic_extra_bits);
#define PR_DEVEL(fmt, args...) pr_devel("%s: " fmt, __func__, args)
@@ -56,7 +50,6 @@ int uv_min_hub_revision_id;
EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
unsigned int uv_apicid_hibits;
EXPORT_SYMBOL_GPL(uv_apicid_hibits);
-static DEFINE_SPINLOCK(uv_nmi_lock);
static struct apic apic_x2apic_uv_x;
@@ -795,68 +788,6 @@ void __cpuinit uv_cpu_init(void)
set_x2apic_extra_bits(uv_hub_info->pnode);
}
-/*
- * When NMI is received, print a stack trace.
- */
-int uv_handle_nmi(unsigned int reason, struct pt_regs *regs)
-{
- unsigned long real_uv_nmi;
- int bid;
-
- /*
- * Each blade has an MMR that indicates when an NMI has been sent
- * to cpus on the blade. If an NMI is detected, atomically
- * clear the MMR and update a per-blade NMI count used to
- * cause each cpu on the blade to notice a new NMI.
- */
- bid = uv_numa_blade_id();
- real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK);
-
- if (unlikely(real_uv_nmi)) {
- spin_lock(&uv_blade_info[bid].nmi_lock);
- real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK);
- if (real_uv_nmi) {
- uv_blade_info[bid].nmi_count++;
- uv_write_local_mmr(UVH_NMI_MMR_CLEAR, UV_NMI_PENDING_MASK);
- }
- spin_unlock(&uv_blade_info[bid].nmi_lock);
- }
-
- if (likely(__get_cpu_var(cpu_last_nmi_count) == uv_blade_info[bid].nmi_count))
- return NMI_DONE;
-
- __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count;
-
- /*
- * Use a lock so only one cpu prints at a time.
- * This prevents intermixed output.
- */
- spin_lock(&uv_nmi_lock);
- pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id());
- dump_stack();
- spin_unlock(&uv_nmi_lock);
-
- return NMI_HANDLED;
-}
-
-void uv_register_nmi_notifier(void)
-{
- if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv"))
- printk(KERN_WARNING "UV NMI handler failed to register\n");
-}
-
-void uv_nmi_init(void)
-{
- unsigned int value;
-
- /*
- * Unmask NMI on all cpus
- */
- value = apic_read(APIC_LVT1) | APIC_DM_NMI;
- value &= ~APIC_LVT_MASKED;
- apic_write(APIC_LVT1, value);
-}
-
void __init uv_system_init(void)
{
union uvh_rh_gam_config_mmr_u m_n_config;
--- linux.orig/arch/x86/platform/uv/Makefile
+++ linux/arch/x86/platform/uv/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o
+obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o uv_nmi.o
--- /dev/null
+++ linux/arch/x86/platform/uv/uv_nmi.c
@@ -0,0 +1,101 @@
+/*
+ * SGI NMI support routines
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (c) 2009-2013 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) Mike Travis
+ */
+
+#include <linux/cpu.h>
+#include <linux/nmi.h>
+
+#include <asm/apic.h>
+#include <asm/uv/uv.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/uv_mmrs.h>
+
+/* BMC sets a bit this MMR non-zero before sending an NMI */
+#define UVH_NMI_MMR UVH_SCRATCH5
+#define UVH_NMI_MMR_CLEAR (UVH_NMI_MMR + 8)
+#define UV_NMI_PENDING_MASK (1UL << 63)
+DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count);
+static DEFINE_SPINLOCK(uv_nmi_lock);
+
+/*
+ * When NMI is received, print a stack trace.
+ */
+int uv_handle_nmi(unsigned int reason, struct pt_regs *regs)
+{
+ unsigned long real_uv_nmi;
+ int bid;
+
+ /*
+ * Each blade has an MMR that indicates when an NMI has been sent
+ * to cpus on the blade. If an NMI is detected, atomically
+ * clear the MMR and update a per-blade NMI count used to
+ * cause each cpu on the blade to notice a new NMI.
+ */
+ bid = uv_numa_blade_id();
+ real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK);
+
+ if (unlikely(real_uv_nmi)) {
+ spin_lock(&uv_blade_info[bid].nmi_lock);
+ real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) &
+ UV_NMI_PENDING_MASK);
+ if (real_uv_nmi) {
+ uv_blade_info[bid].nmi_count++;
+ uv_write_local_mmr(UVH_NMI_MMR_CLEAR,
+ UV_NMI_PENDING_MASK);
+ }
+ spin_unlock(&uv_blade_info[bid].nmi_lock);
+ }
+
+ if (likely(__get_cpu_var(cpu_last_nmi_count) ==
+ uv_blade_info[bid].nmi_count))
+ return NMI_DONE;
+
+ __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count;
+
+ /*
+ * Use a lock so only one cpu prints at a time.
+ * This prevents intermixed output.
+ */
+ spin_lock(&uv_nmi_lock);
+ pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id());
+ dump_stack();
+ spin_unlock(&uv_nmi_lock);
+
+ return NMI_HANDLED;
+}
+
+void uv_register_nmi_notifier(void)
+{
+ if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv"))
+ pr_warn("UV NMI handler failed to register\n");
+}
+
+void uv_nmi_init(void)
+{
+ unsigned int value;
+
+ /*
+ * Unmask NMI on all cpus
+ */
+ value = apic_read(APIC_LVT1) | APIC_DM_NMI;
+ value &= ~APIC_LVT_MASKED;
+ apic_write(APIC_LVT1, value);
+}
+
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 12/14] x86/UV: Add uvtrace support
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (10 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 11/14] x86/UV: Move NMI support Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-12 19:38 ` [PATCH 13/14] x86/UV: Update UV support for external NMI signals Mike Travis
2013-03-12 19:38 ` [PATCH 14/14] x86/UV: Add call to KGDB/KDB from NMI handler Mike Travis
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Alex Shi,
Cliff Wickman, Alexander Gordeev, Suresh Siddha,
Michael S. Tsirkin, Steffen Persvold
[-- Attachment #1: uv-add-trace-support.patch --]
[-- Type: text/plain, Size: 2948 bytes --]
This patch adds support for the uvtrace KDB module by providing a
skeleton call to the registered trace function. It also provides
another separate 'NMI' tracer that is triggered by the system wide
'power nmi' command.
Cc: Alex Shi <alex.shi@intel.com>
Cc: Cliff Wickman <cpw@sgi.com>
Cc: Alexander Gordeev <agordeev@redhat.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Steffen Persvold <sp@numascale.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
arch/x86/include/asm/uv/uv.h | 12 ++++++++++--
arch/x86/platform/uv/uv_nmi.c | 10 +++++++++-
2 files changed, 19 insertions(+), 3 deletions(-)
--- linux.orig/arch/x86/include/asm/uv/uv.h
+++ linux/arch/x86/include/asm/uv/uv.h
@@ -14,24 +14,32 @@ extern void uv_cpu_init(void);
extern void uv_nmi_init(void);
extern void uv_register_nmi_notifier(void);
extern void uv_system_init(void);
+extern void (*uv_trace_nmi_func)(int cpu, struct pt_regs *regs, int ignored);
+extern void (*uv_trace_func)(const char *f, const int l, const char *fmt, ...);
+#define uvtrace(fmt, ...) \
+do { \
+ if (unlikely(uv_trace_func)) \
+ (uv_trace_func)(__func__, __LINE__, fmt, ##__VA_ARGS__);\
+} while (0)
extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
struct mm_struct *mm,
unsigned long start,
unsigned long end,
unsigned int cpu);
-#else /* X86_UV */
+#else /* !X86_UV */
static inline enum uv_system_type get_uv_system_type(void) { return UV_NONE; }
static inline int is_uv_system(void) { return 0; }
static inline void uv_cpu_init(void) { }
static inline void uv_system_init(void) { }
+static inline void uvtrace(void *fmt, ...) { }
static inline void uv_register_nmi_notifier(void) { }
static inline const struct cpumask *
uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm,
unsigned long start, unsigned long end, unsigned int cpu)
{ return cpumask; }
-#endif /* X86_UV */
+#endif /* !X86_UV */
#endif /* _ASM_X86_UV_UV_H */
--- linux.orig/arch/x86/platform/uv/uv_nmi.c
+++ linux/arch/x86/platform/uv/uv_nmi.c
@@ -1,5 +1,5 @@
/*
- * SGI NMI support routines
+ * SGI NMI/TRACE support routines
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
*/
#include <linux/cpu.h>
+#include <linux/module.h>
#include <linux/nmi.h>
#include <asm/apic.h>
@@ -34,6 +35,13 @@
DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count);
static DEFINE_SPINLOCK(uv_nmi_lock);
+void (*uv_trace_func)(const char *f, const int l, const char *fmt, ...);
+EXPORT_SYMBOL(uv_trace_func);
+
+void (*uv_trace_nmi_func)(int cpu, struct pt_regs *regs, int ignored);
+EXPORT_SYMBOL(uv_trace_nmi_func);
+
+
/*
* When NMI is received, print a stack trace.
*/
--
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH 13/14] x86/UV: Update UV support for external NMI signals
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (11 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 12/14] x86/UV: Add uvtrace support Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
2013-03-14 7:20 ` Ingo Molnar
2013-03-12 19:38 ` [PATCH 14/14] x86/UV: Add call to KGDB/KDB from NMI handler Mike Travis
13 siblings, 1 reply; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel, Russ Anderson,
Alexander Gordeev, Suresh Siddha, Michael S. Tsirkin,
Steffen Persvold
[-- Attachment #1: uv-update-nmi-support.patch --]
[-- Type: text/plain, Size: 23889 bytes --]
This patch updates the UV NMI handler for the external SMM
'POWER NMI' command. This command sets a special flag in one
of the MMRs on each HUB and sends the NMI signal to all cpus
in the system.
The code has also been optimized to minimize reading of the MMRs as
much as possible, by using a per HUB atomic NMI flag. Too high a
rate of reading MMRs not only disrupts the UV Hub's primary function
of directing NumaLink traffic, but can also cause problems. And to
avoid excessive overhead when perf tools are causing millions of
NMIs per second (when running on a large number of CPUS), this
handler uses primarily the NMI_UNKNOWN notifier chain.
There is an exception where the NMI_LOCAL notifier chain is used.
When the perf tools are in use, it's possible that our NMI was
captured by some other NMI handler and then ignored. We set a
per_cpu flag for those CPUs that ignored the initial NMI, and then
send them an IPI NMI signal.
There are also some new parameters introduced to alter and tune the
behavior of the NMI handler. These parameters are not documented in
Documentation/kernel-parameters.txt as they are only useful to SGI
support personnel, and are not generally useful to system users.
Cc: Russ Anderson <rja@sgi.com>
Cc: Alexander Gordeev <agordeev@redhat.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Steffen Persvold <sp@numascale.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
arch/x86/include/asm/uv/uv_hub.h | 57 +++
arch/x86/include/asm/uv/uv_mmrs.h | 31 +
arch/x86/kernel/apic/x2apic_uv_x.c | 1
arch/x86/platform/uv/uv_nmi.c | 600 ++++++++++++++++++++++++++++++++++---
4 files changed, 648 insertions(+), 41 deletions(-)
--- linux.orig/arch/x86/include/asm/uv/uv_hub.h
+++ linux/arch/x86/include/asm/uv/uv_hub.h
@@ -502,8 +502,8 @@ struct uv_blade_info {
unsigned short nr_online_cpus;
unsigned short pnode;
short memory_nid;
- spinlock_t nmi_lock;
- unsigned long nmi_count;
+ spinlock_t nmi_lock; /* obsolete, see uv_hub_nmi */
+ unsigned long nmi_count; /* obsolete, see uv_hub_nmi */
};
extern struct uv_blade_info *uv_blade_info;
extern short *uv_node_to_blade;
@@ -576,6 +576,59 @@ static inline int uv_num_possible_blades
return uv_possible_blades;
}
+/* Per Hub NMI support */
+extern void uv_nmi_setup(void);
+
+/* BMC sets a bit this MMR non-zero before sending an NMI */
+#define UVH_NMI_MMR UVH_SCRATCH5
+#define UVH_NMI_MMR_CLEAR UVH_SCRATCH5_ALIAS
+#define UVH_NMI_MMR_SHIFT 63
+#define UVH_NMI_MMR_TYPE "SCRATCH5"
+
+/* Newer SMM NMI handler, not present in all systems */
+#define UVH_NMI_MMRX UVH_EVENT_OCCURRED0
+#define UVH_NMI_MMRX_CLEAR UVH_EVENT_OCCURRED0_ALIAS
+#define UVH_NMI_MMRX_SHIFT (is_uv1_hub() ? \
+ UV1H_EVENT_OCCURRED0_EXTIO_INT0_SHFT :\
+ UVXH_EVENT_OCCURRED0_EXTIO_INT0_SHFT)
+#define UVH_NMI_MMRX_TYPE "EXTIO_INT0"
+
+/* Non-zero indicates newer SMM NMI handler present */
+#define UVH_NMI_MMRX_SUPPORTED UVH_EXTIO_INT0_BROADCAST
+
+/* Indicates to BIOS that we want to use the newer SMM NMI handler */
+#define UVH_NMI_MMRX_REQ UVH_SCRATCH5_ALIAS_2
+#define UVH_NMI_MMRX_REQ_SHIFT 62
+
+struct uv_hub_nmi_s {
+ raw_spinlock_t nmi_lock;
+ atomic_t in_nmi; /* flag this node in UV NMI IRQ */
+ atomic_t cpu_owner; /* last locker of this struct */
+ atomic_t read_mmr_count; /* count of MMR reads */
+ atomic_t nmi_count; /* count of true UV NMIs */
+ unsigned long nmi_value; /* last value read from NMI MMR */
+};
+
+struct uv_cpu_nmi_s {
+ struct uv_hub_nmi_s *hub;
+ atomic_t state;
+ atomic_t pinging;
+ int queries;
+ int pings;
+};
+
+DECLARE_PER_CPU(struct uv_cpu_nmi_s, __uv_cpu_nmi);
+#define uv_cpu_nmi (__get_cpu_var(__uv_cpu_nmi))
+#define uv_hub_nmi (uv_cpu_nmi.hub)
+#define uv_cpu_nmi_per(cpu) (per_cpu(__uv_cpu_nmi, cpu))
+#define uv_hub_nmi_per(cpu) (uv_cpu_nmi_per(cpu).hub)
+
+/* uv_cpu_nmi_states */
+#define UV_NMI_STATE_OUT 0
+#define UV_NMI_STATE_IN 1
+#define UV_NMI_STATE_DUMP 2
+#define UV_NMI_STATE_DUMP_DONE 3
+
/* Update SCIR state */
static inline void uv_set_scir_bits(unsigned char value)
{
--- linux.orig/arch/x86/include/asm/uv/uv_mmrs.h
+++ linux/arch/x86/include/asm/uv/uv_mmrs.h
@@ -461,6 +461,23 @@ union uvh_event_occurred0_u {
/* ========================================================================= */
+/* UVH_EXTIO_INT0_BROADCAST */
+/* ========================================================================= */
+#define UVH_EXTIO_INT0_BROADCAST 0x61448UL
+#define UVH_EXTIO_INT0_BROADCAST_32 0x3f0
+
+#define UVH_EXTIO_INT0_BROADCAST_ENABLE_SHFT 0
+#define UVH_EXTIO_INT0_BROADCAST_ENABLE_MASK 0x0000000000000001UL
+
+union uvh_extio_int0_broadcast_u {
+ unsigned long v;
+ struct uvh_extio_int0_broadcast_s {
+ unsigned long enable:1; /* RW */
+ unsigned long rsvd_1_63:63;
+ } s;
+};
+
+/* ========================================================================= */
/* UVH_GR0_TLB_INT0_CONFIG */
/* ========================================================================= */
#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
@@ -2606,6 +2623,20 @@ union uvh_scratch5_u {
};
/* ========================================================================= */
+/* UVH_SCRATCH5_ALIAS */
+/* ========================================================================= */
+#define UVH_SCRATCH5_ALIAS 0x2d0208UL
+#define UVH_SCRATCH5_ALIAS_32 0x780
+
+
+/* ========================================================================= */
+/* UVH_SCRATCH5_ALIAS_2 */
+/* ========================================================================= */
+#define UVH_SCRATCH5_ALIAS_2 0x2d0210UL
+#define UVH_SCRATCH5_ALIAS_2_32 0x788
+
+
+/* ========================================================================= */
/* UVXH_EVENT_OCCURRED2 */
/* ========================================================================= */
#define UVXH_EVENT_OCCURRED2 0x70100UL
--- linux.orig/arch/x86/kernel/apic/x2apic_uv_x.c
+++ linux/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -925,6 +925,7 @@ void __init uv_system_init(void)
map_mmr_high(max_pnode);
map_mmioh_high(min_pnode, max_pnode);
+ uv_nmi_setup();
uv_cpu_init();
uv_scir_register_cpu_notifier();
uv_register_nmi_notifier();
--- linux.orig/arch/x86/platform/uv/uv_nmi.c
+++ linux/arch/x86/platform/uv/uv_nmi.c
@@ -20,79 +20,574 @@
*/
#include <linux/cpu.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/nmi.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#if defined(CONFIG_KEXEC)
+#include <linux/kexec.h>
+#endif
#include <asm/apic.h>
+#include <asm/current.h>
+#include <asm/kdebug.h>
#include <asm/uv/uv.h>
#include <asm/uv/uv_hub.h>
#include <asm/uv/uv_mmrs.h>
-/* BMC sets a bit this MMR non-zero before sending an NMI */
-#define UVH_NMI_MMR UVH_SCRATCH5
-#define UVH_NMI_MMR_CLEAR (UVH_NMI_MMR + 8)
-#define UV_NMI_PENDING_MASK (1UL << 63)
-DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count);
-static DEFINE_SPINLOCK(uv_nmi_lock);
-
void (*uv_trace_func)(const char *f, const int l, const char *fmt, ...);
EXPORT_SYMBOL(uv_trace_func);
void (*uv_trace_nmi_func)(int cpu, struct pt_regs *regs, int ignored);
EXPORT_SYMBOL(uv_trace_nmi_func);
+/*
+ * UV handler for NMI
+ *
+ * Handle system-wide NMI events generated by the global 'power nmi' command.
+ *
+ * Basic operation is to field the NMI interrupt on each cpu and wait
+ * until all cpus have arrived into the nmi handler. If some cpus do not
+ * make it into the handler, try and force them in with the IPI(NMI) signal.
+ *
+ * We also have to lessen MMR accesses as much as possible as this disrupts
+ * the UV Hub's primary mission of directing NumaLink traffic.
+ */
+
+static struct uv_hub_nmi_s **uv_hub_nmi_list;
+
+DEFINE_PER_CPU(struct uv_cpu_nmi_s, __uv_cpu_nmi);
+EXPORT_PER_CPU_SYMBOL_GPL(__uv_cpu_nmi);
+
+static unsigned long nmi_mmr;
+static unsigned long nmi_mmr_clear;
+static unsigned long nmi_mmr_pending;
+
+static atomic_t uv_in_nmi;
+static atomic_t uv_nmi_cpu = ATOMIC_INIT(-1);
+static atomic_t uv_nmi_cpus_in_nmi = ATOMIC_INIT(-1);
+static atomic_t uv_nmi_slave_continue;
+static cpumask_var_t uv_nmi_cpu_mask;
+
+static int param_get_atomic(char *buffer, const struct kernel_param *kp)
+{
+ return sprintf(buffer, "%d\n", atomic_read((atomic_t *)kp->arg));
+}
+
+static int param_set_atomic(const char *val, const struct kernel_param *kp)
+{
+ /* clear on any write */
+ atomic_set((atomic_t *)kp->arg, 0);
+ return 0;
+}
+
+static struct kernel_param_ops param_ops_atomic = {
+ .get = param_get_atomic,
+ .set = param_set_atomic,
+};
+#define param_check_atomic(name, p) __param_check(name, p, atomic_t)
+
+static atomic_t uv_nmi_count;
+module_param_named(nmi_count, uv_nmi_count, atomic, 0644);
+
+static atomic_t uv_nmi_misses;
+module_param_named(nmi_misses, uv_nmi_misses, atomic, 0644);
+
+static atomic_t uv_nmi_ping_count;
+module_param_named(ping_count, uv_nmi_ping_count, atomic, 0644);
+
+static atomic_t uv_nmi_ping_misses;
+module_param_named(ping_misses, uv_nmi_ping_misses, atomic, 0644);
+
+static int uv_nmi_loglevel = 1;
+module_param_named(dump_loglevel, uv_nmi_loglevel, int, 0644);
+
+static int uv_nmi_ips_only;
+module_param_named(dump_ips_only, uv_nmi_ips_only, int, 0644);
+
+static int uv_nmi_kdump_requested;
+module_param_named(nmi_does_kdump, uv_nmi_kdump_requested, int, 0644);
+
+static int uv_nmi_initial_delay = 100;
+module_param_named(initial_delay, uv_nmi_initial_delay, int, 0644);
+
+static int uv_nmi_slave_delay = 100;
+module_param_named(slave_delay, uv_nmi_slave_delay, int, 0644);
+
+static int uv_nmi_loop_delay = 100;
+module_param_named(loop_delay, uv_nmi_loop_delay, int, 0644);
+
+static int uv_nmi_wait_count = 100;
+module_param_named(wait_count, uv_nmi_wait_count, int, 0644);
+
+static int uv_nmi_retry_count = 500;
+module_param_named(retry_count, uv_nmi_retry_count, int, 0644);
+
+#if defined(CONFIG_KEXEC)
+static void uv_nmi_kdump(struct pt_regs *regs)
+{
+ if (!kexec_crash_image) {
+ pr_err("UV: NMI kdump error: crash kernel not loaded\n");
+ return;
+ }
+
+ /* Call crash to dump system state */
+ pr_err("UV: NMI executing kdump [crash_kexec] on CPU%d\n",
+ smp_processor_id());
+ crash_kexec(regs);
+
+ /* If the above call returned then something didn't work */
+ pr_err("UV: NMI kdump error: crash_kexec failed!\n");
+}
+
+#else /* !CONFIG_KEXEC */
+static inline void uv_nmi_kdump(struct pt_regs *regs)
+{
+ pr_err("UV: NMI kdump error: KEXEC not supported in this kernel\n");
+}
+
+#endif /* !CONFIG_KEXEC */
+
+/* Setup which NMI support is present in system */
+static void uv_nmi_setup_mmrs(void)
+{
+ if (uv_read_local_mmr(UVH_NMI_MMRX_SUPPORTED)) {
+ uv_write_local_mmr(UVH_NMI_MMRX_REQ,
+ 1UL << UVH_NMI_MMRX_REQ_SHIFT);
+ nmi_mmr = UVH_NMI_MMRX;
+ nmi_mmr_clear = UVH_NMI_MMRX_CLEAR;
+ nmi_mmr_pending = 1UL << UVH_NMI_MMRX_SHIFT;
+ pr_info("UV: SMM NMI support: %s\n", UVH_NMI_MMRX_TYPE);
+ } else {
+ nmi_mmr = UVH_NMI_MMR;
+ nmi_mmr_clear = UVH_NMI_MMR_CLEAR;
+ nmi_mmr_pending = 1UL << UVH_NMI_MMR_SHIFT;
+ pr_info("UV: SMM NMI support: %s\n", UVH_NMI_MMR_TYPE);
+ }
+}
+
+/* Read NMI MMR and check if NMI flag was set by BMC. */
+static inline int uv_nmi_test_mmr(struct uv_hub_nmi_s *hub_nmi)
+{
+ hub_nmi->nmi_value = uv_read_local_mmr(nmi_mmr);
+ atomic_inc(&hub_nmi->read_mmr_count);
+ return !!(hub_nmi->nmi_value & nmi_mmr_pending);
+}
+
+static inline void uv_local_mmr_clear_nmi(void)
+{
+ uv_write_local_mmr(nmi_mmr_clear, nmi_mmr_pending);
+}
/*
- * When NMI is received, print a stack trace.
+ * If first cpu in on this hub, set hub_nmi "in_nmi" and "owner" values and
+ * return true. If first cpu in on the system, set global "in_nmi" flag.
*/
-int uv_handle_nmi(unsigned int reason, struct pt_regs *regs)
+static int uv_set_in_nmi(int cpu, struct uv_hub_nmi_s *hub_nmi)
{
- unsigned long real_uv_nmi;
- int bid;
+ int first = atomic_add_unless(&hub_nmi->in_nmi, 1, 1);
- /*
- * Each blade has an MMR that indicates when an NMI has been sent
- * to cpus on the blade. If an NMI is detected, atomically
- * clear the MMR and update a per-blade NMI count used to
- * cause each cpu on the blade to notice a new NMI.
- */
- bid = uv_numa_blade_id();
- real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK);
+ if (first) {
+ atomic_set(&hub_nmi->cpu_owner, cpu);
+ if (atomic_add_unless(&uv_in_nmi, 1, 1))
+ atomic_set(&uv_nmi_cpu, cpu);
+
+ atomic_inc(&hub_nmi->nmi_count);
+ }
+ return first;
+}
+
+/* Check if this is a system NMI event */
+static int uv_check_nmi(struct uv_hub_nmi_s *hub_nmi)
+{
+ int cpu = smp_processor_id();
+ int nmi = 0;
+
+ atomic_inc(&uv_nmi_count);
+ uv_cpu_nmi.queries++;
+
+ do {
+ nmi = atomic_read(&hub_nmi->in_nmi);
+ if (nmi)
+ break;
+
+ if (raw_spin_trylock(&hub_nmi->nmi_lock)) {
+
+ /* check hub MMR NMI flag */
+ if (uv_nmi_test_mmr(hub_nmi)) {
+ uv_set_in_nmi(cpu, hub_nmi);
+ nmi = 1;
+ break;
+ }
+
+ /* MMR NMI flag is clear */
+ raw_spin_unlock(&hub_nmi->nmi_lock);
+
+ } else {
+ /* wait a moment for the hub nmi locker to set flag */
+ cpu_relax();
+ udelay(uv_nmi_slave_delay);
+
+ /* re-check hub in_nmi flag */
+ nmi = atomic_read(&hub_nmi->in_nmi);
+ if (nmi)
+ break;
+ }
+
+ /*
+ * check system-wide uv_in_nmi flag
+ * (this check because on large UV1000 systems, the NMI signal
+ * may arrive before the BMC has set this hub's NMI flag in
+ * the MMR.)
+ */
+ if (!nmi) {
+ nmi = atomic_read(&uv_in_nmi);
+ if (nmi)
+ uv_set_in_nmi(cpu, hub_nmi);
+ }
+
+ } while (0);
+
+ if (!nmi)
+ atomic_inc(&uv_nmi_misses);
+
+ return nmi;
+}
+
+/* Need to reset the NMI MMR register, but only once per hub. */
+static inline void uv_clear_nmi(int cpu)
+{
+ struct uv_hub_nmi_s *hub_nmi = uv_hub_nmi;
+
+ if (cpu == atomic_read(&hub_nmi->cpu_owner)) {
+ atomic_set(&hub_nmi->cpu_owner, -1);
+ atomic_set(&hub_nmi->in_nmi, 0);
+ uv_local_mmr_clear_nmi();
+ raw_spin_unlock(&hub_nmi->nmi_lock);
+ }
+}
+
+/* Print non-responding cpus */
+static void uv_nmi_nr_cpus_pr(char *fmt)
+{
+ static char cpu_list[1024];
+ int len = sizeof(cpu_list);
+ int c = cpumask_weight(uv_nmi_cpu_mask);
+ int n = cpulist_scnprintf(cpu_list, len, uv_nmi_cpu_mask);
+
+ if (n >= len-1)
+ strcpy(&cpu_list[len - 6], "...\n");
+
+ /* (can't use pr_* with variable fmt) */
+ printk(fmt, c, cpu_list);
+}
+
+/* Ping non-responding cpus attemping to force them into the NMI handler */
+static void uv_nmi_nr_cpus_ping(void)
+{
+ int cpu;
+
+ for_each_cpu(cpu, uv_nmi_cpu_mask)
+ atomic_set(&uv_cpu_nmi_per(cpu).pinging, 1);
- if (unlikely(real_uv_nmi)) {
- spin_lock(&uv_blade_info[bid].nmi_lock);
- real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) &
- UV_NMI_PENDING_MASK);
- if (real_uv_nmi) {
- uv_blade_info[bid].nmi_count++;
- uv_write_local_mmr(UVH_NMI_MMR_CLEAR,
- UV_NMI_PENDING_MASK);
+ apic->send_IPI_mask(uv_nmi_cpu_mask, APIC_DM_NMI);
+}
+
+/* Clean up flags for cpus that ignored both NMI and ping */
+static void uv_nmi_cleanup_mask(void)
+{
+ int cpu;
+
+ for_each_cpu(cpu, uv_nmi_cpu_mask) {
+ atomic_set(&uv_cpu_nmi_per(cpu).pinging, 0);
+ atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_OUT);
+ cpumask_clear_cpu(cpu, uv_nmi_cpu_mask);
+ }
+}
+
+/* Loop waiting as cpus enter nmi handler */
+static int uv_nmi_wait_cpus(int cpu, int first)
+{
+ int i, j, k, n = num_online_cpus();
+ int last_k = 0, waiting = 0;
+
+ if (first) {
+ cpumask_copy(uv_nmi_cpu_mask, cpu_online_mask);
+ k = 0;
+ } else
+ k = n - cpumask_weight(uv_nmi_cpu_mask);
+
+ udelay(uv_nmi_initial_delay);
+ for (i = 0; i < uv_nmi_retry_count; i++) {
+ int loop_delay = uv_nmi_loop_delay;
+
+ for_each_cpu(j, uv_nmi_cpu_mask) {
+ if (atomic_read(&uv_cpu_nmi_per(j).state)) {
+ cpumask_clear_cpu(j, uv_nmi_cpu_mask);
+ if (++k >= n)
+ break;
+ }
+ }
+ if (k >= n) { /* all in? */
+ k = n;
+ break;
+ }
+ if (last_k != k) { /* abort if none coming in */
+ last_k = k;
+ waiting = 0;
+ } else if (++waiting > uv_nmi_wait_count)
+ break;
+
+ /* extend delay if only waiting for cpu that sent the nmi */
+ if (waiting && (n - k) == 1 &&
+ cpumask_test_cpu(0, uv_nmi_cpu_mask))
+ loop_delay *= 100;
+
+ udelay(loop_delay);
+ }
+ atomic_set(&uv_nmi_cpus_in_nmi, k);
+ return n - k;
+}
+
+/* Wait until all cpus have entered NMI handler */
+static int uv_nmi_wait(int cpu)
+{
+ /* indicate this cpu is in */
+ atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_IN);
+
+ /* if we are not the first cpu in, we are a slave cpu */
+ if (atomic_read(&uv_nmi_cpu) != cpu)
+ return -1;
+
+ do {
+ /* wait for all other cpus to gather here */
+ if (!uv_nmi_wait_cpus(cpu, 1))
+ break;
+
+ /* if not all made it in, send IPI NMI to them */
+ uv_nmi_nr_cpus_pr(
+ "UV: Sending NMI IPI to %d non-responding CPUs: %s\n");
+ uv_nmi_nr_cpus_ping();
+
+ /* if some cpus are still not in, ignore them */
+ if (!uv_nmi_wait_cpus(cpu, 0))
+ break;
+
+ uv_nmi_nr_cpus_pr("UV: %d CPUs not in NMI loop: %s\n");
+ } while (0);
+
+ pr_err("UV: %d of %d CPUs in NMI\n",
+ atomic_read(&uv_nmi_cpus_in_nmi), num_online_cpus());
+
+ return cpu;
+}
+
+static void uv_nmi_dump_cpu_ip_hdr(void)
+{
+ printk("UV: NMI %4s %6s %16s %16s [PID 0 suppressed]\n",
+ "CPU", "PID", "COMMAND", "IP");
+}
+
+static void uv_nmi_dump_cpu_ip(int cpu, struct pt_regs *regs)
+{
+ printk("UV: NMI %4d %6d %-32.32s ",
+ cpu, current->pid, current->comm);
+
+ printk_address(regs->ip, 1);
+}
+
+/* Dump this cpu's state */
+static void uv_nmi_dump_state_cpu(int cpu, struct pt_regs *regs, int ignored)
+{
+ char *dots = " ................................. ";
+
+ /* call possible nmi trace function */
+ if (unlikely(uv_trace_nmi_func))
+ (uv_trace_nmi_func)(cpu, regs, ignored);
+
+ /* otherwise if dump has been requested */
+ else if (uv_nmi_loglevel) {
+ int saved_console_loglevel = console_loglevel;
+ console_loglevel = uv_nmi_loglevel;
+
+ if (uv_nmi_ips_only) {
+ if (cpu == 0)
+ uv_nmi_dump_cpu_ip_hdr();
+
+ if (ignored)
+ printk("UV: NMI %4d%signored NMI\n", cpu, dots);
+
+ else if (current->pid != 0)
+ uv_nmi_dump_cpu_ip(cpu, regs);
+
+ } else {
+ if (ignored) {
+ printk(
+ "UV:%sNMI ignored on CPU %d\n",
+ dots, cpu);
+ } else {
+ printk("UV:%sNMI process trace for CPU %d\n",
+ dots, cpu);
+ show_regs(regs);
+ }
+ }
+ console_loglevel = saved_console_loglevel;
+ }
+ atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_DUMP_DONE);
+}
+
+/* Trigger a slave cpu to dump it's state */
+static void uv_nmi_trigger_dump(int cpu)
+{
+ int retry = 10000;
+
+ if (atomic_read(&uv_cpu_nmi_per(cpu).state) != UV_NMI_STATE_IN)
+ return;
+
+ atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_DUMP);
+ do {
+ cpu_relax();
+ udelay(10);
+ if (atomic_read(&uv_cpu_nmi_per(cpu).state)
+ != UV_NMI_STATE_DUMP)
+ return;
+ } while (--retry > 0);
+
+ pr_err("UV: CPU %d stuck in process dump function\n", cpu);
+ atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_DUMP_DONE);
+}
+
+/* Wait until all cpus ready to exit */
+static void uv_nmi_sync_exit(int master)
+{
+ atomic_dec(&uv_nmi_cpus_in_nmi);
+ if (master) {
+ while (atomic_read(&uv_nmi_cpus_in_nmi) > 0)
+ cpu_relax();
+ atomic_set(&uv_nmi_slave_continue, 0);
+ } else {
+ while (atomic_read(&uv_nmi_slave_continue))
+ cpu_relax();
+ }
+}
+
+/* Walk through cpu list and dump state of each */
+static void uv_nmi_dump_state(int cpu, struct pt_regs *regs, int master)
+{
+ if (master) {
+ int tcpu;
+
+ pr_err("UV: tracing %s for %d CPUs from CPU %d\n",
+ uv_nmi_ips_only ? "IPs" : "processes",
+ atomic_read(&uv_nmi_cpus_in_nmi), cpu);
+
+ atomic_set(&uv_nmi_slave_continue, 2);
+ for_each_online_cpu(tcpu) {
+ if (cpumask_test_cpu(tcpu, uv_nmi_cpu_mask))
+ uv_nmi_dump_state_cpu(tcpu, regs, 1);
+ else if (tcpu == cpu)
+ uv_nmi_dump_state_cpu(tcpu, regs, 0);
+ else
+ uv_nmi_trigger_dump(tcpu);
}
- spin_unlock(&uv_blade_info[bid].nmi_lock);
+ pr_err("UV: process trace complete\n");
+ } else {
+ while (!atomic_read(&uv_nmi_slave_continue))
+ cpu_relax();
+ while (atomic_read(&uv_cpu_nmi.state) != UV_NMI_STATE_DUMP)
+ cpu_relax();
+ uv_nmi_dump_state_cpu(cpu, regs, 0);
}
+ uv_nmi_sync_exit(master);
+}
- if (likely(__get_cpu_var(cpu_last_nmi_count) ==
- uv_blade_info[bid].nmi_count))
+static void uv_nmi_touch_watchdogs(void)
+{
+ touch_softlockup_watchdog_sync();
+ clocksource_touch_watchdog();
+ rcu_cpu_stall_reset();
+ touch_nmi_watchdog();
+}
+
+/*
+ * UV NMI handler
+ */
+int uv_handle_nmi(unsigned int reason, struct pt_regs *regs)
+{
+ struct uv_hub_nmi_s *hub_nmi = uv_hub_nmi;
+ int cpu = smp_processor_id();
+ int master = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /* If not a UV Global NMI, ignore */
+ if (!atomic_read(&uv_cpu_nmi.pinging) && !uv_check_nmi(hub_nmi)) {
+ local_irq_restore(flags);
return NMI_DONE;
+ }
- __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count;
+ /* Pause until all cpus are in NMI handler */
+ if (cpu == uv_nmi_wait(cpu))
+ master = 1;
+
+ /* If NMI kdump requested, attempt to do it */
+ if (master && uv_nmi_kdump_requested)
+ uv_nmi_kdump(regs);
+
+ /* Dump state of each cpu */
+ uv_nmi_dump_state(cpu, regs, master);
+
+ /* Clear per_cpu "in nmi" flag */
+ atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT);
+
+ /* Clear MMR NMI flag on each hub */
+ uv_clear_nmi(cpu);
+
+ /* Clear global flags */
+ if (master) {
+ if (cpumask_weight(uv_nmi_cpu_mask))
+ uv_nmi_cleanup_mask();
+ atomic_set(&uv_nmi_cpus_in_nmi, -1);
+ atomic_set(&uv_nmi_cpu, -1);
+ atomic_set(&uv_in_nmi, 0);
+ }
- /*
- * Use a lock so only one cpu prints at a time.
- * This prevents intermixed output.
- */
- spin_lock(&uv_nmi_lock);
- pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id());
- dump_stack();
- spin_unlock(&uv_nmi_lock);
+ uv_nmi_touch_watchdogs();
+ local_irq_restore(flags);
return NMI_HANDLED;
}
+/*
+ * NMI handler for pulling in CPUs when perf events are grabbing our NMI
+ */
+int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs)
+{
+ int ret;
+
+ uv_cpu_nmi.queries++;
+ if (!atomic_read(&uv_cpu_nmi.pinging)) {
+ atomic_inc(&uv_nmi_ping_misses);
+ return NMI_DONE;
+ }
+
+ uv_cpu_nmi.pings++;
+ atomic_inc(&uv_nmi_ping_count);
+ ret = uv_handle_nmi(reason, regs);
+ atomic_set(&uv_cpu_nmi.pinging, 0);
+ return ret;
+}
+
void uv_register_nmi_notifier(void)
{
if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv"))
pr_warn("UV NMI handler failed to register\n");
+
+ if (register_nmi_handler(NMI_LOCAL, uv_handle_nmi_ping, 0, "uvping"))
+ pr_warn("UV PING NMI handler failed to register\n");
}
void uv_nmi_init(void)
@@ -107,3 +602,30 @@ void uv_nmi_init(void)
apic_write(APIC_LVT1, value);
}
+void uv_nmi_setup(void)
+{
+ int size = sizeof(void *) * (1 << NODES_SHIFT);
+ int cpu, nid;
+
+ /* Setup hub nmi info */
+ uv_nmi_setup_mmrs();
+ uv_hub_nmi_list = kzalloc(size, GFP_KERNEL);
+ pr_info("UV: NMI hub list @ 0x%p (%d)\n", uv_hub_nmi_list, size);
+ BUG_ON(!uv_hub_nmi_list);
+ size = sizeof(struct uv_hub_nmi_s);
+ for_each_present_cpu(cpu) {
+ nid = cpu_to_node(cpu);
+ if (uv_hub_nmi_list[nid] == NULL) {
+ uv_hub_nmi_list[nid] = kzalloc_node(size,
+ GFP_KERNEL, nid);
+ BUG_ON(!uv_hub_nmi_list[nid]);
+ raw_spin_lock_init(&(uv_hub_nmi_list[nid]->nmi_lock));
+ atomic_set(&uv_hub_nmi_list[nid]->cpu_owner, -1);
+ }
+ uv_hub_nmi_per(cpu) = uv_hub_nmi_list[nid];
+ }
+ alloc_cpumask_var(&uv_nmi_cpu_mask, GFP_KERNEL);
+ BUG_ON(!uv_nmi_cpu_mask);
+}
+
+
--
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH 13/14] x86/UV: Update UV support for external NMI signals
2013-03-12 19:38 ` [PATCH 13/14] x86/UV: Update UV support for external NMI signals Mike Travis
@ 2013-03-14 7:20 ` Ingo Molnar
2013-03-20 6:13 ` Mike Travis
0 siblings, 1 reply; 28+ messages in thread
From: Ingo Molnar @ 2013-03-14 7:20 UTC (permalink / raw)
To: Mike Travis
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Russ Anderson, Alexander Gordeev, Suresh Siddha,
Michael S. Tsirkin, Steffen Persvold
* Mike Travis <travis@sgi.com> wrote:
>
> There is an exception where the NMI_LOCAL notifier chain is used. When
> the perf tools are in use, it's possible that our NMI was captured by
> some other NMI handler and then ignored. We set a per_cpu flag for
> those CPUs that ignored the initial NMI, and then send them an IPI NMI
> signal.
"Other" NMI handlers should never lose NMIs - if they do then they should
be fixed I think.
Thanks,
Ingo
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 13/14] x86/UV: Update UV support for external NMI signals
2013-03-14 7:20 ` Ingo Molnar
@ 2013-03-20 6:13 ` Mike Travis
2013-03-21 11:51 ` Ingo Molnar
0 siblings, 1 reply; 28+ messages in thread
From: Mike Travis @ 2013-03-20 6:13 UTC (permalink / raw)
To: Ingo Molnar
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Russ Anderson, Alexander Gordeev, Suresh Siddha,
Michael S. Tsirkin, Steffen Persvold
On 3/14/2013 12:20 AM, Ingo Molnar wrote:
>
> * Mike Travis <travis@sgi.com> wrote:
>
>>
>> There is an exception where the NMI_LOCAL notifier chain is used. When
>> the perf tools are in use, it's possible that our NMI was captured by
>> some other NMI handler and then ignored. We set a per_cpu flag for
>> those CPUs that ignored the initial NMI, and then send them an IPI NMI
>> signal.
>
> "Other" NMI handlers should never lose NMIs - if they do then they should
> be fixed I think.
>
> Thanks,
>
> Ingo
Hi Ingo,
I suspect that the other NMI handlers would not grab ours if we were
on the NMI_LOCAL chain to claim them. The problem though is the UV
Hub is not designed to have that amount of traffic reading the MMRs.
This was handled in previous kernel versions by a.) putting us at the
bottom of the chain; and b.) as soon as a handler claimed an NMI as
it's own, the search would be stopped.
Neither of these are true any more as all handlers are called for
all NMIs. (I measured anywhere from .5M to 4M NMIs per second on a
64 socket, 1024 cpu thread system [not sure why the rate changes]).
This was the primary motivation for placing the UV NMI handler on the
NMI_UNKNOWN chain, so it would be called only if all other handlers
"gave up", and thus not incur the overhead of the MMR reads on every
NMI event.
The good news is that I haven't yet encountered a case where the
"missing" cpus were not called into the NMI loop. Even better news
is that on the previous (3.0 vintage) kernels running two perf tops
would almost always cause either tons of the infamous "dazed and
confused" messages, or would lock up the system. Now it results in
quite a few messages like:
[ 961.119417] perf_event_intel: clearing PMU state on CPU#652
followed by a dump of a number of cpu PMC registers. But the system
remains responsive. (This was experienced in our Customer Training
Lab where multiple system admins were in the class.)
The bad news is I'm not sure why the errant NMI interrupts are lost.
I have noticed that restricting the 'perf tops' to separate and
distinct cpusets seems to lessen this "stomping on each other's perf
event handlers" effect, which might be more representative of actual
customer usage.
So in total the situation is vastly improved... :)
Thanks,
Mike
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 13/14] x86/UV: Update UV support for external NMI signals
2013-03-20 6:13 ` Mike Travis
@ 2013-03-21 11:51 ` Ingo Molnar
0 siblings, 0 replies; 28+ messages in thread
From: Ingo Molnar @ 2013-03-21 11:51 UTC (permalink / raw)
To: Mike Travis
Cc: Jason Wessel, Dimitri Sivanich, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Russ Anderson, Alexander Gordeev, Suresh Siddha,
Michael S. Tsirkin, Steffen Persvold
* Mike Travis <travis@sgi.com> wrote:
>
>
> On 3/14/2013 12:20 AM, Ingo Molnar wrote:
> >
> > * Mike Travis <travis@sgi.com> wrote:
> >
> >>
> >> There is an exception where the NMI_LOCAL notifier chain is used. When
> >> the perf tools are in use, it's possible that our NMI was captured by
> >> some other NMI handler and then ignored. We set a per_cpu flag for
> >> those CPUs that ignored the initial NMI, and then send them an IPI NMI
> >> signal.
> >
> > "Other" NMI handlers should never lose NMIs - if they do then they should
> > be fixed I think.
> >
> > Thanks,
> >
> > Ingo
>
> Hi Ingo,
>
> I suspect that the other NMI handlers would not grab ours if we were
> on the NMI_LOCAL chain to claim them. The problem though is the UV
> Hub is not designed to have that amount of traffic reading the MMRs.
> This was handled in previous kernel versions by a.) putting us at the
> bottom of the chain; and b.) as soon as a handler claimed an NMI as
> it's own, the search would be stopped.
>
> Neither of these are true any more as all handlers are called for
> all NMIs. (I measured anywhere from .5M to 4M NMIs per second on a
> 64 socket, 1024 cpu thread system [not sure why the rate changes]).
> This was the primary motivation for placing the UV NMI handler on the
> NMI_UNKNOWN chain, so it would be called only if all other handlers
> "gave up", and thus not incur the overhead of the MMR reads on every
> NMI event.
That's a fair motivation.
> The good news is that I haven't yet encountered a case where the
> "missing" cpus were not called into the NMI loop. Even better news
> is that on the previous (3.0 vintage) kernels running two perf tops
> would almost always cause either tons of the infamous "dazed and
> confused" messages, or would lock up the system. Now it results in
> quite a few messages like:
>
> [ 961.119417] perf_event_intel: clearing PMU state on CPU#652
>
> followed by a dump of a number of cpu PMC registers. But the system
> remains responsive. (This was experienced in our Customer Training
> Lab where multiple system admins were in the class.)
I too can provoke those messages when pushing PMUs hard enough via
multiple perf users. I suspect there's still some PMU erratum that
seems to have been introduced at around Nehalem CPUs.
Clearing the PMU works it around, at the cost of a loss of a slight
amount of profiling data.
> The bad news is I'm not sure why the errant NMI interrupts are lost.
> I have noticed that restricting the 'perf tops' to separate and
> distinct cpusets seems to lessen this "stomping on each other's perf
> event handlers" effect, which might be more representative of actual
> customer usage.
>
> So in total the situation is vastly improved... :)
Okay. My main dislike is the linecount:
4 files changed, 648 insertions(+), 41 deletions(-)
... for something that should in theory work almost out of box, with
minimal glue!
As long as it stays in the UV platform code this isn't a NAK from me -
just wanted to inquire whether most of that complexity could be eliminated
by figuring out the root cause of the lost NMIs ...
Thanks,
Ingo
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 14/14] x86/UV: Add call to KGDB/KDB from NMI handler
2013-03-12 19:38 [PATCH 00/14] x86/UV/KDB/NMI: Updates for NMI/KDB handler for SGI UV Mike Travis
` (12 preceding siblings ...)
2013-03-12 19:38 ` [PATCH 13/14] x86/UV: Update UV support for external NMI signals Mike Travis
@ 2013-03-12 19:38 ` Mike Travis
13 siblings, 0 replies; 28+ messages in thread
From: Mike Travis @ 2013-03-12 19:38 UTC (permalink / raw)
To: Jason Wessel
Cc: Dimitri Sivanich, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Andrew Morton, kgdb-bugreport, x86, linux-kernel,
Alexander Gordeev, Suresh Siddha, Michael S. Tsirkin,
Steffen Persvold
[-- Attachment #1: uv-add-nmi-call-kdb.patch --]
[-- Type: text/plain, Size: 3377 bytes --]
This patch restores the ability to enter KDB (and KGDB) from the UV
NMI handler. It utilizes the newly added kgdb_nmicallin function
to gain entry to KGDB/KDB by the master. The slaves still enter via
the standard kgdb_nmicallback function.
The handler also uses the new 'send_ready' pointer to tell KGDB/KDB
to signal the slaves when to proceed into the KGDB slave loop.
Cc: Alexander Gordeev <agordeev@redhat.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Steffen Persvold <sp@numascale.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
---
arch/x86/platform/uv/uv_nmi.c | 73 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 71 insertions(+), 2 deletions(-)
--- linux.orig/arch/x86/platform/uv/uv_nmi.c
+++ linux/arch/x86/platform/uv/uv_nmi.c
@@ -21,6 +21,8 @@
#include <linux/cpu.h>
#include <linux/delay.h>
+#include <linux/kgdb.h>
+#include <linux/kdb.h>
#include <linux/module.h>
#include <linux/nmi.h>
#include <linux/sched.h>
@@ -33,6 +35,7 @@
#include <asm/apic.h>
#include <asm/current.h>
#include <asm/kdebug.h>
+#include <asm/traps.h>
#include <asm/uv/uv.h>
#include <asm/uv/uv_hub.h>
#include <asm/uv/uv_mmrs.h>
@@ -511,6 +514,68 @@ static void uv_nmi_touch_watchdogs(void)
touch_nmi_watchdog();
}
+#ifdef CONFIG_KGDB_KDB
+
+/* Disable to force process dump instead of entering KDB or KGDB */
+static int uv_nmi_kdb_on = 1;
+module_param_named(kdb_on, uv_nmi_kdb_on, int, 0644);
+
+/* Call KDB from NMI handler */
+static void uv_call_kdb(int cpu, struct pt_regs *regs,
+ int master, unsigned long *flags)
+{
+ int ret;
+
+ if (master) {
+ /* call KGDB NMI handler as MASTER */
+ local_irq_restore(*flags);
+ ret = kgdb_nmicallin(cpu, X86_TRAP_NMI, regs,
+ &uv_nmi_slave_continue);
+ local_irq_save(*flags);
+
+ /*
+ * if KGDB/KDB did not handle the NMI, then signal slaves
+ * to do process dump instead.
+ */
+ if (ret) {
+ uv_nmi_dump_state(cpu, regs, 1);
+ return;
+ }
+ } else {
+ int sig;
+
+ /* wait for KGDB to say it's ready for slaves to enter */
+ do {
+ cpu_relax();
+ sig = atomic_read(&uv_nmi_slave_continue);
+ } while (!sig);
+
+ /*
+ * if KGDB/KDB did not handle the NMI for the master, then
+ * the master signals the slaves to do process dump instead.
+ */
+ if (sig == 2) {
+ uv_nmi_dump_state(cpu, regs, 0);
+ return;
+ }
+
+ /* call KGDB as slave */
+ local_irq_restore(*flags);
+ ret = kgdb_nmicallback(cpu, regs);
+ local_irq_save(*flags);
+ }
+ uv_nmi_sync_exit(master);
+}
+
+#else /* !CONFIG_KGDB_KDB */
+static inline void uv_call_kdb(int cpu, struct pt_regs *regs,
+ int master, unsigned long *flags)
+{
+ pr_err("UV: NMI error: KDB is not enabled in this kernel\n");
+ uv_nmi_dump_state(cpu, regs, master);
+}
+#endif /* !CONFIG_KGDB_KDB */
+
/*
* UV NMI handler
*/
@@ -537,8 +602,12 @@ int uv_handle_nmi(unsigned int reason, s
if (master && uv_nmi_kdump_requested)
uv_nmi_kdump(regs);
- /* Dump state of each cpu */
- uv_nmi_dump_state(cpu, regs, master);
+ /* Call KDB if enabled */
+ if (uv_nmi_kdb_on)
+ uv_call_kdb(cpu, regs, master, &flags);
+
+ else /* Otherwise dump state of each cpu */
+ uv_nmi_dump_state(cpu, regs, master);
/* Clear per_cpu "in nmi" flag */
atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT);
--
^ permalink raw reply [flat|nested] 28+ messages in thread