diff options
| author | Don Zickus <dzickus@redhat.com> | 2006-09-26 04:52:27 -0400 |
|---|---|---|
| committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:27 -0400 |
| commit | 407984f1af259b31957c7c05075a454a751bb801 (patch) | |
| tree | 1e9318b4255957c27a4dbacd84711604bf789393 | |
| parent | 2fbe7b25c8edaf2d10e6c1a4cc9f8afe714c4764 (diff) | |
[PATCH] x86: Add abilty to enable/disable nmi watchdog with sysctl
Adds a new /proc/sys/kernel/nmi call that will enable/disable the nmi
watchdog.
Signed-off-by: Don Zickus <dzickus@redhat.com>
Signed-off-by: Andi Kleen <ak@suse.de>
| -rw-r--r-- | arch/i386/kernel/nmi.c | 52 | ||||
| -rw-r--r-- | arch/x86_64/kernel/nmi.c | 48 | ||||
| -rw-r--r-- | include/asm-i386/nmi.h | 1 | ||||
| -rw-r--r-- | include/asm-x86_64/nmi.h | 1 | ||||
| -rw-r--r-- | include/linux/sysctl.h | 1 | ||||
| -rw-r--r-- | kernel/sysctl.c | 11 |
6 files changed, 114 insertions, 0 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index acd3fdea2a21..28065d0b71a9 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c | |||
| @@ -846,6 +846,58 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) | |||
| 846 | return 0; | 846 | return 0; |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | /* | ||
| 850 | * proc handler for /proc/sys/kernel/nmi_watchdog | ||
| 851 | */ | ||
| 852 | int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, | ||
| 853 | void __user *buffer, size_t *length, loff_t *ppos) | ||
| 854 | { | ||
| 855 | int old_state; | ||
| 856 | |||
| 857 | nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0; | ||
| 858 | old_state = nmi_watchdog_enabled; | ||
| 859 | proc_dointvec(table, write, file, buffer, length, ppos); | ||
| 860 | if (!!old_state == !!nmi_watchdog_enabled) | ||
| 861 | return 0; | ||
| 862 | |||
| 863 | if (atomic_read(&nmi_active) < 0) { | ||
| 864 | printk(KERN_WARNING "NMI watchdog is permanently disabled\n"); | ||
| 865 | return -EINVAL; | ||
| 866 | } | ||
| 867 | |||
| 868 | if (nmi_watchdog == NMI_DEFAULT) { | ||
| 869 | if (nmi_known_cpu() > 0) | ||
| 870 | nmi_watchdog = NMI_LOCAL_APIC; | ||
| 871 | else | ||
| 872 | nmi_watchdog = NMI_IO_APIC; | ||
| 873 | } | ||
| 874 | |||
| 875 | if (nmi_watchdog == NMI_LOCAL_APIC) | ||
| 876 | { | ||
| 877 | if (nmi_watchdog_enabled) | ||
| 878 | enable_lapic_nmi_watchdog(); | ||
| 879 | else | ||
| 880 | disable_lapic_nmi_watchdog(); | ||
| 881 | } else if (nmi_watchdog == NMI_IO_APIC) { | ||
| 882 | /* FIXME | ||
| 883 | * for some reason these functions don't work | ||
| 884 | */ | ||
| 885 | printk("Can not enable/disable NMI on IO APIC\n"); | ||
| 886 | return -EINVAL; | ||
| 887 | #if 0 | ||
| 888 | if (nmi_watchdog_enabled) | ||
| 889 | enable_timer_nmi_watchdog(); | ||
| 890 | else | ||
| 891 | disable_timer_nmi_watchdog(); | ||
| 892 | #endif | ||
| 893 | } else { | ||
| 894 | printk( KERN_WARNING | ||
| 895 | "NMI watchdog doesn't know what hardware to touch\n"); | ||
| 896 | return -EIO; | ||
| 897 | } | ||
| 898 | return 0; | ||
| 899 | } | ||
| 900 | |||
| 849 | #endif | 901 | #endif |
| 850 | 902 | ||
| 851 | EXPORT_SYMBOL(nmi_active); | 903 | EXPORT_SYMBOL(nmi_active); |
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 9d175dcf3a2d..3a17411a9a19 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c | |||
| @@ -750,6 +750,54 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) | |||
| 750 | return 0; | 750 | return 0; |
| 751 | } | 751 | } |
| 752 | 752 | ||
| 753 | /* | ||
| 754 | * proc handler for /proc/sys/kernel/nmi | ||
| 755 | */ | ||
| 756 | int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, | ||
| 757 | void __user *buffer, size_t *length, loff_t *ppos) | ||
| 758 | { | ||
| 759 | int old_state; | ||
| 760 | |||
| 761 | nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0; | ||
| 762 | old_state = nmi_watchdog_enabled; | ||
| 763 | proc_dointvec(table, write, file, buffer, length, ppos); | ||
| 764 | if (!!old_state == !!nmi_watchdog_enabled) | ||
| 765 | return 0; | ||
| 766 | |||
| 767 | if (atomic_read(&nmi_active) < 0) { | ||
| 768 | printk( KERN_WARNING "NMI watchdog is permanently disabled\n"); | ||
| 769 | return -EINVAL; | ||
| 770 | } | ||
| 771 | |||
| 772 | /* if nmi_watchdog is not set yet, then set it */ | ||
| 773 | nmi_watchdog_default(); | ||
| 774 | |||
| 775 | if (nmi_watchdog == NMI_LOCAL_APIC) | ||
| 776 | { | ||
| 777 | if (nmi_watchdog_enabled) | ||
| 778 | enable_lapic_nmi_watchdog(); | ||
| 779 | else | ||
| 780 | disable_lapic_nmi_watchdog(); | ||
| 781 | } else if (nmi_watchdog == NMI_IO_APIC) { | ||
| 782 | /* FIXME | ||
| 783 | * for some reason these functions don't work | ||
| 784 | */ | ||
| 785 | printk("Can not enable/disable NMI on IO APIC\n"); | ||
| 786 | return -EIO; | ||
| 787 | #if 0 | ||
| 788 | if (nmi_watchdog_enabled) | ||
| 789 | enable_timer_nmi_watchdog(); | ||
| 790 | else | ||
| 791 | disable_timer_nmi_watchdog(); | ||
| 792 | #endif | ||
| 793 | } else { | ||
| 794 | printk(KERN_WARNING | ||
| 795 | "NMI watchdog doesn't know what hardware to touch\n"); | ||
| 796 | return -EIO; | ||
| 797 | } | ||
| 798 | return 0; | ||
| 799 | } | ||
| 800 | |||
| 753 | #endif | 801 | #endif |
| 754 | 802 | ||
| 755 | EXPORT_SYMBOL(nmi_active); | 803 | EXPORT_SYMBOL(nmi_active); |
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h index 34d6bf063b6e..13b5d8311bf7 100644 --- a/include/asm-i386/nmi.h +++ b/include/asm-i386/nmi.h | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | */ | 14 | */ |
| 15 | int do_nmi_callback(struct pt_regs *regs, int cpu); | 15 | int do_nmi_callback(struct pt_regs *regs, int cpu); |
| 16 | 16 | ||
| 17 | extern int nmi_watchdog_enabled; | ||
| 17 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); | 18 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); |
| 18 | extern int avail_to_resrv_perfctr_nmi(unsigned int); | 19 | extern int avail_to_resrv_perfctr_nmi(unsigned int); |
| 19 | extern int reserve_perfctr_nmi(unsigned int); | 20 | extern int reserve_perfctr_nmi(unsigned int); |
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index 8818c39d34e0..2c23b0df87d2 100644 --- a/include/asm-x86_64/nmi.h +++ b/include/asm-x86_64/nmi.h | |||
| @@ -43,6 +43,7 @@ extern void die_nmi(char *str, struct pt_regs *regs); | |||
| 43 | 43 | ||
| 44 | extern int panic_on_timeout; | 44 | extern int panic_on_timeout; |
| 45 | extern int unknown_nmi_panic; | 45 | extern int unknown_nmi_panic; |
| 46 | extern int nmi_watchdog_enabled; | ||
| 46 | 47 | ||
| 47 | extern int check_nmi_watchdog(void); | 48 | extern int check_nmi_watchdog(void); |
| 48 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); | 49 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); |
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 736ed917a4f8..ecb79ba52ae1 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
| @@ -150,6 +150,7 @@ enum | |||
| 150 | KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */ | 150 | KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */ |
| 151 | KERN_COMPAT_LOG=73, /* int: print compat layer messages */ | 151 | KERN_COMPAT_LOG=73, /* int: print compat layer messages */ |
| 152 | KERN_MAX_LOCK_DEPTH=74, | 152 | KERN_MAX_LOCK_DEPTH=74, |
| 153 | KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */ | ||
| 153 | }; | 154 | }; |
| 154 | 155 | ||
| 155 | 156 | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 83f168361624..040de6bd74dd 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -76,6 +76,9 @@ extern int compat_log; | |||
| 76 | 76 | ||
| 77 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) | 77 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) |
| 78 | int unknown_nmi_panic; | 78 | int unknown_nmi_panic; |
| 79 | int nmi_watchdog_enabled; | ||
| 80 | extern int proc_nmi_enabled(struct ctl_table *, int , struct file *, | ||
| 81 | void __user *, size_t *, loff_t *); | ||
| 79 | #endif | 82 | #endif |
| 80 | 83 | ||
| 81 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ | 84 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ |
| @@ -628,6 +631,14 @@ static ctl_table kern_table[] = { | |||
| 628 | .mode = 0644, | 631 | .mode = 0644, |
| 629 | .proc_handler = &proc_dointvec, | 632 | .proc_handler = &proc_dointvec, |
| 630 | }, | 633 | }, |
| 634 | { | ||
| 635 | .ctl_name = KERN_NMI_WATCHDOG, | ||
| 636 | .procname = "nmi_watchdog", | ||
| 637 | .data = &nmi_watchdog_enabled, | ||
| 638 | .maxlen = sizeof (int), | ||
| 639 | .mode = 0644, | ||
| 640 | .proc_handler = &proc_nmi_enabled, | ||
| 641 | }, | ||
| 631 | #endif | 642 | #endif |
| 632 | #if defined(CONFIG_X86) | 643 | #if defined(CONFIG_X86) |
| 633 | { | 644 | { |
