[PATCH] x86_64: Fix mce_log

The attempt to fixup the lockless mce log buffer introduced an infinite loop
when trying to find a free entry.

And:

Using rcu_dereference() to load mcelog.next doesn't seem to be sufficient
enough to ensure that mcelog.next is loaded each time around the loop in
mce_log(). Instead, use an explicit rmb() to ensure that the compiler gets it
right.

AK: turned the smp_wmbs into true wmbs to make sure they are not
reordered by the compiler on UP.

Signed-off-by: Mike Waychison <mikew@google.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Mike Waychison and committed by Linus Torvalds 7644143c 7d318d77

+7 -3
+7 -3
arch/x86_64/kernel/mce.c
··· 54 54 { 55 55 unsigned next, entry; 56 56 mce->finished = 0; 57 - smp_wmb(); 57 + wmb(); 58 58 for (;;) { 59 59 entry = rcu_dereference(mcelog.next); 60 + /* The rmb forces the compiler to reload next in each 61 + iteration */ 62 + rmb(); 60 63 for (;;) { 61 64 /* When the buffer fills up discard new entries. Assume 62 65 that the earlier errors are the more interesting. */ ··· 72 69 entry++; 73 70 continue; 74 71 } 72 + break; 75 73 } 76 74 smp_rmb(); 77 75 next = entry + 1; ··· 80 76 break; 81 77 } 82 78 memcpy(mcelog.entry + entry, mce, sizeof(struct mce)); 83 - smp_wmb(); 79 + wmb(); 84 80 mcelog.entry[entry].finished = 1; 85 - smp_wmb(); 81 + wmb(); 86 82 87 83 if (!test_and_set_bit(0, &console_logged)) 88 84 notify_user = 1;