diff options
author | Andi Kleen <ak@suse.de> | 2005-09-12 12:49:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-12 13:49:56 -0400 |
commit | 673242c10d535bfe238d9d8e82ac93432d35b88e (patch) | |
tree | 959b4ffb0ebf788df812fe27498248c26610d22c | |
parent | a54e678b8f476d6f28e6aa4409f6b88ce476af1b (diff) |
[PATCH] x86-64: Make lockless machine check record passing a bit more robust.
One machine is constantly throwing NMI watchdog timeouts in mce_log
This was one attempt to fix it.
(AK: this doesn't actually fix the bug I'm seeing unfortunately, probably
drop. I don't like it that the reader can spin forever now waiting
for a writer)
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/x86_64/kernel/mce.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 8aa56736cde3..87ea8fdd43fd 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c | |||
@@ -56,15 +56,19 @@ void mce_log(struct mce *mce) | |||
56 | smp_wmb(); | 56 | smp_wmb(); |
57 | for (;;) { | 57 | for (;;) { |
58 | entry = rcu_dereference(mcelog.next); | 58 | entry = rcu_dereference(mcelog.next); |
59 | /* When the buffer fills up discard new entries. Assume | 59 | for (;;) { |
60 | that the earlier errors are the more interesting. */ | 60 | /* When the buffer fills up discard new entries. Assume |
61 | if (entry >= MCE_LOG_LEN) { | 61 | that the earlier errors are the more interesting. */ |
62 | set_bit(MCE_OVERFLOW, &mcelog.flags); | 62 | if (entry >= MCE_LOG_LEN) { |
63 | return; | 63 | set_bit(MCE_OVERFLOW, &mcelog.flags); |
64 | return; | ||
65 | } | ||
66 | /* Old left over entry. Skip. */ | ||
67 | if (mcelog.entry[entry].finished) { | ||
68 | entry++; | ||
69 | continue; | ||
70 | } | ||
64 | } | 71 | } |
65 | /* Old left over entry. Skip. */ | ||
66 | if (mcelog.entry[entry].finished) | ||
67 | continue; | ||
68 | smp_rmb(); | 72 | smp_rmb(); |
69 | next = entry + 1; | 73 | next = entry + 1; |
70 | if (cmpxchg(&mcelog.next, entry, next) == entry) | 74 | if (cmpxchg(&mcelog.next, entry, next) == entry) |
@@ -404,9 +408,15 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff | |||
404 | } | 408 | } |
405 | 409 | ||
406 | err = 0; | 410 | err = 0; |
407 | for (i = 0; i < next; i++) { | 411 | for (i = 0; i < next; i++) { |
408 | if (!mcelog.entry[i].finished) | 412 | unsigned long start = jiffies; |
409 | continue; | 413 | while (!mcelog.entry[i].finished) { |
414 | if (!time_before(jiffies, start + 2)) { | ||
415 | memset(mcelog.entry + i,0, sizeof(struct mce)); | ||
416 | continue; | ||
417 | } | ||
418 | cpu_relax(); | ||
419 | } | ||
410 | smp_rmb(); | 420 | smp_rmb(); |
411 | err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce)); | 421 | err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce)); |
412 | buf += sizeof(struct mce); | 422 | buf += sizeof(struct mce); |