Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/fpu: Fix FNSAVE usage in eagerfpu mode

In eager fpu mode, having deactivated FPU without immediately
reloading some other context is illegal. Therefore, to recover from
FNSAVE, we can't just deactivate the state -- we need to reload it
if we're not actively context switching.

We had this wrong in fpu__save() and fpu__copy(). Fix both.
__kernel_fpu_begin() was fine -- add a comment.

This fixes a warning triggerable with nofxsr eagerfpu=on.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: yu-cheng yu <yu-cheng.yu@intel.com>
Link: http://lkml.kernel.org/r/60662444e13c76f06e23c15c5dcdba31b4ac3d67.1453675014.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Andy Lutomirski and committed by
Ingo Molnar
5ed73f40 4ecd16ec

+15 -3
+15 -3
arch/x86/kernel/fpu/core.c
··· 114 114 kernel_fpu_disable(); 115 115 116 116 if (fpu->fpregs_active) { 117 + /* 118 + * Ignore return value -- we don't care if reg state 119 + * is clobbered. 120 + */ 117 121 copy_fpregs_to_fpstate(fpu); 118 122 } else { 119 123 this_cpu_write(fpu_fpregs_owner_ctx, NULL); ··· 193 189 194 190 preempt_disable(); 195 191 if (fpu->fpregs_active) { 196 - if (!copy_fpregs_to_fpstate(fpu)) 197 - fpregs_deactivate(fpu); 192 + if (!copy_fpregs_to_fpstate(fpu)) { 193 + if (use_eager_fpu()) 194 + copy_kernel_to_fpregs(&fpu->state); 195 + else 196 + fpregs_deactivate(fpu); 197 + } 198 198 } 199 199 preempt_enable(); 200 200 } ··· 267 259 preempt_disable(); 268 260 if (!copy_fpregs_to_fpstate(dst_fpu)) { 269 261 memcpy(&src_fpu->state, &dst_fpu->state, xstate_size); 270 - fpregs_deactivate(src_fpu); 262 + 263 + if (use_eager_fpu()) 264 + copy_kernel_to_fpregs(&src_fpu->state); 265 + else 266 + fpregs_deactivate(src_fpu); 271 267 } 272 268 preempt_enable(); 273 269 }