| From: Siarhei Liakh <Siarhei.Liakh@concurrent-rt.com> |
| Date: Thu, 14 Jun 2018 19:36:07 +0000 |
| Subject: x86: Call fixup_exception() before notify_die() in math_error() |
| |
| commit 3ae6295ccb7cf6d344908209701badbbbb503e40 upstream. |
| |
| fpu__drop() has an explicit fwait which under some conditions can trigger a |
| fixable FPU exception while in kernel. Thus, we should attempt to fixup the |
| exception first, and only call notify_die() if the fixup failed just like |
| in do_general_protection(). The original call sequence incorrectly triggers |
| KDB entry on debug kernels under particular FPU-intensive workloads. |
| |
| Andy noted, that this makes the whole conditional irq enable thing even |
| more inconsistent, but fixing that it outside the scope of this. |
| |
| Signed-off-by: Siarhei Liakh <siarhei.liakh@concurrent-rt.com> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Reviewed-by: Andy Lutomirski <luto@kernel.org> |
| Cc: "H. Peter Anvin" <hpa@zytor.com> |
| Cc: "Borislav Petkov" <bpetkov@suse.de> |
| Link: https://lkml.kernel.org/r/DM5PR11MB201156F1CAB2592B07C79A03B17D0@DM5PR11MB2011.namprd11.prod.outlook.com |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| arch/x86/kernel/traps.c | 14 ++++++++------ |
| 1 file changed, 8 insertions(+), 6 deletions(-) |
| |
| --- a/arch/x86/kernel/traps.c |
| +++ b/arch/x86/kernel/traps.c |
| @@ -556,17 +556,19 @@ static void math_error(struct pt_regs *r |
| char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" : |
| "simd exception"; |
| |
| - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, SIGFPE) == NOTIFY_STOP) |
| - return; |
| conditional_sti(regs); |
| |
| if (!user_mode_vm(regs)) |
| { |
| - if (!fixup_exception(regs)) { |
| - task->thread.error_code = error_code; |
| - task->thread.trap_nr = trapnr; |
| + if (fixup_exception(regs)) |
| + return; |
| + |
| + task->thread.error_code = error_code; |
| + task->thread.trap_nr = trapnr; |
| + |
| + if (notify_die(DIE_TRAP, str, regs, error_code, |
| + trapnr, SIGFPE) != NOTIFY_STOP) |
| die(str, regs, error_code); |
| - } |
| return; |
| } |
| |