From: Don Zickus <dzickus@redhat.com> Date: Mon, 10 May 2010 16:13:22 -0400 Subject: [misc] nmi_watchdog: add /proc/sys/kernel/nmi_watchdog Message-id: <1273508002-2207-1-git-send-email-dzickus@redhat.com> Patchwork-id: 24925 O-Subject: [RHEL-6 PATCH] [x86] nmi_watchdog: add /proc/sys/kernel/nmi_watchdog Bugzilla: 455323 RH-Acked-by: Jarod Wilson <jarod@redhat.com> https://bugzilla.redhat.com/show_bug.cgi?id=455323 Upstream added this /proc command a long time ago to easily turn nmi_watchdog on and off. RHEL-5 doesn't have this ability and some scripts would like to use this to make it easy to port between RHEL-5, RHEL-6 and upstream. The support was easy enough to add. Tested on x86_64 and i386 both bare-metal and FV guests. Please ACK. Signed-off-by: Don Zickus <dzickus@redhat.com> diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 8a17646..8a948b1 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -30,6 +30,7 @@ unsigned int nmi_watchdog = NMI_NONE; int unknown_nmi_panic; +int nmi_watchdog_enabled; static unsigned int nmi_hz = HZ; extern void show_registers(struct pt_regs *regs); @@ -457,6 +458,35 @@ int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file, return 0; } +/* + * proc handler for /proc/sys/kernel/nmi_watchdog + */ +int proc_nmi_enabled(ctl_table *table, int write, struct file *file, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int old_state; + + nmi_watchdog_enabled = (atomic_read(&nmi_watchdog_active) > 0) ? 1 : 0; + old_state = nmi_watchdog_enabled; + proc_dointvec(table, write, file, buffer, length, ppos); + if (!!old_state == !!nmi_watchdog_enabled) + return 0; + + if (nmi_watchdog_enabled) { + if (nmi_watchdog == NMI_LOCAL_APIC) + enable_lapic_nmi_watchdog(); + else if (nmi_watchdog == NMI_IO_APIC) + acpi_nmi_enable(); + } else { + if (nmi_watchdog == NMI_LOCAL_APIC) + disable_lapic_nmi_watchdog(); + else if (nmi_watchdog == NMI_IO_APIC) + acpi_nmi_disable(); + } + + return 0; +} + #endif EXPORT_SYMBOL(nmi_active); diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 638aa5f..cb6f1ca 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -29,6 +29,7 @@ #include <asm/intel_arch_perfmon.h> int unknown_nmi_panic; +int nmi_watchdog_enabled; int panic_on_unrecovered_nmi; static atomic_t lapic_nmi_reserved = ATOMIC_INIT(0); @@ -506,6 +507,35 @@ int proc_unknown_nmi_panic(struct ctl_table *table, int write, struct file *file return 0; } +/* + * proc handler for /proc/sys/kernel/nmi_enabled + */ +int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int old_state; + + nmi_watchdog_enabled = (atomic_read(&nmi_watchdog_active) > 0) ? 1 : 0; + old_state = nmi_watchdog_enabled; + proc_dointvec(table, write, file, buffer, length, ppos); + if (!!old_state == !!nmi_watchdog_enabled) + return 0; + + if (nmi_watchdog_enabled) { + if (nmi_watchdog == NMI_LOCAL_APIC) + enable_lapic_nmi_watchdog(); + else if (nmi_watchdog == NMI_IO_APIC) + acpi_nmi_enable(); + } else { + if (nmi_watchdog == NMI_LOCAL_APIC) + disable_lapic_nmi_watchdog(); + else if (nmi_watchdog == NMI_IO_APIC) + acpi_nmi_disable(); + } + + return 0; +} + #endif EXPORT_SYMBOL(nmi_active); diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h index 48edc43..9ce2f8d 100644 --- a/include/asm-i386/nmi.h +++ b/include/asm-i386/nmi.h @@ -63,5 +63,6 @@ extern unsigned int nmi_watchdog; #define NMI_INVALID 3 extern int unknown_nmi_panic; +extern int nmi_watchdog_enabled; #endif /* ASM_NMI_H */ diff --git a/include/asm-x86_64/mach-xen/asm/nmi.h b/include/asm-x86_64/mach-xen/asm/nmi.h index cc2b01b..1bb3bc2 100644 --- a/include/asm-x86_64/mach-xen/asm/nmi.h +++ b/include/asm-x86_64/mach-xen/asm/nmi.h @@ -70,6 +70,7 @@ static inline unsigned char get_nmi_reason(void) extern int panic_on_timeout; extern int unknown_nmi_panic; +extern int nmi_watchdog_enabled; void lapic_watchdog_stop(void); int lapic_watchdog_probe(void); diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index 7d82b1a..d696395 100644 --- a/include/asm-x86_64/nmi.h +++ b/include/asm-x86_64/nmi.h @@ -62,6 +62,7 @@ extern void die_nmi(char *str, struct pt_regs *regs); extern int panic_on_timeout; extern int unknown_nmi_panic; +extern int nmi_watchdog_enabled; extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); extern int avail_to_resrv_perfctr_nmi(unsigned int); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index adfb1c9..5b302a0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -165,6 +165,7 @@ enum KERN_HUNG_TASK_CHECK_COUNT=83, KERN_HUNG_TASK_TIMEOUT_SECS=84, KERN_HUNG_TASK_WARNINGS=85, + KERN_NMI_WATCHDOG=86, }; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 494f90b..aa705cf 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -88,6 +88,8 @@ extern int vm_devzero_optimized; #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); +extern int proc_nmi_enabled(ctl_table *, int, struct file *, + void __user *, size_t *, loff_t *); #endif #ifdef CONFIG_DETECT_SOFTLOCKUP @@ -748,6 +750,14 @@ static ctl_table kern_table[] = { .mode = 0644, .proc_handler = &proc_unknown_nmi_panic, }, + { + .ctl_name = KERN_NMI_WATCHDOG, + .procname = "nmi_watchdog", + .data = &nmi_watchdog_enabled, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_nmi_enabled, + }, #endif #if defined(CONFIG_X86) {