diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 5 | ||||
-rw-r--r-- | Documentation/sysctl/kernel.txt | 17 | ||||
-rw-r--r-- | include/linux/nmi.h | 1 | ||||
-rw-r--r-- | kernel/sysctl.c | 11 | ||||
-rw-r--r-- | kernel/watchdog.c | 39 |
5 files changed, 73 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 884904975d0b..c1b9aa8c5a52 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -3130,6 +3130,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
3130 | [KNL] Should the soft-lockup detector generate panics. | 3130 | [KNL] Should the soft-lockup detector generate panics. |
3131 | Format: <integer> | 3131 | Format: <integer> |
3132 | 3132 | ||
3133 | softlockup_all_cpu_backtrace= | ||
3134 | [KNL] Should the soft-lockup detector generate | ||
3135 | backtraces on all cpus. | ||
3136 | Format: <integer> | ||
3137 | |||
3133 | sonypi.*= [HW] Sony Programmable I/O Control Device driver | 3138 | sonypi.*= [HW] Sony Programmable I/O Control Device driver |
3134 | See Documentation/laptops/sonypi.txt | 3139 | See Documentation/laptops/sonypi.txt |
3135 | 3140 | ||
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 708bb7f1b7e0..c14374e71775 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt | |||
@@ -75,6 +75,7 @@ show up in /proc/sys/kernel: | |||
75 | - shmall | 75 | - shmall |
76 | - shmmax [ sysv ipc ] | 76 | - shmmax [ sysv ipc ] |
77 | - shmmni | 77 | - shmmni |
78 | - softlockup_all_cpu_backtrace | ||
78 | - stop-a [ SPARC only ] | 79 | - stop-a [ SPARC only ] |
79 | - sysrq ==> Documentation/sysrq.txt | 80 | - sysrq ==> Documentation/sysrq.txt |
80 | - sysctl_writes_strict | 81 | - sysctl_writes_strict |
@@ -783,6 +784,22 @@ via the /proc/sys interface: | |||
783 | 784 | ||
784 | ============================================================== | 785 | ============================================================== |
785 | 786 | ||
787 | softlockup_all_cpu_backtrace: | ||
788 | |||
789 | This value controls the soft lockup detector thread's behavior | ||
790 | when a soft lockup condition is detected as to whether or not | ||
791 | to gather further debug information. If enabled, each cpu will | ||
792 | be issued an NMI and instructed to capture stack trace. | ||
793 | |||
794 | This feature is only applicable for architectures which support | ||
795 | NMI. | ||
796 | |||
797 | 0: do nothing. This is the default behavior. | ||
798 | |||
799 | 1: on detection capture more debug information. | ||
800 | |||
801 | ============================================================== | ||
802 | |||
786 | tainted: | 803 | tainted: |
787 | 804 | ||
788 | Non-zero if the kernel has been tainted. Numeric values, which | 805 | Non-zero if the kernel has been tainted. Numeric values, which |
diff --git a/include/linux/nmi.h b/include/linux/nmi.h index a17ab6398d7c..447775ee2c4b 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h | |||
@@ -57,6 +57,7 @@ int hw_nmi_is_cpu_stuck(struct pt_regs *); | |||
57 | u64 hw_nmi_get_sample_period(int watchdog_thresh); | 57 | u64 hw_nmi_get_sample_period(int watchdog_thresh); |
58 | extern int watchdog_user_enabled; | 58 | extern int watchdog_user_enabled; |
59 | extern int watchdog_thresh; | 59 | extern int watchdog_thresh; |
60 | extern int sysctl_softlockup_all_cpu_backtrace; | ||
60 | struct ctl_table; | 61 | struct ctl_table; |
61 | extern int proc_dowatchdog(struct ctl_table *, int , | 62 | extern int proc_dowatchdog(struct ctl_table *, int , |
62 | void __user *, size_t *, loff_t *); | 63 | void __user *, size_t *, loff_t *); |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 075d1903138f..75b22e22a72c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -860,6 +860,17 @@ static struct ctl_table kern_table[] = { | |||
860 | .extra1 = &zero, | 860 | .extra1 = &zero, |
861 | .extra2 = &one, | 861 | .extra2 = &one, |
862 | }, | 862 | }, |
863 | #ifdef CONFIG_SMP | ||
864 | { | ||
865 | .procname = "softlockup_all_cpu_backtrace", | ||
866 | .data = &sysctl_softlockup_all_cpu_backtrace, | ||
867 | .maxlen = sizeof(int), | ||
868 | .mode = 0644, | ||
869 | .proc_handler = proc_dointvec_minmax, | ||
870 | .extra1 = &zero, | ||
871 | .extra2 = &one, | ||
872 | }, | ||
873 | #endif /* CONFIG_SMP */ | ||
863 | { | 874 | { |
864 | .procname = "nmi_watchdog", | 875 | .procname = "nmi_watchdog", |
865 | .data = &watchdog_user_enabled, | 876 | .data = &watchdog_user_enabled, |
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 30e482240dae..c3319bd1b040 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
@@ -31,6 +31,12 @@ | |||
31 | 31 | ||
32 | int watchdog_user_enabled = 1; | 32 | int watchdog_user_enabled = 1; |
33 | int __read_mostly watchdog_thresh = 10; | 33 | int __read_mostly watchdog_thresh = 10; |
34 | #ifdef CONFIG_SMP | ||
35 | int __read_mostly sysctl_softlockup_all_cpu_backtrace; | ||
36 | #else | ||
37 | #define sysctl_softlockup_all_cpu_backtrace 0 | ||
38 | #endif | ||
39 | |||
34 | static int __read_mostly watchdog_running; | 40 | static int __read_mostly watchdog_running; |
35 | static u64 __read_mostly sample_period; | 41 | static u64 __read_mostly sample_period; |
36 | 42 | ||
@@ -47,6 +53,7 @@ static DEFINE_PER_CPU(bool, watchdog_nmi_touch); | |||
47 | static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); | 53 | static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); |
48 | static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); | 54 | static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); |
49 | #endif | 55 | #endif |
56 | static unsigned long soft_lockup_nmi_warn; | ||
50 | 57 | ||
51 | /* boot commands */ | 58 | /* boot commands */ |
52 | /* | 59 | /* |
@@ -95,6 +102,15 @@ static int __init nosoftlockup_setup(char *str) | |||
95 | } | 102 | } |
96 | __setup("nosoftlockup", nosoftlockup_setup); | 103 | __setup("nosoftlockup", nosoftlockup_setup); |
97 | /* */ | 104 | /* */ |
105 | #ifdef CONFIG_SMP | ||
106 | static int __init softlockup_all_cpu_backtrace_setup(char *str) | ||
107 | { | ||
108 | sysctl_softlockup_all_cpu_backtrace = | ||
109 | !!simple_strtol(str, NULL, 0); | ||
110 | return 1; | ||
111 | } | ||
112 | __setup("softlockup_all_cpu_backtrace=", softlockup_all_cpu_backtrace_setup); | ||
113 | #endif | ||
98 | 114 | ||
99 | /* | 115 | /* |
100 | * Hard-lockup warnings should be triggered after just a few seconds. Soft- | 116 | * 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) | |||
271 | unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts); | 287 | unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts); |
272 | struct pt_regs *regs = get_irq_regs(); | 288 | struct pt_regs *regs = get_irq_regs(); |
273 | int duration; | 289 | int duration; |
290 | int softlockup_all_cpu_backtrace = sysctl_softlockup_all_cpu_backtrace; | ||
274 | 291 | ||
275 | /* kick the hardlockup detector */ | 292 | /* kick the hardlockup detector */ |
276 | watchdog_interrupt_count(); | 293 | watchdog_interrupt_count(); |
@@ -317,6 +334,17 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) | |||
317 | if (__this_cpu_read(soft_watchdog_warn) == true) | 334 | if (__this_cpu_read(soft_watchdog_warn) == true) |
318 | return HRTIMER_RESTART; | 335 | return HRTIMER_RESTART; |
319 | 336 | ||
337 | if (softlockup_all_cpu_backtrace) { | ||
338 | /* Prevent multiple soft-lockup reports if one cpu is already | ||
339 | * engaged in dumping cpu back traces | ||
340 | */ | ||
341 | if (test_and_set_bit(0, &soft_lockup_nmi_warn)) { | ||
342 | /* Someone else will report us. Let's give up */ | ||
343 | __this_cpu_write(soft_watchdog_warn, true); | ||
344 | return HRTIMER_RESTART; | ||
345 | } | ||
346 | } | ||
347 | |||
320 | printk(KERN_EMERG "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", | 348 | printk(KERN_EMERG "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", |
321 | smp_processor_id(), duration, | 349 | smp_processor_id(), duration, |
322 | current->comm, task_pid_nr(current)); | 350 | current->comm, task_pid_nr(current)); |
@@ -327,6 +355,17 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) | |||
327 | else | 355 | else |
328 | dump_stack(); | 356 | dump_stack(); |
329 | 357 | ||
358 | if (softlockup_all_cpu_backtrace) { | ||
359 | /* Avoid generating two back traces for current | ||
360 | * given that one is already made above | ||
361 | */ | ||
362 | trigger_allbutself_cpu_backtrace(); | ||
363 | |||
364 | clear_bit(0, &soft_lockup_nmi_warn); | ||
365 | /* Barrier to sync with other cpus */ | ||
366 | smp_mb__after_atomic(); | ||
367 | } | ||
368 | |||
330 | if (softlockup_panic) | 369 | if (softlockup_panic) |
331 | panic("softlockup: hung tasks"); | 370 | panic("softlockup: hung tasks"); |
332 | __this_cpu_write(soft_watchdog_warn, true); | 371 | __this_cpu_write(soft_watchdog_warn, true); |