diff options
author | Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> | 2011-06-17 04:40:36 -0400 |
---|---|---|
committer | Borislav Petkov <borislav.petkov@amd.com> | 2011-09-14 09:50:15 -0400 |
commit | 9aaef96f61d93062556d34e15731f7d5869dd82e (patch) | |
tree | 211c712b62e3ba4e8444b02f59d91f8e61aca23c /arch/x86 | |
parent | b6fd41e29dea9c6753b1843a77e50433e6123bcb (diff) |
x86, mce: Do not call del_timer_sync() in IRQ context
del_timer_sync() can cause a deadlock when called in interrupt context.
It is used with on_each_cpu() in some parts for sysfs files like bank*,
check_interval, cmci_disabled and ignore_ce.
However, use of on_each_cpu() results in calling the function passed
as the argument in interrupt context. This causes a flood of nested
warnings from del_timer_sync() (it runs on each CPU) caused even by a
simple file access like:
$ echo 300 > /sys/devices/system/machinecheck/machinecheck0/check_interval
Fortunately, these MCE-specific files are rarely used and AFAIK only few
MCE geeks experience this warning.
To remove the warning, move timer deletion outside of the interrupt
context.
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 08363b04212..5b5cceec94c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -1140,6 +1140,15 @@ static void mce_start_timer(unsigned long data) | |||
1140 | add_timer_on(t, smp_processor_id()); | 1140 | add_timer_on(t, smp_processor_id()); |
1141 | } | 1141 | } |
1142 | 1142 | ||
1143 | /* Must not be called in IRQ context where del_timer_sync() can deadlock */ | ||
1144 | static void mce_timer_delete_all(void) | ||
1145 | { | ||
1146 | int cpu; | ||
1147 | |||
1148 | for_each_online_cpu(cpu) | ||
1149 | del_timer_sync(&per_cpu(mce_timer, cpu)); | ||
1150 | } | ||
1151 | |||
1143 | static void mce_do_trigger(struct work_struct *work) | 1152 | static void mce_do_trigger(struct work_struct *work) |
1144 | { | 1153 | { |
1145 | call_usermodehelper(mce_helper, mce_helper_argv, NULL, UMH_NO_WAIT); | 1154 | call_usermodehelper(mce_helper, mce_helper_argv, NULL, UMH_NO_WAIT); |
@@ -1750,7 +1759,6 @@ static struct syscore_ops mce_syscore_ops = { | |||
1750 | 1759 | ||
1751 | static void mce_cpu_restart(void *data) | 1760 | static void mce_cpu_restart(void *data) |
1752 | { | 1761 | { |
1753 | del_timer_sync(&__get_cpu_var(mce_timer)); | ||
1754 | if (!mce_available(__this_cpu_ptr(&cpu_info))) | 1762 | if (!mce_available(__this_cpu_ptr(&cpu_info))) |
1755 | return; | 1763 | return; |
1756 | __mcheck_cpu_init_generic(); | 1764 | __mcheck_cpu_init_generic(); |
@@ -1760,16 +1768,15 @@ static void mce_cpu_restart(void *data) | |||
1760 | /* Reinit MCEs after user configuration changes */ | 1768 | /* Reinit MCEs after user configuration changes */ |
1761 | static void mce_restart(void) | 1769 | static void mce_restart(void) |
1762 | { | 1770 | { |
1771 | mce_timer_delete_all(); | ||
1763 | on_each_cpu(mce_cpu_restart, NULL, 1); | 1772 | on_each_cpu(mce_cpu_restart, NULL, 1); |
1764 | } | 1773 | } |
1765 | 1774 | ||
1766 | /* Toggle features for corrected errors */ | 1775 | /* Toggle features for corrected errors */ |
1767 | static void mce_disable_ce(void *all) | 1776 | static void mce_disable_cmci(void *data) |
1768 | { | 1777 | { |
1769 | if (!mce_available(__this_cpu_ptr(&cpu_info))) | 1778 | if (!mce_available(__this_cpu_ptr(&cpu_info))) |
1770 | return; | 1779 | return; |
1771 | if (all) | ||
1772 | del_timer_sync(&__get_cpu_var(mce_timer)); | ||
1773 | cmci_clear(); | 1780 | cmci_clear(); |
1774 | } | 1781 | } |
1775 | 1782 | ||
@@ -1852,7 +1859,8 @@ static ssize_t set_ignore_ce(struct sys_device *s, | |||
1852 | if (mce_ignore_ce ^ !!new) { | 1859 | if (mce_ignore_ce ^ !!new) { |
1853 | if (new) { | 1860 | if (new) { |
1854 | /* disable ce features */ | 1861 | /* disable ce features */ |
1855 | on_each_cpu(mce_disable_ce, (void *)1, 1); | 1862 | mce_timer_delete_all(); |
1863 | on_each_cpu(mce_disable_cmci, NULL, 1); | ||
1856 | mce_ignore_ce = 1; | 1864 | mce_ignore_ce = 1; |
1857 | } else { | 1865 | } else { |
1858 | /* enable ce features */ | 1866 | /* enable ce features */ |
@@ -1875,7 +1883,7 @@ static ssize_t set_cmci_disabled(struct sys_device *s, | |||
1875 | if (mce_cmci_disabled ^ !!new) { | 1883 | if (mce_cmci_disabled ^ !!new) { |
1876 | if (new) { | 1884 | if (new) { |
1877 | /* disable cmci */ | 1885 | /* disable cmci */ |
1878 | on_each_cpu(mce_disable_ce, NULL, 1); | 1886 | on_each_cpu(mce_disable_cmci, NULL, 1); |
1879 | mce_cmci_disabled = 1; | 1887 | mce_cmci_disabled = 1; |
1880 | } else { | 1888 | } else { |
1881 | /* enable cmci */ | 1889 | /* enable cmci */ |