diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-14 19:49:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-14 19:49:17 -0400 |
commit | 1dcf58d6e6e6eb7ec10e9abc56887b040205b06f (patch) | |
tree | c03e7a25ef13eea62f1547914a76e5c68f3f4c28 /kernel/watchdog.c | |
parent | 80dcc31fbe55932ac9204daee5f2ebc0c49b6da3 (diff) | |
parent | e4b0db72be2487bae0e3251c22f82c104f7c1cfd (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge first patchbomb from Andrew Morton:
- arch/sh updates
- ocfs2 updates
- kernel/watchdog feature
- about half of mm/
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (122 commits)
Documentation: update arch list in the 'memtest' entry
Kconfig: memtest: update number of test patterns up to 17
arm: add support for memtest
arm64: add support for memtest
memtest: use phys_addr_t for physical addresses
mm: move memtest under mm
mm, hugetlb: abort __get_user_pages if current has been oom killed
mm, mempool: do not allow atomic resizing
memcg: print cgroup information when system panics due to panic_on_oom
mm: numa: remove migrate_ratelimited
mm: fold arch_randomize_brk into ARCH_HAS_ELF_RANDOMIZE
mm: split ET_DYN ASLR from mmap ASLR
s390: redefine randomize_et_dyn for ELF_ET_DYN_BASE
mm: expose arch_mmap_rnd when available
s390: standardize mmap_rnd() usage
powerpc: standardize mmap_rnd() usage
mips: extract logic for mmap_rnd()
arm64: standardize mmap_rnd() usage
x86: standardize mmap_rnd() usage
arm: factor out mmap ASLR into mmap_rnd
...
Diffstat (limited to 'kernel/watchdog.c')
-rw-r--r-- | kernel/watchdog.c | 289 |
1 files changed, 215 insertions, 74 deletions
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 9a056f5bc02c..2316f50b07a4 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
@@ -24,8 +24,33 @@ | |||
24 | #include <linux/kvm_para.h> | 24 | #include <linux/kvm_para.h> |
25 | #include <linux/perf_event.h> | 25 | #include <linux/perf_event.h> |
26 | 26 | ||
27 | int watchdog_user_enabled = 1; | 27 | /* |
28 | * The run state of the lockup detectors is controlled by the content of the | ||
29 | * 'watchdog_enabled' variable. Each lockup detector has its dedicated bit - | ||
30 | * bit 0 for the hard lockup detector and bit 1 for the soft lockup detector. | ||
31 | * | ||
32 | * 'watchdog_user_enabled', 'nmi_watchdog_enabled' and 'soft_watchdog_enabled' | ||
33 | * are variables that are only used as an 'interface' between the parameters | ||
34 | * in /proc/sys/kernel and the internal state bits in 'watchdog_enabled'. The | ||
35 | * 'watchdog_thresh' variable is handled differently because its value is not | ||
36 | * boolean, and the lockup detectors are 'suspended' while 'watchdog_thresh' | ||
37 | * is equal zero. | ||
38 | */ | ||
39 | #define NMI_WATCHDOG_ENABLED_BIT 0 | ||
40 | #define SOFT_WATCHDOG_ENABLED_BIT 1 | ||
41 | #define NMI_WATCHDOG_ENABLED (1 << NMI_WATCHDOG_ENABLED_BIT) | ||
42 | #define SOFT_WATCHDOG_ENABLED (1 << SOFT_WATCHDOG_ENABLED_BIT) | ||
43 | |||
44 | #ifdef CONFIG_HARDLOCKUP_DETECTOR | ||
45 | static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED; | ||
46 | #else | ||
47 | static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED; | ||
48 | #endif | ||
49 | int __read_mostly nmi_watchdog_enabled; | ||
50 | int __read_mostly soft_watchdog_enabled; | ||
51 | int __read_mostly watchdog_user_enabled; | ||
28 | int __read_mostly watchdog_thresh = 10; | 52 | int __read_mostly watchdog_thresh = 10; |
53 | |||
29 | #ifdef CONFIG_SMP | 54 | #ifdef CONFIG_SMP |
30 | int __read_mostly sysctl_softlockup_all_cpu_backtrace; | 55 | int __read_mostly sysctl_softlockup_all_cpu_backtrace; |
31 | #else | 56 | #else |
@@ -58,8 +83,6 @@ static unsigned long soft_lockup_nmi_warn; | |||
58 | #ifdef CONFIG_HARDLOCKUP_DETECTOR | 83 | #ifdef CONFIG_HARDLOCKUP_DETECTOR |
59 | static int hardlockup_panic = | 84 | static int hardlockup_panic = |
60 | CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE; | 85 | CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE; |
61 | |||
62 | static bool hardlockup_detector_enabled = true; | ||
63 | /* | 86 | /* |
64 | * We may not want to enable hard lockup detection by default in all cases, | 87 | * We may not want to enable hard lockup detection by default in all cases, |
65 | * for example when running the kernel as a guest on a hypervisor. In these | 88 | * for example when running the kernel as a guest on a hypervisor. In these |
@@ -68,14 +91,9 @@ static bool hardlockup_detector_enabled = true; | |||
68 | * kernel command line parameters are parsed, because otherwise it is not | 91 | * kernel command line parameters are parsed, because otherwise it is not |
69 | * possible to override this in hardlockup_panic_setup(). | 92 | * possible to override this in hardlockup_panic_setup(). |
70 | */ | 93 | */ |
71 | void watchdog_enable_hardlockup_detector(bool val) | 94 | void hardlockup_detector_disable(void) |
72 | { | ||
73 | hardlockup_detector_enabled = val; | ||
74 | } | ||
75 | |||
76 | bool watchdog_hardlockup_detector_is_enabled(void) | ||
77 | { | 95 | { |
78 | return hardlockup_detector_enabled; | 96 | watchdog_enabled &= ~NMI_WATCHDOG_ENABLED; |
79 | } | 97 | } |
80 | 98 | ||
81 | static int __init hardlockup_panic_setup(char *str) | 99 | static int __init hardlockup_panic_setup(char *str) |
@@ -85,15 +103,9 @@ static int __init hardlockup_panic_setup(char *str) | |||
85 | else if (!strncmp(str, "nopanic", 7)) | 103 | else if (!strncmp(str, "nopanic", 7)) |
86 | hardlockup_panic = 0; | 104 | hardlockup_panic = 0; |
87 | else if (!strncmp(str, "0", 1)) | 105 | else if (!strncmp(str, "0", 1)) |
88 | watchdog_user_enabled = 0; | 106 | watchdog_enabled &= ~NMI_WATCHDOG_ENABLED; |
89 | else if (!strncmp(str, "1", 1) || !strncmp(str, "2", 1)) { | 107 | else if (!strncmp(str, "1", 1)) |
90 | /* | 108 | watchdog_enabled |= NMI_WATCHDOG_ENABLED; |
91 | * Setting 'nmi_watchdog=1' or 'nmi_watchdog=2' (legacy option) | ||
92 | * has the same effect. | ||
93 | */ | ||
94 | watchdog_user_enabled = 1; | ||
95 | watchdog_enable_hardlockup_detector(true); | ||
96 | } | ||
97 | return 1; | 109 | return 1; |
98 | } | 110 | } |
99 | __setup("nmi_watchdog=", hardlockup_panic_setup); | 111 | __setup("nmi_watchdog=", hardlockup_panic_setup); |
@@ -112,19 +124,18 @@ __setup("softlockup_panic=", softlockup_panic_setup); | |||
112 | 124 | ||
113 | static int __init nowatchdog_setup(char *str) | 125 | static int __init nowatchdog_setup(char *str) |
114 | { | 126 | { |
115 | watchdog_user_enabled = 0; | 127 | watchdog_enabled = 0; |
116 | return 1; | 128 | return 1; |
117 | } | 129 | } |
118 | __setup("nowatchdog", nowatchdog_setup); | 130 | __setup("nowatchdog", nowatchdog_setup); |
119 | 131 | ||
120 | /* deprecated */ | ||
121 | static int __init nosoftlockup_setup(char *str) | 132 | static int __init nosoftlockup_setup(char *str) |
122 | { | 133 | { |
123 | watchdog_user_enabled = 0; | 134 | watchdog_enabled &= ~SOFT_WATCHDOG_ENABLED; |
124 | return 1; | 135 | return 1; |
125 | } | 136 | } |
126 | __setup("nosoftlockup", nosoftlockup_setup); | 137 | __setup("nosoftlockup", nosoftlockup_setup); |
127 | /* */ | 138 | |
128 | #ifdef CONFIG_SMP | 139 | #ifdef CONFIG_SMP |
129 | static int __init softlockup_all_cpu_backtrace_setup(char *str) | 140 | static int __init softlockup_all_cpu_backtrace_setup(char *str) |
130 | { | 141 | { |
@@ -239,10 +250,11 @@ static int is_softlockup(unsigned long touch_ts) | |||
239 | { | 250 | { |
240 | unsigned long now = get_timestamp(); | 251 | unsigned long now = get_timestamp(); |
241 | 252 | ||
242 | /* Warn about unreasonable delays: */ | 253 | if (watchdog_enabled & SOFT_WATCHDOG_ENABLED) { |
243 | if (time_after(now, touch_ts + get_softlockup_thresh())) | 254 | /* Warn about unreasonable delays. */ |
244 | return now - touch_ts; | 255 | if (time_after(now, touch_ts + get_softlockup_thresh())) |
245 | 256 | return now - touch_ts; | |
257 | } | ||
246 | return 0; | 258 | return 0; |
247 | } | 259 | } |
248 | 260 | ||
@@ -477,6 +489,21 @@ static void watchdog(unsigned int cpu) | |||
477 | __this_cpu_write(soft_lockup_hrtimer_cnt, | 489 | __this_cpu_write(soft_lockup_hrtimer_cnt, |
478 | __this_cpu_read(hrtimer_interrupts)); | 490 | __this_cpu_read(hrtimer_interrupts)); |
479 | __touch_watchdog(); | 491 | __touch_watchdog(); |
492 | |||
493 | /* | ||
494 | * watchdog_nmi_enable() clears the NMI_WATCHDOG_ENABLED bit in the | ||
495 | * failure path. Check for failures that can occur asynchronously - | ||
496 | * for example, when CPUs are on-lined - and shut down the hardware | ||
497 | * perf event on each CPU accordingly. | ||
498 | * | ||
499 | * The only non-obvious place this bit can be cleared is through | ||
500 | * watchdog_nmi_enable(), so a pr_info() is placed there. Placing a | ||
501 | * pr_info here would be too noisy as it would result in a message | ||
502 | * every few seconds if the hardlockup was disabled but the softlockup | ||
503 | * enabled. | ||
504 | */ | ||
505 | if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) | ||
506 | watchdog_nmi_disable(cpu); | ||
480 | } | 507 | } |
481 | 508 | ||
482 | #ifdef CONFIG_HARDLOCKUP_DETECTOR | 509 | #ifdef CONFIG_HARDLOCKUP_DETECTOR |
@@ -492,14 +519,9 @@ static int watchdog_nmi_enable(unsigned int cpu) | |||
492 | struct perf_event_attr *wd_attr; | 519 | struct perf_event_attr *wd_attr; |
493 | struct perf_event *event = per_cpu(watchdog_ev, cpu); | 520 | struct perf_event *event = per_cpu(watchdog_ev, cpu); |
494 | 521 | ||
495 | /* | 522 | /* nothing to do if the hard lockup detector is disabled */ |
496 | * Some kernels need to default hard lockup detection to | 523 | if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) |
497 | * 'disabled', for example a guest on a hypervisor. | 524 | goto out; |
498 | */ | ||
499 | if (!watchdog_hardlockup_detector_is_enabled()) { | ||
500 | event = ERR_PTR(-ENOENT); | ||
501 | goto handle_err; | ||
502 | } | ||
503 | 525 | ||
504 | /* is it already setup and enabled? */ | 526 | /* is it already setup and enabled? */ |
505 | if (event && event->state > PERF_EVENT_STATE_OFF) | 527 | if (event && event->state > PERF_EVENT_STATE_OFF) |
@@ -515,7 +537,6 @@ static int watchdog_nmi_enable(unsigned int cpu) | |||
515 | /* Try to register using hardware perf events */ | 537 | /* Try to register using hardware perf events */ |
516 | event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); | 538 | event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); |
517 | 539 | ||
518 | handle_err: | ||
519 | /* save cpu0 error for future comparision */ | 540 | /* save cpu0 error for future comparision */ |
520 | if (cpu == 0 && IS_ERR(event)) | 541 | if (cpu == 0 && IS_ERR(event)) |
521 | cpu0_err = PTR_ERR(event); | 542 | cpu0_err = PTR_ERR(event); |
@@ -527,6 +548,18 @@ handle_err: | |||
527 | goto out_save; | 548 | goto out_save; |
528 | } | 549 | } |
529 | 550 | ||
551 | /* | ||
552 | * Disable the hard lockup detector if _any_ CPU fails to set up | ||
553 | * set up the hardware perf event. The watchdog() function checks | ||
554 | * the NMI_WATCHDOG_ENABLED bit periodically. | ||
555 | * | ||
556 | * The barriers are for syncing up watchdog_enabled across all the | ||
557 | * cpus, as clear_bit() does not use barriers. | ||
558 | */ | ||
559 | smp_mb__before_atomic(); | ||
560 | clear_bit(NMI_WATCHDOG_ENABLED_BIT, &watchdog_enabled); | ||
561 | smp_mb__after_atomic(); | ||
562 | |||
530 | /* skip displaying the same error again */ | 563 | /* skip displaying the same error again */ |
531 | if (cpu > 0 && (PTR_ERR(event) == cpu0_err)) | 564 | if (cpu > 0 && (PTR_ERR(event) == cpu0_err)) |
532 | return PTR_ERR(event); | 565 | return PTR_ERR(event); |
@@ -540,6 +573,9 @@ handle_err: | |||
540 | else | 573 | else |
541 | pr_err("disabled (cpu%i): unable to create perf event: %ld\n", | 574 | pr_err("disabled (cpu%i): unable to create perf event: %ld\n", |
542 | cpu, PTR_ERR(event)); | 575 | cpu, PTR_ERR(event)); |
576 | |||
577 | pr_info("Shutting down hard lockup detector on all cpus\n"); | ||
578 | |||
543 | return PTR_ERR(event); | 579 | return PTR_ERR(event); |
544 | 580 | ||
545 | /* success path */ | 581 | /* success path */ |
@@ -628,7 +664,7 @@ static void restart_watchdog_hrtimer(void *info) | |||
628 | HRTIMER_MODE_REL_PINNED); | 664 | HRTIMER_MODE_REL_PINNED); |
629 | } | 665 | } |
630 | 666 | ||
631 | static void update_timers(int cpu) | 667 | static void update_watchdog(int cpu) |
632 | { | 668 | { |
633 | /* | 669 | /* |
634 | * Make sure that perf event counter will adopt to a new | 670 | * Make sure that perf event counter will adopt to a new |
@@ -643,17 +679,17 @@ static void update_timers(int cpu) | |||
643 | watchdog_nmi_enable(cpu); | 679 | watchdog_nmi_enable(cpu); |
644 | } | 680 | } |
645 | 681 | ||
646 | static void update_timers_all_cpus(void) | 682 | static void update_watchdog_all_cpus(void) |
647 | { | 683 | { |
648 | int cpu; | 684 | int cpu; |
649 | 685 | ||
650 | get_online_cpus(); | 686 | get_online_cpus(); |
651 | for_each_online_cpu(cpu) | 687 | for_each_online_cpu(cpu) |
652 | update_timers(cpu); | 688 | update_watchdog(cpu); |
653 | put_online_cpus(); | 689 | put_online_cpus(); |
654 | } | 690 | } |
655 | 691 | ||
656 | static int watchdog_enable_all_cpus(bool sample_period_changed) | 692 | static int watchdog_enable_all_cpus(void) |
657 | { | 693 | { |
658 | int err = 0; | 694 | int err = 0; |
659 | 695 | ||
@@ -663,8 +699,12 @@ static int watchdog_enable_all_cpus(bool sample_period_changed) | |||
663 | pr_err("Failed to create watchdog threads, disabled\n"); | 699 | pr_err("Failed to create watchdog threads, disabled\n"); |
664 | else | 700 | else |
665 | watchdog_running = 1; | 701 | watchdog_running = 1; |
666 | } else if (sample_period_changed) { | 702 | } else { |
667 | update_timers_all_cpus(); | 703 | /* |
704 | * Enable/disable the lockup detectors or | ||
705 | * change the sample period 'on the fly'. | ||
706 | */ | ||
707 | update_watchdog_all_cpus(); | ||
668 | } | 708 | } |
669 | 709 | ||
670 | return err; | 710 | return err; |
@@ -682,48 +722,149 @@ static void watchdog_disable_all_cpus(void) | |||
682 | } | 722 | } |
683 | 723 | ||
684 | /* | 724 | /* |
685 | * proc handler for /proc/sys/kernel/nmi_watchdog,watchdog_thresh | 725 | * Update the run state of the lockup detectors. |
726 | */ | ||
727 | static int proc_watchdog_update(void) | ||
728 | { | ||
729 | int err = 0; | ||
730 | |||
731 | /* | ||
732 | * Watchdog threads won't be started if they are already active. | ||
733 | * The 'watchdog_running' variable in watchdog_*_all_cpus() takes | ||
734 | * care of this. If those threads are already active, the sample | ||
735 | * period will be updated and the lockup detectors will be enabled | ||
736 | * or disabled 'on the fly'. | ||
737 | */ | ||
738 | if (watchdog_enabled && watchdog_thresh) | ||
739 | err = watchdog_enable_all_cpus(); | ||
740 | else | ||
741 | watchdog_disable_all_cpus(); | ||
742 | |||
743 | return err; | ||
744 | |||
745 | } | ||
746 | |||
747 | static DEFINE_MUTEX(watchdog_proc_mutex); | ||
748 | |||
749 | /* | ||
750 | * common function for watchdog, nmi_watchdog and soft_watchdog parameter | ||
751 | * | ||
752 | * caller | table->data points to | 'which' contains the flag(s) | ||
753 | * -------------------|-----------------------|----------------------------- | ||
754 | * proc_watchdog | watchdog_user_enabled | NMI_WATCHDOG_ENABLED or'ed | ||
755 | * | | with SOFT_WATCHDOG_ENABLED | ||
756 | * -------------------|-----------------------|----------------------------- | ||
757 | * proc_nmi_watchdog | nmi_watchdog_enabled | NMI_WATCHDOG_ENABLED | ||
758 | * -------------------|-----------------------|----------------------------- | ||
759 | * proc_soft_watchdog | soft_watchdog_enabled | SOFT_WATCHDOG_ENABLED | ||
760 | */ | ||
761 | static int proc_watchdog_common(int which, struct ctl_table *table, int write, | ||
762 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
763 | { | ||
764 | int err, old, new; | ||
765 | int *watchdog_param = (int *)table->data; | ||
766 | |||
767 | mutex_lock(&watchdog_proc_mutex); | ||
768 | |||
769 | /* | ||
770 | * If the parameter is being read return the state of the corresponding | ||
771 | * bit(s) in 'watchdog_enabled', else update 'watchdog_enabled' and the | ||
772 | * run state of the lockup detectors. | ||
773 | */ | ||
774 | if (!write) { | ||
775 | *watchdog_param = (watchdog_enabled & which) != 0; | ||
776 | err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
777 | } else { | ||
778 | err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
779 | if (err) | ||
780 | goto out; | ||
781 | |||
782 | /* | ||
783 | * There is a race window between fetching the current value | ||
784 | * from 'watchdog_enabled' and storing the new value. During | ||
785 | * this race window, watchdog_nmi_enable() can sneak in and | ||
786 | * clear the NMI_WATCHDOG_ENABLED bit in 'watchdog_enabled'. | ||
787 | * The 'cmpxchg' detects this race and the loop retries. | ||
788 | */ | ||
789 | do { | ||
790 | old = watchdog_enabled; | ||
791 | /* | ||
792 | * If the parameter value is not zero set the | ||
793 | * corresponding bit(s), else clear it(them). | ||
794 | */ | ||
795 | if (*watchdog_param) | ||
796 | new = old | which; | ||
797 | else | ||
798 | new = old & ~which; | ||
799 | } while (cmpxchg(&watchdog_enabled, old, new) != old); | ||
800 | |||
801 | /* | ||
802 | * Update the run state of the lockup detectors. | ||
803 | * Restore 'watchdog_enabled' on failure. | ||
804 | */ | ||
805 | err = proc_watchdog_update(); | ||
806 | if (err) | ||
807 | watchdog_enabled = old; | ||
808 | } | ||
809 | out: | ||
810 | mutex_unlock(&watchdog_proc_mutex); | ||
811 | return err; | ||
812 | } | ||
813 | |||
814 | /* | ||
815 | * /proc/sys/kernel/watchdog | ||
816 | */ | ||
817 | int proc_watchdog(struct ctl_table *table, int write, | ||
818 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
819 | { | ||
820 | return proc_watchdog_common(NMI_WATCHDOG_ENABLED|SOFT_WATCHDOG_ENABLED, | ||
821 | table, write, buffer, lenp, ppos); | ||
822 | } | ||
823 | |||
824 | /* | ||
825 | * /proc/sys/kernel/nmi_watchdog | ||
686 | */ | 826 | */ |
827 | int proc_nmi_watchdog(struct ctl_table *table, int write, | ||
828 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
829 | { | ||
830 | return proc_watchdog_common(NMI_WATCHDOG_ENABLED, | ||
831 | table, write, buffer, lenp, ppos); | ||
832 | } | ||
833 | |||
834 | /* | ||
835 | * /proc/sys/kernel/soft_watchdog | ||
836 | */ | ||
837 | int proc_soft_watchdog(struct ctl_table *table, int write, | ||
838 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
839 | { | ||
840 | return proc_watchdog_common(SOFT_WATCHDOG_ENABLED, | ||
841 | table, write, buffer, lenp, ppos); | ||
842 | } | ||
687 | 843 | ||
688 | int proc_dowatchdog(struct ctl_table *table, int write, | 844 | /* |
689 | void __user *buffer, size_t *lenp, loff_t *ppos) | 845 | * /proc/sys/kernel/watchdog_thresh |
846 | */ | ||
847 | int proc_watchdog_thresh(struct ctl_table *table, int write, | ||
848 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
690 | { | 849 | { |
691 | int err, old_thresh, old_enabled; | 850 | int err, old; |
692 | bool old_hardlockup; | ||
693 | static DEFINE_MUTEX(watchdog_proc_mutex); | ||
694 | 851 | ||
695 | mutex_lock(&watchdog_proc_mutex); | 852 | mutex_lock(&watchdog_proc_mutex); |
696 | old_thresh = ACCESS_ONCE(watchdog_thresh); | ||
697 | old_enabled = ACCESS_ONCE(watchdog_user_enabled); | ||
698 | old_hardlockup = watchdog_hardlockup_detector_is_enabled(); | ||
699 | 853 | ||
854 | old = ACCESS_ONCE(watchdog_thresh); | ||
700 | err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | 855 | err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); |
856 | |||
701 | if (err || !write) | 857 | if (err || !write) |
702 | goto out; | 858 | goto out; |
703 | 859 | ||
704 | set_sample_period(); | ||
705 | /* | 860 | /* |
706 | * Watchdog threads shouldn't be enabled if they are | 861 | * Update the sample period. |
707 | * disabled. The 'watchdog_running' variable check in | 862 | * Restore 'watchdog_thresh' on failure. |
708 | * watchdog_*_all_cpus() function takes care of this. | ||
709 | */ | 863 | */ |
710 | if (watchdog_user_enabled && watchdog_thresh) { | 864 | set_sample_period(); |
711 | /* | 865 | err = proc_watchdog_update(); |
712 | * Prevent a change in watchdog_thresh accidentally overriding | 866 | if (err) |
713 | * the enablement of the hardlockup detector. | 867 | watchdog_thresh = old; |
714 | */ | ||
715 | if (watchdog_user_enabled != old_enabled) | ||
716 | watchdog_enable_hardlockup_detector(true); | ||
717 | err = watchdog_enable_all_cpus(old_thresh != watchdog_thresh); | ||
718 | } else | ||
719 | watchdog_disable_all_cpus(); | ||
720 | |||
721 | /* Restore old values on failure */ | ||
722 | if (err) { | ||
723 | watchdog_thresh = old_thresh; | ||
724 | watchdog_user_enabled = old_enabled; | ||
725 | watchdog_enable_hardlockup_detector(old_hardlockup); | ||
726 | } | ||
727 | out: | 868 | out: |
728 | mutex_unlock(&watchdog_proc_mutex); | 869 | mutex_unlock(&watchdog_proc_mutex); |
729 | return err; | 870 | return err; |
@@ -734,6 +875,6 @@ void __init lockup_detector_init(void) | |||
734 | { | 875 | { |
735 | set_sample_period(); | 876 | set_sample_period(); |
736 | 877 | ||
737 | if (watchdog_user_enabled) | 878 | if (watchdog_enabled) |
738 | watchdog_enable_all_cpus(false); | 879 | watchdog_enable_all_cpus(); |
739 | } | 880 | } |