|
@@ -31,6 +31,12 @@
|
|
|
|
|
|
int watchdog_user_enabled = 1;
|
|
|
int __read_mostly watchdog_thresh = 10;
|
|
|
+#ifdef CONFIG_SMP
|
|
|
+int __read_mostly sysctl_softlockup_all_cpu_backtrace;
|
|
|
+#else
|
|
|
+#define sysctl_softlockup_all_cpu_backtrace 0
|
|
|
+#endif
|
|
|
+
|
|
|
static int __read_mostly watchdog_running;
|
|
|
static u64 __read_mostly sample_period;
|
|
|
|
|
@@ -47,6 +53,7 @@ static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
|
|
|
static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
|
|
|
static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
|
|
|
#endif
|
|
|
+static unsigned long soft_lockup_nmi_warn;
|
|
|
|
|
|
/* boot commands */
|
|
|
/*
|
|
@@ -95,6 +102,15 @@ static int __init nosoftlockup_setup(char *str)
|
|
|
}
|
|
|
__setup("nosoftlockup", nosoftlockup_setup);
|
|
|
/* */
|
|
|
+#ifdef CONFIG_SMP
|
|
|
+static int __init softlockup_all_cpu_backtrace_setup(char *str)
|
|
|
+{
|
|
|
+ sysctl_softlockup_all_cpu_backtrace =
|
|
|
+ !!simple_strtol(str, NULL, 0);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+__setup("softlockup_all_cpu_backtrace=", softlockup_all_cpu_backtrace_setup);
|
|
|
+#endif
|
|
|
|
|
|
/*
|
|
|
* Hard-lockup warnings should be triggered after just a few seconds. Soft-
|
|
@@ -271,6 +287,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
|
|
|
unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts);
|
|
|
struct pt_regs *regs = get_irq_regs();
|
|
|
int duration;
|
|
|
+ int softlockup_all_cpu_backtrace = sysctl_softlockup_all_cpu_backtrace;
|
|
|
|
|
|
/* kick the hardlockup detector */
|
|
|
watchdog_interrupt_count();
|
|
@@ -317,6 +334,17 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
|
|
|
if (__this_cpu_read(soft_watchdog_warn) == true)
|
|
|
return HRTIMER_RESTART;
|
|
|
|
|
|
+ if (softlockup_all_cpu_backtrace) {
|
|
|
+ /* Prevent multiple soft-lockup reports if one cpu is already
|
|
|
+ * engaged in dumping cpu back traces
|
|
|
+ */
|
|
|
+ if (test_and_set_bit(0, &soft_lockup_nmi_warn)) {
|
|
|
+ /* Someone else will report us. Let's give up */
|
|
|
+ __this_cpu_write(soft_watchdog_warn, true);
|
|
|
+ return HRTIMER_RESTART;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
printk(KERN_EMERG "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
|
|
|
smp_processor_id(), duration,
|
|
|
current->comm, task_pid_nr(current));
|
|
@@ -327,6 +355,17 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
|
|
|
else
|
|
|
dump_stack();
|
|
|
|
|
|
+ if (softlockup_all_cpu_backtrace) {
|
|
|
+ /* Avoid generating two back traces for current
|
|
|
+ * given that one is already made above
|
|
|
+ */
|
|
|
+ trigger_allbutself_cpu_backtrace();
|
|
|
+
|
|
|
+ clear_bit(0, &soft_lockup_nmi_warn);
|
|
|
+ /* Barrier to sync with other cpus */
|
|
|
+ smp_mb__after_atomic();
|
|
|
+ }
|
|
|
+
|
|
|
if (softlockup_panic)
|
|
|
panic("softlockup: hung tasks");
|
|
|
__this_cpu_write(soft_watchdog_warn, true);
|