| From | Kamal Mostafa <> | Subject | [PATCH 3.19.y-ckt 091/146] powerpc/mce: fix off by one errors in mce event handling | Date | Wed, 17 Jun 2015 15:23:16 -0700 |
| |
3.19.8-ckt2 -stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Axtens <dja@axtens.net>
commit ffb2d78eca08a1451137583d4e435aecfd6af809 upstream.
Before 69111bac42f5 ("powerpc: Replace __get_cpu_var uses"), in save_mce_event, index got the value of mce_nest_count, and mce_nest_count was incremented *after* index was set.
However, that patch changed the behaviour so that mce_nest count was incremented *before* setting index.
This causes an off-by-one error, as get_mce_event sets index as mce_nest_count - 1 before reading mce_event. Thus get_mce_event reads bogus data, causing warnings like "Machine Check Exception, Unknown event version 0 !" and breaking MCEs handling.
Restore the old behaviour and unbreak MCE handling by subtracting one from the newly incremented value.
The same broken change occured in machine_check_queue_event (which set a queue read by machine_check_process_queued_event). Fix that too, unbreaking printing of MCE information.
Fixes: 69111bac42f5 ("powerpc: Replace __get_cpu_var uses") CC: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> CC: Christoph Lameter <cl@linux.com> Signed-off-by: Daniel Axtens <dja@axtens.net> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Kamal Mostafa <kamal@canonical.com> --- arch/powerpc/kernel/mce.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c index 15c99b6..b2eb468 100644 --- a/arch/powerpc/kernel/mce.c +++ b/arch/powerpc/kernel/mce.c @@ -73,7 +73,7 @@ void save_mce_event(struct pt_regs *regs, long handled, uint64_t nip, uint64_t addr) { uint64_t srr1; - int index = __this_cpu_inc_return(mce_nest_count); + int index = __this_cpu_inc_return(mce_nest_count) - 1; struct machine_check_event *mce = this_cpu_ptr(&mce_event[index]); /* @@ -184,7 +184,7 @@ void machine_check_queue_event(void) if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) return; - index = __this_cpu_inc_return(mce_queue_count); + index = __this_cpu_inc_return(mce_queue_count) - 1; /* If queue is full, just return for now. */ if (index >= MAX_MC_EVT) { __this_cpu_dec(mce_queue_count); -- 1.9.1
|