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