summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-01-11 12:11:39 +0100
committerPaul Mackerras <paulus@samba.org>2006-01-12 10:09:29 +0100
commit5388fb1025443ec223ba556b10efc4c5f83f8682 (patch)
treeb14832a8886bd254533f226263a2047545c57805 /arch/powerpc/kernel/signal_32.c
parentMerge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb (diff)
downloadlinux-5388fb1025443ec223ba556b10efc4c5f83f8682.tar.xz
linux-5388fb1025443ec223ba556b10efc4c5f83f8682.zip
[PATCH] powerpc: Avoid potential FP corruption with preempt and UP
Heikki Lindholm pointed out that there was a potential race with the lazy CPU state (FP, VR, EVR) stuff if preempt is enabled. The race is that in the process of restoring FP state on sigreturn, the task gets preempted by a user task that wants to use the FPU. It will take an FP unavailable exception, which will write the current FPU state to the thread_struct, overwriting the values which sigreturn has stored. Note that this can only happen on UP since we don't implement lazy CPU state on SMP. The fix is to flush the lazy CPU state before updating the thread_struct. To do this we re-use the flush_lazy_cpu_state() function from process.c. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c21
1 files changed, 9 insertions, 12 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d3f0b6d452fb..177bba78fb0b 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -497,6 +497,15 @@ static long restore_user_regs(struct pt_regs *regs,
if (err)
return 1;
+ /*
+ * Do this before updating the thread state in
+ * current->thread.fpr/vr/evr. That way, if we get preempted
+ * and another task grabs the FPU/Altivec/SPE, it won't be
+ * tempted to save the current CPU state into the thread_struct
+ * and corrupt what we are writing there.
+ */
+ discard_lazy_cpu_state();
+
/* force the process to reload the FP registers from
current->thread when it next does FP instructions */
regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
@@ -538,18 +547,6 @@ static long restore_user_regs(struct pt_regs *regs,
return 1;
#endif /* CONFIG_SPE */
-#ifndef CONFIG_SMP
- preempt_disable();
- if (last_task_used_math == current)
- last_task_used_math = NULL;
- if (last_task_used_altivec == current)
- last_task_used_altivec = NULL;
-#ifdef CONFIG_SPE
- if (last_task_used_spe == current)
- last_task_used_spe = NULL;
-#endif
- preempt_enable();
-#endif
return 0;
}