diff options
author | Peter Chubb <peterc@gelato.unsw.edu.au> | 2005-06-08 18:50:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-08 19:21:14 -0400 |
commit | 05062d96a23ec0959ee5ea969f40813170c73c0e (patch) | |
tree | 9aa09b58ff455cc43b81cae10d3c4dac9fe9f462 /arch/ia64/kernel | |
parent | f829fd23c87918374bac0d90404fe12f0e788d52 (diff) |
[PATCH] ia64: fix floating-point preemption problem
There've been reports of problems with CONFIG_PREEMPT=y and the high
floating point partition. This is caused by the possibility of preemption
and rescheduling on a different processor while saving or restioirng the
high partition.
The only places where the FPU state is touched are in ptrace, in
switch_to(), and where handling a floating-point exception. In switch_to()
preemption is off. So it's only in trap.c and ptrace.c that we need to
prevent preemption.
Here is a patch that adds commentary to make the conditions clear, and adds
appropriate preempt_{en,dis}able() calls to make it so. In trap.c I use
preempt_enable_no_resched(), as we're about to return to user space where
the preemption flag will be checked anyway.
Signed-off-by: Peter Chubb <peterc@gelato.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ia64/kernel')
-rw-r--r-- | arch/ia64/kernel/ptrace.c | 6 | ||||
-rw-r--r-- | arch/ia64/kernel/traps.c | 11 |
2 files changed, 16 insertions, 1 deletions
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 08c8a5eb25ab..575a8f657b31 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -635,11 +635,17 @@ ia64_flush_fph (struct task_struct *task) | |||
635 | { | 635 | { |
636 | struct ia64_psr *psr = ia64_psr(ia64_task_regs(task)); | 636 | struct ia64_psr *psr = ia64_psr(ia64_task_regs(task)); |
637 | 637 | ||
638 | /* | ||
639 | * Prevent migrating this task while | ||
640 | * we're fiddling with the FPU state | ||
641 | */ | ||
642 | preempt_disable(); | ||
638 | if (ia64_is_local_fpu_owner(task) && psr->mfh) { | 643 | if (ia64_is_local_fpu_owner(task) && psr->mfh) { |
639 | psr->mfh = 0; | 644 | psr->mfh = 0; |
640 | task->thread.flags |= IA64_THREAD_FPH_VALID; | 645 | task->thread.flags |= IA64_THREAD_FPH_VALID; |
641 | ia64_save_fpu(&task->thread.fph[0]); | 646 | ia64_save_fpu(&task->thread.fph[0]); |
642 | } | 647 | } |
648 | preempt_enable(); | ||
643 | } | 649 | } |
644 | 650 | ||
645 | /* | 651 | /* |
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index 9bad6652d531..1861173bd4f6 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c | |||
@@ -220,13 +220,21 @@ disabled_fph_fault (struct pt_regs *regs) | |||
220 | 220 | ||
221 | /* first, grant user-level access to fph partition: */ | 221 | /* first, grant user-level access to fph partition: */ |
222 | psr->dfh = 0; | 222 | psr->dfh = 0; |
223 | |||
224 | /* | ||
225 | * Make sure that no other task gets in on this processor | ||
226 | * while we're claiming the FPU | ||
227 | */ | ||
228 | preempt_disable(); | ||
223 | #ifndef CONFIG_SMP | 229 | #ifndef CONFIG_SMP |
224 | { | 230 | { |
225 | struct task_struct *fpu_owner | 231 | struct task_struct *fpu_owner |
226 | = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); | 232 | = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); |
227 | 233 | ||
228 | if (ia64_is_local_fpu_owner(current)) | 234 | if (ia64_is_local_fpu_owner(current)) { |
235 | preempt_enable_no_resched(); | ||
229 | return; | 236 | return; |
237 | } | ||
230 | 238 | ||
231 | if (fpu_owner) | 239 | if (fpu_owner) |
232 | ia64_flush_fph(fpu_owner); | 240 | ia64_flush_fph(fpu_owner); |
@@ -244,6 +252,7 @@ disabled_fph_fault (struct pt_regs *regs) | |||
244 | */ | 252 | */ |
245 | psr->mfh = 1; | 253 | psr->mfh = 1; |
246 | } | 254 | } |
255 | preempt_enable_no_resched(); | ||
247 | } | 256 | } |
248 | 257 | ||
249 | static inline int | 258 | static inline int |