mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	kernel/watchdog: split up config options
Split SOFTLOCKUP_DETECTOR from LOCKUP_DETECTOR, and split HARDLOCKUP_DETECTOR_PERF from HARDLOCKUP_DETECTOR. LOCKUP_DETECTOR implies the general boot, sysctl, and programming interfaces for the lockup detectors. An architecture that wants to use a hard lockup detector must define HAVE_HARDLOCKUP_DETECTOR_PERF or HAVE_HARDLOCKUP_DETECTOR_ARCH. Alternatively an arch can define HAVE_NMI_WATCHDOG, which provides the minimum arch_touch_nmi_watchdog, and it otherwise does its own thing and does not implement the LOCKUP_DETECTOR interfaces. sparc is unusual in that it has started to implement some of the interfaces, but not fully yet. It should probably be converted to a full HAVE_HARDLOCKUP_DETECTOR_ARCH. [npiggin@gmail.com: fix] Link: http://lkml.kernel.org/r/20170617223522.66c0ad88@roar.ozlabs.ibm.com Link: http://lkml.kernel.org/r/20170616065715.18390-4-npiggin@gmail.com Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Reviewed-by: Don Zickus <dzickus@redhat.com> Reviewed-by: Babu Moger <babu.moger@oracle.com> Tested-by: Babu Moger <babu.moger@oracle.com> [sparc] Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									f2e0cff85e
								
							
						
					
					
						commit
						05a4a95279
					
				
					 11 changed files with 257 additions and 168 deletions
				
			
		
							
								
								
									
										25
									
								
								arch/Kconfig
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								arch/Kconfig
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -198,9 +198,6 @@ config HAVE_KPROBES_ON_FTRACE
 | 
			
		|||
config HAVE_NMI
 | 
			
		||||
	bool
 | 
			
		||||
 | 
			
		||||
config HAVE_NMI_WATCHDOG
 | 
			
		||||
	depends on HAVE_NMI
 | 
			
		||||
	bool
 | 
			
		||||
#
 | 
			
		||||
# An arch should select this if it provides all these things:
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -288,6 +285,28 @@ config HAVE_PERF_EVENTS_NMI
 | 
			
		|||
	  subsystem.  Also has support for calculating CPU cycle events
 | 
			
		||||
	  to determine how many clock cycles in a given period.
 | 
			
		||||
 | 
			
		||||
config HAVE_HARDLOCKUP_DETECTOR_PERF
 | 
			
		||||
	bool
 | 
			
		||||
	depends on HAVE_PERF_EVENTS_NMI
 | 
			
		||||
	help
 | 
			
		||||
	  The arch chooses to use the generic perf-NMI-based hardlockup
 | 
			
		||||
	  detector. Must define HAVE_PERF_EVENTS_NMI.
 | 
			
		||||
 | 
			
		||||
config HAVE_NMI_WATCHDOG
 | 
			
		||||
	depends on HAVE_NMI
 | 
			
		||||
	bool
 | 
			
		||||
	help
 | 
			
		||||
	  The arch provides a low level NMI watchdog. It provides
 | 
			
		||||
	  asm/nmi.h, and defines its own arch_touch_nmi_watchdog().
 | 
			
		||||
 | 
			
		||||
config HAVE_HARDLOCKUP_DETECTOR_ARCH
 | 
			
		||||
	bool
 | 
			
		||||
	select HAVE_NMI_WATCHDOG
 | 
			
		||||
	help
 | 
			
		||||
	  The arch chooses to provide its own hardlockup detector, which is
 | 
			
		||||
	  a superset of the HAVE_NMI_WATCHDOG. It also conforms to config
 | 
			
		||||
	  interfaces and parameters provided by hardlockup detector subsystem.
 | 
			
		||||
 | 
			
		||||
config HAVE_PERF_REGS
 | 
			
		||||
	bool
 | 
			
		||||
	help
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -197,6 +197,7 @@ config PPC
 | 
			
		|||
	select HAVE_OPTPROBES			if PPC64
 | 
			
		||||
	select HAVE_PERF_EVENTS
 | 
			
		||||
	select HAVE_PERF_EVENTS_NMI		if PPC64
 | 
			
		||||
	select HAVE_HARDLOCKUP_DETECTOR_PERF	if HAVE_PERF_EVENTS_NMI
 | 
			
		||||
	select HAVE_PERF_REGS
 | 
			
		||||
	select HAVE_PERF_USER_STACK_DUMP
 | 
			
		||||
	select HAVE_RCU_TABLE_FREE		if SMP
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -752,7 +752,7 @@ struct ppc_pci_io ppc_pci_io;
 | 
			
		|||
