* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
* Author: Phil Schwan <phil@clusterfs.com>
*/
-#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
#include <linux/kmod.h>
+#include <linux/module.h>
#include <linux/notifier.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#ifdef HAVE_KERNEL_LOCKED
-#include <linux/smp_lock.h>
-#endif
#include <linux/unistd.h>
-#include <linux/interrupt.h>
-#include <asm/uaccess.h>
-#include <linux/completion.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/version.h>
+#include <linux/stacktrace.h>
+#include <linux/utsname.h>
# define DEBUG_SUBSYSTEM S_LNET
#include "tracefile.h"
-#include <linux/kallsyms.h>
-
char lnet_debug_log_upcall[1024] = "/usr/lib/lustre/lnet_debug_log_upcall";
/**
/* coverity[+kill] */
void lbug_with_loc(struct libcfs_debug_msg_data *msgdata)
{
- libcfs_catastrophe = 1;
- libcfs_debug_msg(msgdata, "LBUG\n");
+ libcfs_catastrophe = 1;
+ libcfs_debug_msg(msgdata, "LBUG\n");
- if (in_interrupt()) {
- panic("LBUG in interrupt.\n");
- /* not reached */
- }
+ if (in_interrupt()) {
+ panic("LBUG in interrupt.\n");
+ /* not reached */
+ }
- libcfs_debug_dumpstack(NULL);
- if (!libcfs_panic_on_lbug)
- libcfs_debug_dumplog();
- if (libcfs_panic_on_lbug)
- panic("LBUG");
+ libcfs_debug_dumpstack(NULL);
+ if (libcfs_panic_on_lbug)
+ panic("LBUG");
+ else
+ libcfs_debug_dumplog();
set_current_state(TASK_UNINTERRUPTIBLE);
- while (1)
- schedule();
+ while (1)
+ schedule();
}
EXPORT_SYMBOL(lbug_with_loc);
-#ifdef CONFIG_X86
-#include <linux/nmi.h>
-#include <asm/stacktrace.h>
+#ifdef CONFIG_STACKTRACE
-#ifdef HAVE_STACKTRACE_OPS
-#ifdef HAVE_STACKTRACE_WARNING
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
- printk("%s", (char *)data);
- print_symbol(msg, symbol);
- printk("\n");
-}
+#ifndef HAVE_SAVE_STACK_TRACE_TSK
+#define save_stack_trace_tsk(tsk, trace) \
+do { \
+ if (tsk == current) \
+ save_stack_trace(trace); \
+ else \
+ pr_info("No stack, save_stack_trace_tsk() not exported\n"); \
+} while (0)
+#endif
-static void print_trace_warning(void *data, char *msg)
+#define MAX_ST_ENTRIES 100
+static DEFINE_SPINLOCK(st_lock);
+
+/*
+ * Linux v5.1-rc5 214d8ca6ee ("stacktrace: Provide common infrastructure")
+ * CONFIG_ARCH_STACKWALK indicates that save_stack_trace_tsk symbol is not
+ * exported. Use symbol_get() to find if save_stack_trace_tsk is available.
+ */
+#ifdef CONFIG_ARCH_STACKWALK
+typedef unsigned int (stack_trace_save_tsk_t)(struct task_struct *task,
+ unsigned long *store, unsigned int size,
+ unsigned int skipnr);
+static stack_trace_save_tsk_t *task_dump_stack;
+#endif
+
+static void libcfs_call_trace(struct task_struct *tsk)
{
- printk("%s%s\n", (char *)data, msg);
-}
+#ifdef CONFIG_ARCH_STACKWALK
+ static unsigned long entries[MAX_ST_ENTRIES];
+ unsigned int i, nr_entries;
+
+ if (!task_dump_stack)
+ task_dump_stack = (stack_trace_save_tsk_t *)
+ symbol_get("stack_trace_save_tsk");
+
+ spin_lock(&st_lock);
+ pr_info("Pid: %d, comm: %.20s %s %s\n", tsk->pid, tsk->comm,
+ init_utsname()->release, init_utsname()->version);
+ pr_info("Call Trace TBD:\n");
+ if (task_dump_stack) {
+ nr_entries = task_dump_stack(tsk, entries, MAX_ST_ENTRIES, 0);
+ for (i = 0; i < nr_entries; i++)
+ pr_info("[<0>] %pB\n", (void *)entries[i]);
+ }
+ spin_unlock(&st_lock);
+#else
+ struct stack_trace trace;
+ static unsigned long entries[MAX_ST_ENTRIES];
+
+ trace.nr_entries = 0;
+ trace.max_entries = MAX_ST_ENTRIES;
+ trace.entries = entries;
+ trace.skip = 0;
+
+ spin_lock(&st_lock);
+ pr_info("Pid: %d, comm: %.20s %s %s\n", tsk->pid, tsk->comm,
+ init_utsname()->release, init_utsname()->version);
+ pr_info("Call Trace:\n");
+ save_stack_trace_tsk(tsk, &trace);
+ print_stack_trace(&trace, 0);
+ spin_unlock(&st_lock);
#endif
+}
+
+#else /* !CONFIG_STACKTRACE */
+
+#ifdef CONFIG_X86
+#include <linux/nmi.h>
+#include <asm/stacktrace.h>
+#ifdef HAVE_STACKTRACE_OPS
static int print_trace_stack(void *data, char *name)
{
printk(" <%s> ", name);
}
static const struct stacktrace_ops print_trace_ops = {
-#ifdef HAVE_STACKTRACE_WARNING
- .warning = print_trace_warning,
- .warning_symbol = print_trace_warning_symbol,
-#endif
.stack = print_trace_stack,
.address = print_trace_address,
-#ifdef STACKTRACE_OPS_HAVE_WALK_STACK
.walk_stack = print_context_stack,
-#endif
};
#endif /* HAVE_STACKTRACE_OPS */
#ifdef HAVE_STACKTRACE_OPS
printk("Pid: %d, comm: %.20s\n", tsk->pid, tsk->comm);
printk("\nCall Trace:\n");
- dump_trace(tsk, NULL, NULL,
-#ifdef HAVE_DUMP_TRACE_ADDRESS
- 0,
-#endif /* HAVE_DUMP_TRACE_ADDRESS */
- &print_trace_ops, NULL);
+ dump_trace(tsk, NULL, NULL, 0, &print_trace_ops, NULL);
printk("\n");
#else /* !HAVE_STACKTRACE_OPS */
if (tsk == current)
#endif /* CONFIG_X86 */
+#endif /* CONFIG_STACKTRACE */
+
void libcfs_debug_dumpstack(struct task_struct *tsk)
{
libcfs_call_trace(tsk ?: current);
}
EXPORT_SYMBOL(libcfs_debug_dumpstack);
-struct task_struct *libcfs_current(void)
-{
- CWARN("current task struct is %p\n", current);
- return current;
-}
-
static int panic_notifier(struct notifier_block *self, unsigned long unused1,
void *unused2)
{
if (in_interrupt()) {
cfs_trace_debug_print();
} else {
-#ifdef HAVE_KERNEL_LOCKED
- while (kernel_locked())
- unlock_kernel();
-#endif
libcfs_debug_dumplog_internal((void *)(long)current_pid());
}
#endif