diff options
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 75 |
1 files changed, 64 insertions, 11 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 9c7419e459d6..54bd1b2fb4c0 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -204,6 +204,9 @@ static void print_mce_tail(void) | |||
204 | 204 | ||
205 | static atomic_t mce_paniced; | 205 | static atomic_t mce_paniced; |
206 | 206 | ||
207 | static int fake_panic; | ||
208 | static atomic_t mce_fake_paniced; | ||
209 | |||
207 | /* Panic in progress. Enable interrupts and wait for final IPI */ | 210 | /* Panic in progress. Enable interrupts and wait for final IPI */ |
208 | static void wait_for_panic(void) | 211 | static void wait_for_panic(void) |
209 | { | 212 | { |
@@ -221,15 +224,21 @@ static void mce_panic(char *msg, struct mce *final, char *exp) | |||
221 | { | 224 | { |
222 | int i; | 225 | int i; |
223 | 226 | ||
224 | /* | 227 | if (!fake_panic) { |
225 | * Make sure only one CPU runs in machine check panic | 228 | /* |
226 | */ | 229 | * Make sure only one CPU runs in machine check panic |
227 | if (atomic_inc_return(&mce_paniced) > 1) | 230 | */ |
228 | wait_for_panic(); | 231 | if (atomic_inc_return(&mce_paniced) > 1) |
229 | barrier(); | 232 | wait_for_panic(); |
233 | barrier(); | ||
230 | 234 | ||
231 | bust_spinlocks(1); | 235 | bust_spinlocks(1); |
232 | console_verbose(); | 236 | console_verbose(); |
237 | } else { | ||
238 | /* Don't log too much for fake panic */ | ||
239 | if (atomic_inc_return(&mce_fake_paniced) > 1) | ||
240 | return; | ||
241 | } | ||
233 | print_mce_head(); | 242 | print_mce_head(); |
234 | /* First print corrected ones that are still unlogged */ | 243 | /* First print corrected ones that are still unlogged */ |
235 | for (i = 0; i < MCE_LOG_LEN; i++) { | 244 | for (i = 0; i < MCE_LOG_LEN; i++) { |
@@ -256,9 +265,12 @@ static void mce_panic(char *msg, struct mce *final, char *exp) | |||
256 | print_mce_tail(); | 265 | print_mce_tail(); |
257 | if (exp) | 266 | if (exp) |
258 | printk(KERN_EMERG "Machine check: %s\n", exp); | 267 | printk(KERN_EMERG "Machine check: %s\n", exp); |
259 | if (panic_timeout == 0) | 268 | if (!fake_panic) { |
260 | panic_timeout = mce_panic_timeout; | 269 | if (panic_timeout == 0) |
261 | panic(msg); | 270 | panic_timeout = mce_panic_timeout; |
271 | panic(msg); | ||
272 | } else | ||
273 | printk(KERN_EMERG "Fake kernel panic: %s\n", msg); | ||
262 | } | 274 | } |
263 | 275 | ||
264 | /* Support code for software error injection */ | 276 | /* Support code for software error injection */ |
@@ -2015,4 +2027,45 @@ struct dentry *mce_get_debugfs_dir(void) | |||
2015 | 2027 | ||
2016 | return dmce; | 2028 | return dmce; |
2017 | } | 2029 | } |
2030 | |||
2031 | static void mce_reset(void) | ||
2032 | { | ||
2033 | cpu_missing = 0; | ||
2034 | atomic_set(&mce_fake_paniced, 0); | ||
2035 | atomic_set(&mce_executing, 0); | ||
2036 | atomic_set(&mce_callin, 0); | ||
2037 | atomic_set(&global_nwo, 0); | ||
2038 | } | ||
2039 | |||
2040 | static int fake_panic_get(void *data, u64 *val) | ||
2041 | { | ||
2042 | *val = fake_panic; | ||
2043 | return 0; | ||
2044 | } | ||
2045 | |||
2046 | static int fake_panic_set(void *data, u64 val) | ||
2047 | { | ||
2048 | mce_reset(); | ||
2049 | fake_panic = val; | ||
2050 | return 0; | ||
2051 | } | ||
2052 | |||
2053 | DEFINE_SIMPLE_ATTRIBUTE(fake_panic_fops, fake_panic_get, | ||
2054 | fake_panic_set, "%llu\n"); | ||
2055 | |||
2056 | static int __init mce_debugfs_init(void) | ||
2057 | { | ||
2058 | struct dentry *dmce, *ffake_panic; | ||
2059 | |||
2060 | dmce = mce_get_debugfs_dir(); | ||
2061 | if (!dmce) | ||
2062 | return -ENOMEM; | ||
2063 | ffake_panic = debugfs_create_file("fake_panic", 0444, dmce, NULL, | ||
2064 | &fake_panic_fops); | ||
2065 | if (!ffake_panic) | ||
2066 | return -ENOMEM; | ||
2067 | |||
2068 | return 0; | ||
2069 | } | ||
2070 | late_initcall(mce_debugfs_init); | ||
2018 | #endif | 2071 | #endif |