diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-09 21:01:52 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-09 21:01:52 -0500 |
commit | c93ecedab35f5305542a9fe5cfbd37377189589e (patch) | |
tree | c480259a0588c1dd47f596e25f6ac805d878bf05 /arch/x86/kernel | |
parent | 072bc448cc796c4d2d3519795f38e13a6c2a14a5 (diff) | |
parent | 7575637ab293861a799f3bbafe0d8c597389f4e9 (diff) |
Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fpu updates from Ingo Molnar:
"Initial round of kernel_fpu_begin/end cleanups from Oleg Nesterov,
plus a cleanup from Borislav Petkov"
* 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, fpu: Fix math_state_restore() race with kernel_fpu_begin()
x86, fpu: Don't abuse has_fpu in __kernel_fpu_begin/end()
x86, fpu: Introduce per-cpu in_kernel_fpu state
x86/fpu: Use a symbolic name for asm operand
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/i387.c | 39 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 12 |
2 files changed, 31 insertions, 20 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index a9a4229f6161..81049ffab2d6 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
@@ -19,6 +19,19 @@ | |||
19 | #include <asm/fpu-internal.h> | 19 | #include <asm/fpu-internal.h> |
20 | #include <asm/user.h> | 20 | #include <asm/user.h> |
21 | 21 | ||
22 | static DEFINE_PER_CPU(bool, in_kernel_fpu); | ||
23 | |||
24 | void kernel_fpu_disable(void) | ||
25 | { | ||
26 | WARN_ON(this_cpu_read(in_kernel_fpu)); | ||
27 | this_cpu_write(in_kernel_fpu, true); | ||
28 | } | ||
29 | |||
30 | void kernel_fpu_enable(void) | ||
31 | { | ||
32 | this_cpu_write(in_kernel_fpu, false); | ||
33 | } | ||
34 | |||
22 | /* | 35 | /* |
23 | * Were we in an interrupt that interrupted kernel mode? | 36 | * Were we in an interrupt that interrupted kernel mode? |
24 | * | 37 | * |
@@ -33,6 +46,9 @@ | |||
33 | */ | 46 | */ |
34 | static inline bool interrupted_kernel_fpu_idle(void) | 47 | static inline bool interrupted_kernel_fpu_idle(void) |
35 | { | 48 | { |
49 | if (this_cpu_read(in_kernel_fpu)) | ||
50 | return false; | ||
51 | |||
36 | if (use_eager_fpu()) | 52 | if (use_eager_fpu()) |
37 | return __thread_has_fpu(current); | 53 | return __thread_has_fpu(current); |
38 | 54 | ||
@@ -73,10 +89,10 @@ void __kernel_fpu_begin(void) | |||
73 | { | 89 | { |
74 | struct task_struct *me = current; | 90 | struct task_struct *me = current; |
75 | 91 | ||
92 | this_cpu_write(in_kernel_fpu, true); | ||
93 | |||
76 | if (__thread_has_fpu(me)) { | 94 | if (__thread_has_fpu(me)) { |
77 | __thread_clear_has_fpu(me); | ||
78 | __save_init_fpu(me); | 95 | __save_init_fpu(me); |
79 | /* We do 'stts()' in __kernel_fpu_end() */ | ||
80 | } else if (!use_eager_fpu()) { | 96 | } else if (!use_eager_fpu()) { |
81 | this_cpu_write(fpu_owner_task, NULL); | 97 | this_cpu_write(fpu_owner_task, NULL); |
82 | clts(); | 98 | clts(); |
@@ -86,19 +102,16 @@ EXPORT_SYMBOL(__kernel_fpu_begin); | |||
86 | 102 | ||
87 | void __kernel_fpu_end(void) | 103 | void __kernel_fpu_end(void) |
88 | { | 104 | { |
89 | if (use_eager_fpu()) { | 105 | struct task_struct *me = current; |
90 | /* | 106 | |
91 | * For eager fpu, most the time, tsk_used_math() is true. | 107 | if (__thread_has_fpu(me)) { |
92 | * Restore the user math as we are done with the kernel usage. | 108 | if (WARN_ON(restore_fpu_checking(me))) |
93 | * At few instances during thread exit, signal handling etc, | 109 | drop_init_fpu(me); |
94 | * tsk_used_math() is false. Those few places will take proper | 110 | } else if (!use_eager_fpu()) { |
95 | * actions, so we don't need to restore the math here. | ||
96 | */ | ||
97 | if (likely(tsk_used_math(current))) | ||
98 | math_state_restore(); | ||
99 | } else { | ||
100 | stts(); | 111 | stts(); |
101 | } | 112 | } |
113 | |||
114 | this_cpu_write(in_kernel_fpu, false); | ||
102 | } | 115 | } |
103 | EXPORT_SYMBOL(__kernel_fpu_end); | 116 | EXPORT_SYMBOL(__kernel_fpu_end); |
104 | 117 | ||
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index c74f2f5652da..9d2073e2ecc9 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -859,18 +859,16 @@ void math_state_restore(void) | |||
859 | local_irq_disable(); | 859 | local_irq_disable(); |
860 | } | 860 | } |
861 | 861 | ||
862 | /* Avoid __kernel_fpu_begin() right after __thread_fpu_begin() */ | ||
863 | kernel_fpu_disable(); | ||
862 | __thread_fpu_begin(tsk); | 864 | __thread_fpu_begin(tsk); |
863 | |||
864 | /* | ||
865 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | ||
866 | */ | ||
867 | if (unlikely(restore_fpu_checking(tsk))) { | 865 | if (unlikely(restore_fpu_checking(tsk))) { |
868 | drop_init_fpu(tsk); | 866 | drop_init_fpu(tsk); |
869 | force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk); | 867 | force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk); |
870 | return; | 868 | } else { |
869 | tsk->thread.fpu_counter++; | ||
871 | } | 870 | } |
872 | 871 | kernel_fpu_enable(); | |
873 | tsk->thread.fpu_counter++; | ||
874 | } | 872 | } |
875 | EXPORT_SYMBOL_GPL(math_state_restore); | 873 | EXPORT_SYMBOL_GPL(math_state_restore); |
876 | 874 | ||