EXPORT_SYMBOL(ppc_pci_io);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
 | 
			
		||||
u64 hw_nmi_get_sample_period(int watchdog_thresh)
 | 
			
		||||
{
 | 
			
		||||
	return ppc_proc_freq * watchdog_thresh;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -162,6 +162,7 @@ config X86
 | 
			
		|||
	select HAVE_PCSPKR_PLATFORM
 | 
			
		||||
	select HAVE_PERF_EVENTS
 | 
			
		||||
	select HAVE_PERF_EVENTS_NMI
 | 
			
		||||
	select HAVE_HARDLOCKUP_DETECTOR_PERF	if HAVE_PERF_EVENTS_NMI
 | 
			
		||||
	select HAVE_PERF_REGS
 | 
			
		||||
	select HAVE_PERF_USER_STACK_DUMP
 | 
			
		||||
	select HAVE_REGS_AND_STACK_ACCESS_API
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@
 | 
			
		|||
#include <linux/init.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
 | 
			
		||||
u64 hw_nmi_get_sample_period(int watchdog_thresh)
 | 
			
		||||
{
 | 
			
		||||
	return (u64)(cpu_khz) * 1000 * watchdog_thresh;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,13 +11,21 @@
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_LOCKUP_DETECTOR
 | 
			
		||||
void lockup_detector_init(void);
 | 
			
		||||
#else
 | 
			
		||||
static inline void lockup_detector_init(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SOFTLOCKUP_DETECTOR
 | 
			
		||||
extern void touch_softlockup_watchdog_sched(void);
 | 
			
		||||
extern void touch_softlockup_watchdog(void);
 | 
			
		||||
extern void touch_softlockup_watchdog_sync(void);
 | 
			
		||||
extern void touch_all_softlockup_watchdogs(void);
 | 
			
		||||
extern unsigned int  softlockup_panic;
 | 
			
		||||
extern unsigned int  hardlockup_panic;
 | 
			
		||||
void lockup_detector_init(void);
 | 
			
		||||
extern int soft_watchdog_enabled;
 | 
			
		||||
extern atomic_t watchdog_park_in_progress;
 | 
			
		||||
#else
 | 
			
		||||
static inline void touch_softlockup_watchdog_sched(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -31,9 +39,6 @@ static inline void touch_softlockup_watchdog_sync(void)
 | 
			
		|||
static inline void touch_all_softlockup_watchdogs(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
static inline void lockup_detector_init(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_DETECT_HUNG_TASK
 | 
			
		||||
| 
						 | 
				
			
			@ -63,15 +68,18 @@ static inline void reset_hung_task_detector(void)
 | 
			
		|||
 | 
			
		||||
#if defined(CONFIG_HARDLOCKUP_DETECTOR)
 | 
			
		||||
extern void hardlockup_detector_disable(void);
 | 
			
		||||
extern unsigned int hardlockup_panic;
 | 
			
		||||
#else
 | 
			
		||||
static inline void hardlockup_detector_disable(void) {}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_HARDLOCKUP_DETECTOR) || defined(CONFIG_HAVE_NMI_WATCHDOG)
 | 
			
		||||
#if defined(CONFIG_HARDLOCKUP_DETECTOR_PERF)
 | 
			
		||||
extern void arch_touch_nmi_watchdog(void);
 | 
			
		||||
#else
 | 
			
		||||
#if !defined(CONFIG_HAVE_NMI_WATCHDOG)
 | 
			
		||||
static inline void arch_touch_nmi_watchdog(void) {}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * touch_nmi_watchdog - restart NMI watchdog timeout.
 | 
			
		||||
| 
						 | 
				
			
			@ -141,15 +149,18 @@ static inline bool trigger_single_cpu_backtrace(int cpu)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_LOCKUP_DETECTOR
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
 | 
			
		||||
u64 hw_nmi_get_sample_period(int watchdog_thresh);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_LOCKUP_DETECTOR
 | 
			
		||||
extern int nmi_watchdog_enabled;
 | 
			
		||||
extern int soft_watchdog_enabled;
 | 
			
		||||
extern int watchdog_user_enabled;
 | 
			
		||||
extern int watchdog_thresh;
 | 
			
		||||
extern unsigned long watchdog_enabled;
 | 
			
		||||
extern struct cpumask watchdog_cpumask;
 | 
			
		||||
extern unsigned long *watchdog_cpumask_bits;
 | 
			
		||||
extern atomic_t watchdog_park_in_progress;
 | 
			
		||||
extern int __read_mostly watchdog_suspended;
 | 
			
		||||
#ifdef CONFIG_SMP
 | 
			
		||||
extern int sysctl_softlockup_all_cpu_backtrace;
 | 
			
		||||
extern int sysctl_hardlockup_all_cpu_backtrace;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,7 +82,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
 | 
			
		|||
obj-$(CONFIG_KGDB) += debug/
 | 
			
		||||
obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
 | 
			
		||||
obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o
 | 
			
		||||
obj-$(CONFIG_HARDLOCKUP_DETECTOR) += watchdog_hld.o
 | 
			
		||||
obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF) += watchdog_hld.o
 | 
			
		||||
obj-$(CONFIG_SECCOMP) += seccomp.o
 | 
			
		||||
obj-$(CONFIG_RELAY) += relay.o
 | 
			
		||||
obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -900,6 +900,14 @@ static struct ctl_table kern_table[] = {
 | 
			
		|||
		.extra2		= &zero,
 | 
			
		||||
#endif
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "watchdog_cpumask",
 | 
			
		||||
		.data		= &watchdog_cpumask_bits,
 | 
			
		||||
		.maxlen		= NR_CPUS,
 | 
			
		||||
		.mode		= 0644,
 | 
			
		||||
		.proc_handler	= proc_watchdog_cpumask,
 | 
			
		||||
	},
 | 
			
		||||
#ifdef CONFIG_SOFTLOCKUP_DETECTOR
 | 
			
		||||
	{
 | 
			
		||||
		.procname       = "soft_watchdog",
 | 
			
		||||
		.data           = &soft_watchdog_enabled,
 | 
			
		||||
| 
						 | 
				
			
			@ -909,13 +917,6 @@ static struct ctl_table kern_table[] = {
 | 
			
		|||
		.extra1		= &zero,
 | 
			
		||||
		.extra2		= &one,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "watchdog_cpumask",
 | 
			
		||||
		.data		= &watchdog_cpumask_bits,
 | 
			
		||||
		.maxlen		= NR_CPUS,
 | 
			
		||||
		.mode		= 0644,
 | 
			
		||||
		.proc_handler	= proc_watchdog_cpumask,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "softlockup_panic",
 | 
			
		||||
		.data		= &softlockup_panic,
 | 
			
		||||
| 
						 | 
				
			
			@ -925,17 +926,6 @@ static struct ctl_table kern_table[] = {
 | 
			
		|||
		.extra1		= &zero,
 | 
			
		||||
		.extra2		= &one,
 | 
			
		||||
	},
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "hardlockup_panic",
 | 
			
		||||
		.data		= &hardlockup_panic,
 | 
			
		||||
		.maxlen		= sizeof(int),
 | 
			
		||||
		.mode		= 0644,
 | 
			
		||||
		.proc_handler	= proc_dointvec_minmax,
 | 
			
		||||
		.extra1		= &zero,
 | 
			
		||||
		.extra2		= &one,
 | 
			
		||||
	},
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_SMP
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "softlockup_all_cpu_backtrace",
 | 
			
		||||
| 
						 | 
				
			
			@ -946,6 +936,19 @@ static struct ctl_table kern_table[] = {
 | 
			
		|||
		.extra1		= &zero,
 | 
			
		||||
		.extra2		= &one,
 | 
			
		||||
	},
 | 
			
		||||
#endif /* CONFIG_SMP */
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "hardlockup_panic",
 | 
			
		||||
		.data		= &hardlockup_panic,
 | 
			
		||||
		.maxlen		= sizeof(int),
 | 
			
		||||
		.mode		= 0644,
 | 
			
		||||
		.proc_handler	= proc_dointvec_minmax,
 | 
			
		||||
		.extra1		= &zero,
 | 
			
		||||
		.extra2		= &one,
 | 
			
		||||
	},
 | 
			
		||||
#ifdef CONFIG_SMP
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "hardlockup_all_cpu_backtrace",
 | 
			
		||||
		.data		= &sysctl_hardlockup_all_cpu_backtrace,
 | 
			
		||||
| 
						 | 
				
			
			@ -957,6 +960,8 @@ static struct ctl_table kern_table[] = {
 | 
			
		|||
	},
 | 
			
		||||
#endif /* CONFIG_SMP */
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
 | 
			
		||||
	{
 | 
			
		||||
		.procname       = "unknown_nmi_panic",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,15 +29,58 @@
 | 
			
		|||
#include <linux/kvm_para.h>
 | 
			
		||||
#include <linux/kthread.h>
 | 
			
		||||
 | 
			
		||||
/* Watchdog configuration */
 | 
			
		||||
static DEFINE_MUTEX(watchdog_proc_mutex);
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
 | 
			
		||||
unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED;
 | 
			
		||||
int __read_mostly nmi_watchdog_enabled;
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_HARDLOCKUP_DETECTOR) || defined(CONFIG_HAVE_NMI_WATCHDOG)
 | 
			
		||||
unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED |
 | 
			
		||||
						NMI_WATCHDOG_ENABLED;
 | 
			
		||||
#else
 | 
			
		||||
unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED;
 | 
			
		||||
#endif
 | 
			
		||||
int __read_mostly nmi_watchdog_enabled;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR
 | 
			
		||||
/* boot commands */
 | 
			
		||||
/*
 | 
			
		||||
 * Should we panic when a soft-lockup or hard-lockup occurs:
 | 
			
		||||
 */
 | 
			
		||||
unsigned int __read_mostly hardlockup_panic =
 | 
			
		||||
			CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
 | 
			
		||||
/*
 | 
			
		||||
 * We may not want to enable hard lockup detection by default in all cases,
 | 
			
		||||
 * for example when running the kernel as a guest on a hypervisor. In these
 | 
			
		||||
 * cases this function can be called to disable hard lockup detection. This
 | 
			
		||||
 * function should only be executed once by the boot processor before the
 | 
			
		||||
 * kernel command line parameters are parsed, because otherwise it is not
 | 
			
		||||
 * possible to override this in hardlockup_panic_setup().
 | 
			
		||||
 */
 | 
			
		||||
void hardlockup_detector_disable(void)
 | 
			
		||||
{
 | 
			
		||||
	watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init hardlockup_panic_setup(char *str)
 | 
			
		||||
{
 | 
			
		||||
	if (!strncmp(str, "panic", 5))
 | 
			
		||||
		hardlockup_panic = 1;
 | 
			
		||||
	else if (!strncmp(str, "nopanic", 7))
 | 
			
		||||
		hardlockup_panic = 0;
 | 
			
		||||
	else if (!strncmp(str, "0", 1))
 | 
			
		||||
		watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
 | 
			
		||||
	else if (!strncmp(str, "1", 1))
 | 
			
		||||
		watchdog_enabled |= NMI_WATCHDOG_ENABLED;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
__setup("nmi_watchdog=", hardlockup_panic_setup);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SOFTLOCKUP_DETECTOR
 | 
			
		||||
int __read_mostly soft_watchdog_enabled;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int __read_mostly watchdog_user_enabled;
 | 
			
		||||
int __read_mostly watchdog_thresh = 10;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -45,15 +88,9 @@ int __read_mostly watchdog_thresh = 10;
 | 
			
		|||
int __read_mostly sysctl_softlockup_all_cpu_backtrace;
 | 
			
		||||
int __read_mostly sysctl_hardlockup_all_cpu_backtrace;
 | 
			
		||||
#endif
 | 
			
		||||
static struct cpumask watchdog_cpumask __read_mostly;
 | 
			
		||||
struct cpumask watchdog_cpumask __read_mostly;
 | 
			
		||||
unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask);
 | 
			
		||||
 | 
			
		||||
/* Helper for online, unparked cpus. */
 | 
			
		||||
#define for_each_watchdog_cpu(cpu) \
 | 
			
		||||
	for_each_cpu_and((cpu), cpu_online_mask, &watchdog_cpumask)
 | 
			
		||||
 | 
			
		||||
atomic_t watchdog_park_in_progress = ATOMIC_INIT(0);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The 'watchdog_running' variable is set to 1 when the watchdog threads
 | 
			
		||||
 * are registered/started and is set to 0 when the watchdog threads are
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +109,27 @@ static int __read_mostly watchdog_running;
 | 
			
		|||
 * of 'watchdog_running' cannot change while the watchdog is deactivated
 | 
			
		||||
 * temporarily (see related code in 'proc' handlers).
 | 
			
		||||
 */
 | 
			
		||||
static int __read_mostly watchdog_suspended;
 | 
			
		||||
int __read_mostly watchdog_suspended;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These functions can be overridden if an architecture implements its
 | 
			
		||||
 * own hardlockup detector.
 | 
			
		||||
 */
 | 
			
		||||
int __weak watchdog_nmi_enable(unsigned int cpu)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
void __weak watchdog_nmi_disable(unsigned int cpu)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SOFTLOCKUP_DETECTOR
 | 
			
		||||
 | 
			
		||||
/* Helper for online, unparked cpus. */
 | 
			
		||||
#define for_each_watchdog_cpu(cpu) \
 | 
			
		||||
	for_each_cpu_and((cpu), cpu_online_mask, &watchdog_cpumask)
 | 
			
		||||
 | 
			
		||||
atomic_t watchdog_park_in_progress = ATOMIC_INIT(0);
 | 
			
		||||
 | 
			
		||||
static u64 __read_mostly sample_period;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -120,6 +177,7 @@ static int __init softlockup_all_cpu_backtrace_setup(char *str)
 | 
			
		|||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
__setup("softlockup_all_cpu_backtrace=", softlockup_all_cpu_backtrace_setup);
 | 
			
		||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR
 | 
			
		||||
static int __init hardlockup_all_cpu_backtrace_setup(char *str)
 | 
			
		||||
{
 | 
			
		||||
	sysctl_hardlockup_all_cpu_backtrace =
 | 
			
		||||
| 
						 | 
				
			
			@ -128,6 +186,7 @@ static int __init hardlockup_all_cpu_backtrace_setup(char *str)
 | 
			
		|||
}
 | 
			
		||||
__setup("hardlockup_all_cpu_backtrace=", hardlockup_all_cpu_backtrace_setup);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hard-lockup warnings should be triggered after just a few seconds. Soft-
 | 
			
		||||
| 
						 | 
				
			
			@ -213,18 +272,6 @@ void touch_softlockup_watchdog_sync(void)
 | 
			
		|||
	__this_cpu_write(watchdog_touch_ts, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* watchdog detector functions */
 | 
			
		||||
bool is_hardlockup(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long hrint = __this_cpu_read(hrtimer_interrupts);
 | 
			
		||||
 | 
			
		||||
	if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	__this_cpu_write(hrtimer_interrupts_saved, hrint);
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_softlockup(unsigned long touch_ts)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long now = get_timestamp();
 | 
			
		||||
| 
						 | 
				
			
			@ -237,23 +284,23 @@ static int is_softlockup(unsigned long touch_ts)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* watchdog detector functions */
 | 
			
		||||
bool is_hardlockup(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long hrint = __this_cpu_read(hrtimer_interrupts);
 | 
			
		||||
 | 
			
		||||
	if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	__this_cpu_write(hrtimer_interrupts_saved, hrint);
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void watchdog_interrupt_count(void)
 | 
			
		||||
{
 | 
			
		||||
	__this_cpu_inc(hrtimer_interrupts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These two functions are mostly architecture specific
 | 
			
		||||
 * defining them as weak here.
 | 
			
		||||
 */
 | 
			
		||||
int __weak watchdog_nmi_enable(unsigned int cpu)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
void __weak watchdog_nmi_disable(unsigned int cpu)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int watchdog_enable_all_cpus(void);
 | 
			
		||||
static void watchdog_disable_all_cpus(void);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -502,57 +549,6 @@ static void watchdog_unpark_threads(void)
 | 
			
		|||
		kthread_unpark(per_cpu(softlockup_watchdog, cpu));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Suspend the hard and soft lockup detector by parking the watchdog threads.
 | 
			
		||||
 */
 | 
			
		||||
int lockup_detector_suspend(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	get_online_cpus();
 | 
			
		||||
	mutex_lock(&watchdog_proc_mutex);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Multiple suspend requests can be active in parallel (counted by
 | 
			
		||||
	 * the 'watchdog_suspended' variable). If the watchdog threads are
 | 
			
		||||
	 * running, the first caller takes care that they will be parked.
 | 
			
		||||
	 * The state of 'watchdog_running' cannot change while a suspend
 | 
			
		||||
	 * request is active (see related code in 'proc' handlers).
 | 
			
		||||
	 */
 | 
			
		||||
	if (watchdog_running && !watchdog_suspended)
 | 
			
		||||
		ret = watchdog_park_threads();
 | 
			
		||||
 | 
			
		||||
	if (ret == 0)
 | 
			
		||||
		watchdog_suspended++;
 | 
			
		||||
	else {
 | 
			
		||||
		watchdog_disable_all_cpus();
 | 
			
		||||
		pr_err("Failed to suspend lockup detectors, disabled\n");
 | 
			
		||||
		watchdog_enabled = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&watchdog_proc_mutex);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Resume the hard and soft lockup detector by unparking the watchdog threads.
 | 
			
		||||
 */
 | 
			
		||||
void lockup_detector_resume(void)
 | 
			
		||||
{
 | 
			
		||||
	mutex_lock(&watchdog_proc_mutex);
 | 
			
		||||
 | 
			
		||||
	watchdog_suspended--;
 | 
			
		||||
	/*
 | 
			
		||||
	 * The watchdog threads are unparked if they were previously running
 | 
			
		||||
	 * and if there is no more active suspend request.
 | 
			
		||||
	 */
 | 
			
		||||
	if (watchdog_running && !watchdog_suspended)
 | 
			
		||||
		watchdog_unpark_threads();
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&watchdog_proc_mutex);
 | 
			
		||||
	put_online_cpus();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int update_watchdog_all_cpus(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -604,6 +600,81 @@ static void watchdog_disable_all_cpus(void)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else /* SOFTLOCKUP */
 | 
			
		||||
static int watchdog_park_threads(void)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void watchdog_unpark_threads(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int watchdog_enable_all_cpus(void)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void watchdog_disable_all_cpus(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_sample_period(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif /* SOFTLOCKUP */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Suspend the hard and soft lockup detector by parking the watchdog threads.
 | 
			
		||||
 */
 | 
			
		||||
int lockup_detector_suspend(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	get_online_cpus();
 | 
			
		||||
	mutex_lock(&watchdog_proc_mutex);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Multiple suspend requests can be active in parallel (counted by
 | 
			
		||||
	 * the 'watchdog_suspended' variable). If the watchdog threads are
 | 
			
		||||
	 * running, the first caller takes care that they will be parked.
 | 
			
		||||
	 * The state of 'watchdog_running' cannot change while a suspend
 | 
			
		||||
	 * request is active (see related code in 'proc' handlers).
 | 
			
		||||
	 */
 | 
			
		||||
	if (watchdog_running && !watchdog_suspended)
 | 
			
		||||
		ret = watchdog_park_threads();
 | 
			
		||||
 | 
			
		||||
	if (ret == 0)
 | 
			
		||||
		watchdog_suspended++;
 | 
			
		||||
	else {
 | 
			
		||||
		watchdog_disable_all_cpus();
 | 
			
		||||
		pr_err("Failed to suspend lockup detectors, disabled\n");
 | 
			
		||||
		watchdog_enabled = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&watchdog_proc_mutex);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Resume the hard and soft lockup detector by unparking the watchdog threads.
 | 
			
		||||
 */
 | 
			
		||||
void lockup_detector_resume(void)
 | 
			
		||||
{
 | 
			
		||||
	mutex_lock(&watchdog_proc_mutex);
 | 
			
		||||
 | 
			
		||||
	watchdog_suspended--;
 | 
			
		||||
	/*
 | 
			
		||||
	 * The watchdog threads are unparked if they were previously running
 | 
			
		||||
	 * and if there is no more active suspend request.
 | 
			
		||||
	 */
 | 
			
		||||
	if (watchdog_running && !watchdog_suspended)
 | 
			
		||||
		watchdog_unpark_threads();
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&watchdog_proc_mutex);
 | 
			
		||||
	put_online_cpus();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SYSCTL
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -810,9 +881,11 @@ int proc_watchdog_cpumask(struct ctl_table *table, int write,
 | 
			
		|||
			 * a temporary cpumask, so we are likely not in a
 | 
			
		||||
			 * position to do much else to make things better.
 | 
			
		||||
			 */
 | 
			
		||||
#ifdef CONFIG_SOFTLOCKUP_DETECTOR
 | 
			
		||||
			if (smpboot_update_cpumask_percpu_thread(
 | 
			
		||||
				    &watchdog_threads, &watchdog_cpumask) != 0)
 | 
			
		||||
				pr_err("cpumask update failed\n");
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,39 +22,7 @@ static DEFINE_PER_CPU(bool, hard_watchdog_warn);
 | 
			
		|||
static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
 | 
			
		||||
static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 | 
			
		||||
 | 
			
		||||
/* boot commands */
 | 
			
		||||
/*
 | 
			
		||||
 * Should we panic when a soft-lockup or hard-lockup occurs:
 | 
			
		||||
 */
 | 
			
		||||
unsigned int __read_mostly hardlockup_panic =
 | 
			
		||||
			CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
 | 
			
		||||
static unsigned long hardlockup_allcpu_dumped;
 | 
			
		||||
/*
 | 
			
		||||
 * We may not want to enable hard lockup detection by default in all cases,
 | 
			
		||||
 * for example when running the kernel as a guest on a hypervisor. In these
 | 
			
		||||
 * cases this function can be called to disable hard lockup detection. This
 | 
			
		||||
 * function should only be executed once by the boot processor before the
 | 
			
		||||
 * kernel command line parameters are parsed, because otherwise it is not
 | 
			
		||||
 * possible to override this in hardlockup_panic_setup().
 | 
			
		||||
 */
 | 
			
		||||
void hardlockup_detector_disable(void)
 | 
			
		||||
{
 | 
			
		||||
	watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __init hardlockup_panic_setup(char *str)
 | 
			
		||||
{
 | 
			
		||||
	if (!strncmp(str, "panic", 5))
 | 
			
		||||
		hardlockup_panic = 1;
 | 
			
		||||
	else if (!strncmp(str, "nopanic", 7))
 | 
			
		||||
		hardlockup_panic = 0;
 | 
			
		||||
	else if (!strncmp(str, "0", 1))
 | 
			
		||||
		watchdog_enabled &= ~NMI_WATCHDOG_ENABLED;
 | 
			
		||||
	else if (!strncmp(str, "1", 1))
 | 
			
		||||
		watchdog_enabled |= NMI_WATCHDOG_ENABLED;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
__setup("nmi_watchdog=", hardlockup_panic_setup);
 | 
			
		||||
 | 
			
		||||
void arch_touch_nmi_watchdog(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -778,34 +778,45 @@ config DEBUG_SHIRQ
 | 
			
		|||
menu "Debug Lockups and Hangs"
 | 
			
		||||
 | 
			
		||||
config LOCKUP_DETECTOR
 | 
			
		||||
	bool "Detect Hard and Soft Lockups"
 | 
			
		||||
	bool
 | 
			
		||||
 | 
			
		||||
config SOFTLOCKUP_DETECTOR
 | 
			
		||||
	bool "Detect Soft Lockups"
 | 
			
		||||
	depends on DEBUG_KERNEL && !S390
 | 
			
		||||
	select LOCKUP_DETECTOR
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here to enable the kernel to act as a watchdog to detect
 | 
			
		||||
	  hard and soft lockups.
 | 
			
		||||
	  soft lockups.
 | 
			
		||||
 | 
			
		||||
	  Softlockups are bugs that cause the kernel to loop in kernel
 | 
			
		||||
	  mode for more than 20 seconds, without giving other tasks a
 | 
			
		||||
	  chance to run.  The current stack trace is displayed upon
 | 
			
		||||
	  detection and the system will stay locked up.
 | 
			
		||||
 | 
			
		||||
config HARDLOCKUP_DETECTOR_PERF
 | 
			
		||||
	bool
 | 
			
		||||
	select SOFTLOCKUP_DETECTOR
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# arch/ can define HAVE_HARDLOCKUP_DETECTOR_ARCH to provide their own hard
 | 
			
		||||
# lockup detector rather than the perf based detector.
 | 
			
		||||
#
 | 
			
		||||
config HARDLOCKUP_DETECTOR
 | 
			
		||||
	bool "Detect Hard Lockups"
 | 
			
		||||
	depends on DEBUG_KERNEL && !S390
 | 
			
		||||
	depends on HAVE_HARDLOCKUP_DETECTOR_PERF || HAVE_HARDLOCKUP_DETECTOR_ARCH
 | 
			
		||||
	select LOCKUP_DETECTOR
 | 
			
		||||
	select HARDLOCKUP_DETECTOR_PERF if HAVE_HARDLOCKUP_DETECTOR_PERF
 | 
			
		||||
	select HARDLOCKUP_DETECTOR_ARCH if HAVE_HARDLOCKUP_DETECTOR_ARCH
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here to enable the kernel to act as a watchdog to detect
 | 
			
		||||
	  hard lockups.
 | 
			
		||||
 | 
			
		||||
	  Hardlockups are bugs that cause the CPU to loop in kernel mode
 | 
			
		||||
	  for more than 10 seconds, without letting other interrupts have a
 | 
			
		||||
	  chance to run.  The current stack trace is displayed upon detection
 | 
			
		||||
	  and the system will stay locked up.
 | 
			
		||||
 | 
			
		||||
	  The overhead should be minimal.  A periodic hrtimer runs to
 | 
			
		||||
	  generate interrupts and kick the watchdog task every 4 seconds.
 | 
			
		||||
	  An NMI is generated every 10 seconds or so to check for hardlockups.
 | 
			
		||||
 | 
			
		||||
	  The frequency of hrtimer and NMI events and the soft and hard lockup
 | 
			
		||||
	  thresholds can be controlled through the sysctl watchdog_thresh.
 | 
			
		||||
 | 
			
		||||
config HARDLOCKUP_DETECTOR
 | 
			
		||||
	def_bool y
 | 
			
		||||
	depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG
 | 
			
		||||
	depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
 | 
			
		||||
 | 
			
		||||
config BOOTPARAM_HARDLOCKUP_PANIC
 | 
			
		||||
	bool "Panic (Reboot) On Hard Lockups"
 | 
			
		||||
	depends on HARDLOCKUP_DETECTOR
 | 
			
		||||
| 
						 | 
				
			
			@ -826,7 +837,7 @@ config BOOTPARAM_HARDLOCKUP_PANIC_VALUE
 | 
			
		|||
 | 
			
		||||
config BOOTPARAM_SOFTLOCKUP_PANIC
 | 
			
		||||
	bool "Panic (Reboot) On Soft Lockups"
 | 
			
		||||
	depends on LOCKUP_DETECTOR
 | 
			
		||||
	depends on SOFTLOCKUP_DETECTOR
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here to enable the kernel to panic on "soft lockups",
 | 
			
		||||
	  which are bugs that cause the kernel to loop in kernel
 | 
			
		||||
| 
						 | 
				
			
			@ -843,7 +854,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC
 | 
			
		|||
 | 
			
		||||
config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE
 | 
			
		||||
	int
 | 
			
		||||
	depends on LOCKUP_DETECTOR
 | 
			
		||||
	depends on SOFTLOCKUP_DETECTOR
 | 
			
		||||
	range 0 1
 | 
			
		||||
	default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC
 | 
			
		||||
	default 1 if BOOTPARAM_SOFTLOCKUP_PANIC
 | 
			
		||||
| 
						 | 
				
			
			@ -851,7 +862,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE
 | 
			
		|||
config DETECT_HUNG_TASK
 | 
			
		||||
	bool "Detect Hung Tasks"
 | 
			
		||||
	depends on DEBUG_KERNEL
 | 
			
		||||
	default LOCKUP_DETECTOR
 | 
			
		||||
	default SOFTLOCKUP_DETECTOR
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here to enable the kernel to detect "hung tasks",
 | 
			
		||||
	  which are bugs that cause the task to be stuck in
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue