From: Andrea Arcangeli <andrea@suse.de>

Convert the unsafe signed (16bit) used_math to a safe and optimal
PF_USED_MATH

I might have broken arm, see the very first change in the patch to
asm-offsets.c, rest looks ok at first glance.

If you want used_math to return 0 or 1 (instead of 0 or PF_USED_MATH), just
s/!!// in the below patch and place !!  in sched.h::*used_math()
accordingly after applying the patch, it should work just fine.  Using !! 
only when necessary as the below is optimal.

Signed-off-by: Andrea Arcangeli <andrea@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/arm26/kernel/asm-offsets.c |    1 
 25-akpm/arch/arm26/kernel/process.c     |    4 +-
 25-akpm/arch/arm26/kernel/ptrace.c      |    2 -
 25-akpm/arch/i386/kernel/cpu/common.c   |    2 -
 25-akpm/arch/i386/kernel/i387.c         |   15 +++++------
 25-akpm/arch/i386/kernel/process.c      |    2 -
 25-akpm/arch/i386/kernel/ptrace.c       |    8 ++---
 25-akpm/arch/i386/kernel/signal.c       |    4 +-
 25-akpm/arch/i386/kernel/traps.c        |    2 -
 25-akpm/arch/i386/math-emu/fpu_entry.c  |    4 +-
 25-akpm/arch/ia64/ia32/elfcore32.h      |    4 +-
 25-akpm/arch/m32r/kernel/ptrace.c       |    8 ++---
 25-akpm/arch/m32r/kernel/setup.c        |    2 -
 25-akpm/arch/mips/kernel/irixsig.c      |    4 +-
 25-akpm/arch/mips/kernel/process.c      |    2 -
 25-akpm/arch/mips/kernel/ptrace.c       |    4 +-
 25-akpm/arch/mips/kernel/ptrace32.c     |    4 +-
 25-akpm/arch/mips/kernel/signal.c       |    8 ++---
 25-akpm/arch/mips/kernel/signal32.c     |    8 ++---
 25-akpm/arch/mips/kernel/traps.c        |    4 +-
 25-akpm/arch/s390/kernel/process.c      |    3 --
 25-akpm/arch/s390/kernel/setup.c        |    2 -
 25-akpm/arch/sh/kernel/cpu/init.c       |    2 -
 25-akpm/arch/sh/kernel/cpu/sh4/fpu.c    |    4 +-
 25-akpm/arch/sh/kernel/process.c        |    8 ++---
 25-akpm/arch/sh/kernel/ptrace.c         |    8 ++---
 25-akpm/arch/sh/kernel/signal.c         |    8 ++---
 25-akpm/arch/sh64/kernel/fpu.c          |    4 +-
 25-akpm/arch/sh64/kernel/process.c      |    4 +-
 25-akpm/arch/sh64/kernel/ptrace.c       |    8 ++---
 25-akpm/arch/sh64/kernel/signal.c       |    6 ++--
 25-akpm/arch/sparc/kernel/process.c     |    2 -
 25-akpm/arch/sparc/kernel/signal.c      |   12 ++++----
 25-akpm/arch/sparc/kernel/traps.c       |    8 ++---
 25-akpm/arch/x86_64/ia32/fpu32.c        |    2 -
 25-akpm/arch/x86_64/ia32/ia32_binfmt.c  |    4 +-
 25-akpm/arch/x86_64/ia32/ia32_signal.c  |    6 ++--
 25-akpm/arch/x86_64/ia32/ptrace32.c     |    2 -
 25-akpm/arch/x86_64/kernel/i387.c       |   15 +++++------
 25-akpm/arch/x86_64/kernel/process.c    |    2 -
 25-akpm/arch/x86_64/kernel/ptrace.c     |    2 -
 25-akpm/arch/x86_64/kernel/signal.c     |    6 ++--
 25-akpm/arch/x86_64/kernel/traps.c      |    2 -
 25-akpm/include/asm-arm26/constants.h   |    1 
 25-akpm/include/asm-x86_64/i387.h       |   10 -------
 25-akpm/include/linux/sched.h           |   43 ++++++++++++++++++++------------
 46 files changed, 134 insertions(+), 132 deletions(-)

diff -puN arch/arm26/kernel/asm-offsets.c~make-used_math-smp-safe arch/arm26/kernel/asm-offsets.c
--- 25/arch/arm26/kernel/asm-offsets.c~make-used_math-smp-safe	2005-01-22 23:05:59.724463704 -0800
+++ 25-akpm/arch/arm26/kernel/asm-offsets.c	2005-01-22 23:05:59.789453824 -0800
@@ -42,7 +42,6 @@
 
 int main(void)
 {
-  DEFINE(TSK_USED_MATH,		offsetof(struct task_struct, used_math));
   DEFINE(TSK_ACTIVE_MM,		offsetof(struct task_struct, active_mm));
   BLANK();
   DEFINE(VMA_VM_MM,		offsetof(struct vm_area_struct, vm_mm));
diff -puN arch/arm26/kernel/process.c~make-used_math-smp-safe arch/arm26/kernel/process.c
--- 25/arch/arm26/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.725463552 -0800
+++ 25-akpm/arch/arm26/kernel/process.c	2005-01-22 23:05:59.789453824 -0800
@@ -271,7 +271,7 @@ void flush_thread(void)
 	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
 	memset(&thread->fpstate, 0, sizeof(union fp_state));
 
-	current->used_math = 0;
+	clear_used_math();
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -305,7 +305,7 @@ copy_thread(int nr, unsigned long clone_
 int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
 {
 	struct thread_info *thread = current_thread_info();
-	int used_math = current->used_math;
+	int used_math = !!used_math();
 
 	if (used_math)
 		memcpy(fp, &thread->fpstate.soft, sizeof (*fp));
diff -puN arch/arm26/kernel/ptrace.c~make-used_math-smp-safe arch/arm26/kernel/ptrace.c
--- 25/arch/arm26/kernel/ptrace.c~make-used_math-smp-safe	2005-01-22 23:05:59.727463248 -0800
+++ 25-akpm/arch/arm26/kernel/ptrace.c	2005-01-22 23:05:59.790453672 -0800
@@ -540,7 +540,7 @@ static int ptrace_getfpregs(struct task_
  */
 static int ptrace_setfpregs(struct task_struct *tsk, void *ufp)
 {
-	tsk->used_math = 1;
+	set_stopped_child_used_math(tsk);
 	return copy_from_user(&tsk->thread_info->fpstate, ufp,
 			      sizeof(struct user_fp)) ? -EFAULT : 0;
 }
diff -puN arch/i386/kernel/cpu/common.c~make-used_math-smp-safe arch/i386/kernel/cpu/common.c
--- 25/arch/i386/kernel/cpu/common.c~make-used_math-smp-safe	2005-01-22 23:05:59.728463096 -0800
+++ 25-akpm/arch/i386/kernel/cpu/common.c	2005-01-22 23:05:59.791453520 -0800
@@ -629,6 +629,6 @@ void __init cpu_init (void)
 	 * Force FPU initialization:
 	 */
 	current_thread_info()->status = 0;
-	current->used_math = 0;
+	clear_used_math();
 	mxcsr_feature_mask_init();
 }
diff -puN arch/i386/kernel/i387.c~make-used_math-smp-safe arch/i386/kernel/i387.c
--- 25/arch/i386/kernel/i387.c~make-used_math-smp-safe	2005-01-22 23:05:59.730462792 -0800
+++ 25-akpm/arch/i386/kernel/i387.c	2005-01-22 23:05:59.791453520 -0800
@@ -60,7 +60,8 @@ void init_fpu(struct task_struct *tsk)
 		tsk->thread.i387.fsave.twd = 0xffffffffu;
 		tsk->thread.i387.fsave.fos = 0xffff0000u;
 	}
-	tsk->used_math = 1;
+	/* only the device not available exception or ptrace can call init_fpu */
+	set_stopped_child_used_math(tsk);
 }
 
 /*
@@ -331,13 +332,13 @@ static int save_i387_fxsave( struct _fps
 
 int save_i387( struct _fpstate __user *buf )
 {
-	if ( !current->used_math )
+	if ( !used_math() )
 		return 0;
 
 	/* This will cause a "finit" to be triggered by the next
 	 * attempted FPU operation by the 'current' process.
 	 */
-	current->used_math = 0;
+	clear_used_math();
 
 	if ( HAVE_HWFP ) {
 		if ( cpu_has_fxsr ) {
@@ -383,7 +384,7 @@ int restore_i387( struct _fpstate __user
 	} else {
 		err = restore_i387_soft( &current->thread.i387.soft, buf );
 	}
-	current->used_math = 1;
+	set_used_math();
 	return err;
 }
 
@@ -507,7 +508,7 @@ int dump_fpu( struct pt_regs *regs, stru
 	int fpvalid;
 	struct task_struct *tsk = current;
 
-	fpvalid = tsk->used_math;
+	fpvalid = !!used_math();
 	if ( fpvalid ) {
 		unlazy_fpu( tsk );
 		if ( cpu_has_fxsr ) {
@@ -522,7 +523,7 @@ int dump_fpu( struct pt_regs *regs, stru
 
 int dump_task_fpu(struct task_struct *tsk, struct user_i387_struct *fpu)
 {
-	int fpvalid = tsk->used_math;
+	int fpvalid = !!tsk_used_math(tsk);
 
 	if (fpvalid) {
 		if (tsk == current)
@@ -537,7 +538,7 @@ int dump_task_fpu(struct task_struct *ts
 
 int dump_task_extended_fpu(struct task_struct *tsk, struct user_fxsr_struct *fpu)
 {
-	int fpvalid = tsk->used_math && cpu_has_fxsr;
+	int fpvalid = tsk_used_math(tsk) && cpu_has_fxsr;
 
 	if (fpvalid) {
 		if (tsk == current)
diff -puN arch/i386/kernel/process.c~make-used_math-smp-safe arch/i386/kernel/process.c
--- 25/arch/i386/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.731462640 -0800
+++ 25-akpm/arch/i386/kernel/process.c	2005-01-22 23:05:59.792453368 -0800
@@ -351,7 +351,7 @@ void flush_thread(void)
 	 * Forget coprocessor state..
 	 */
 	clear_fpu(tsk);
-	tsk->used_math = 0;
+	clear_used_math();
 }
 
 void release_thread(struct task_struct *dead_task)
diff -puN arch/i386/kernel/ptrace.c~make-used_math-smp-safe arch/i386/kernel/ptrace.c
--- 25/arch/i386/kernel/ptrace.c~make-used_math-smp-safe	2005-01-22 23:05:59.732462488 -0800
+++ 25-akpm/arch/i386/kernel/ptrace.c	2005-01-22 23:05:59.793453216 -0800
@@ -592,7 +592,7 @@ asmlinkage int sys_ptrace(long request, 
 			break;
 		}
 		ret = 0;
-		if (!child->used_math)
+		if (!tsk_used_math(child))
 			init_fpu(child);
 		get_fpregs((struct user_i387_struct __user *)data, child);
 		break;
@@ -604,7 +604,7 @@ asmlinkage int sys_ptrace(long request, 
 			ret = -EIO;
 			break;
 		}
-		child->used_math = 1;
+		set_stopped_child_used_math(child);
 		set_fpregs(child, (struct user_i387_struct __user *)data);
 		ret = 0;
 		break;
@@ -616,7 +616,7 @@ asmlinkage int sys_ptrace(long request, 
 			ret = -EIO;
 			break;
 		}
-		if (!child->used_math)
+		if (!tsk_used_math(child))
 			init_fpu(child);
 		ret = get_fpxregs((struct user_fxsr_struct __user *)data, child);
 		break;
@@ -628,7 +628,7 @@ asmlinkage int sys_ptrace(long request, 
 			ret = -EIO;
 			break;
 		}
-		child->used_math = 1;
+		set_stopped_child_used_math(child);
 		ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data);
 		break;
 	}
diff -puN arch/i386/kernel/signal.c~make-used_math-smp-safe arch/i386/kernel/signal.c
--- 25/arch/i386/kernel/signal.c~make-used_math-smp-safe	2005-01-22 23:05:59.734462184 -0800
+++ 25-akpm/arch/i386/kernel/signal.c	2005-01-22 23:05:59.794453064 -0800
@@ -192,9 +192,9 @@ restore_sigcontext(struct pt_regs *regs,
 			err |= restore_i387(buf);
 		} else {
 			struct task_struct *me = current;
-			if (me->used_math) {
+			if (used_math()) {
 				clear_fpu(me);
-				me->used_math = 0;
+				clear_used_math();
 			}
 		}
 	}
diff -puN arch/i386/kernel/traps.c~make-used_math-smp-safe arch/i386/kernel/traps.c
--- 25/arch/i386/kernel/traps.c~make-used_math-smp-safe	2005-01-22 23:05:59.735462032 -0800
+++ 25-akpm/arch/i386/kernel/traps.c	2005-01-22 23:05:59.795452912 -0800
@@ -911,7 +911,7 @@ asmlinkage void math_state_restore(struc
 	struct task_struct *tsk = thread->task;
 
 	clts();		/* Allow maths ops (or we recurse) */
-	if (!tsk->used_math)
+	if (!tsk_used_math(tsk))
 		init_fpu(tsk);
 	restore_fpu(tsk);
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
diff -puN arch/i386/math-emu/fpu_entry.c~make-used_math-smp-safe arch/i386/math-emu/fpu_entry.c
--- 25/arch/i386/math-emu/fpu_entry.c~make-used_math-smp-safe	2005-01-22 23:05:59.737461728 -0800
+++ 25-akpm/arch/i386/math-emu/fpu_entry.c	2005-01-22 23:05:59.795452912 -0800
@@ -155,10 +155,10 @@ asmlinkage void math_emulate(long arg)
   RE_ENTRANT_CHECK_ON;
 #endif /* RE_ENTRANT_CHECKING */
 
-  if (!current->used_math)
+  if (!used_math())
     {
       finit();
-      current->used_math = 1;
+      set_used_math();
     }
 
   SETUP_DATA_AREA(arg);
diff -puN arch/ia64/ia32/elfcore32.h~make-used_math-smp-safe arch/ia64/ia32/elfcore32.h
--- 25/arch/ia64/ia32/elfcore32.h~make-used_math-smp-safe	2005-01-22 23:05:59.738461576 -0800
+++ 25-akpm/arch/ia64/ia32/elfcore32.h	2005-01-22 23:05:59.796452760 -0800
@@ -106,7 +106,7 @@ elf_core_copy_task_fpregs(struct task_st
 	struct ia32_user_i387_struct *fpstate = (void*)fpu;
 	mm_segment_t old_fs;
 
-	if (!tsk->used_math)
+	if (!tsk_used_math(tsk))
 		return 0;
 	
 	old_fs = get_fs();
@@ -124,7 +124,7 @@ elf_core_copy_task_xfpregs(struct task_s
 	struct ia32_user_fxsr_struct *fpxstate = (void*) xfpu;
 	mm_segment_t old_fs;
 
-	if (!tsk->used_math)
+	if (!tsk_used_math(tsk))
 		return 0;
 
 	old_fs = get_fs();
diff -puN arch/m32r/kernel/ptrace.c~make-used_math-smp-safe arch/m32r/kernel/ptrace.c
--- 25/arch/m32r/kernel/ptrace.c~make-used_math-smp-safe	2005-01-22 23:05:59.739461424 -0800
+++ 25-akpm/arch/m32r/kernel/ptrace.c	2005-01-22 23:05:59.797452608 -0800
@@ -130,7 +130,7 @@ static int ptrace_read_user(struct task_
 #ifndef NO_FPU
 		else if (off >= (long)(&dummy->fpu >> 2) &&
 			 off < (long)(&dummy->u_fpvalid >> 2)) {
-			if (!tsk->used_math) {
+			if (!tsk_used_math(tsk)) {
 				if (off == (long)(&dummy->fpu.fpscr >> 2))
 					tmp = FPSCR_INIT;
 				else
@@ -139,7 +139,7 @@ static int ptrace_read_user(struct task_
 				tmp = ((long *)(&tsk->thread.fpu >> 2))
 					[off - (long)&dummy->fpu];
 		} else if (off == (long)(&dummy->u_fpvalid >> 2))
-			tmp = tsk->used_math;
+			tmp = !!tsk_used_math(tsk);
 #endif /* not NO_FPU */
 		else
 			tmp = 0;
@@ -187,12 +187,12 @@ static int ptrace_write_user(struct task
 #ifndef NO_FPU
 		else if (off >= (long)(&dummy->fpu >> 2) &&
 			 off < (long)(&dummy->u_fpvalid >> 2)) {
-			tsk->used_math = 1;
+			set_stopped_child_used_math(tsk);
 			((long *)&tsk->thread.fpu)
 				[off - (long)&dummy->fpu] = data;
 			ret = 0;
 		} else if (off == (long)(&dummy->u_fpvalid >> 2)) {
-			tsk->used_math = data ? 1 : 0;
+			conditional_stopped_child_used_math(data, tsk);
 			ret = 0;
 		}
 #endif /* not NO_FPU */
diff -puN arch/m32r/kernel/setup.c~make-used_math-smp-safe arch/m32r/kernel/setup.c
--- 25/arch/m32r/kernel/setup.c~make-used_math-smp-safe	2005-01-22 23:05:59.741461120 -0800
+++ 25-akpm/arch/m32r/kernel/setup.c	2005-01-22 23:05:59.797452608 -0800
@@ -391,7 +391,7 @@ void __init cpu_init (void)
 
 	/* Force FPU initialization */
 	current_thread_info()->status = 0;
-	current->used_math = 0;
+	clear_used_math();
 
 #ifdef CONFIG_MMU
 	/* Set up MMU */
diff -puN arch/mips/kernel/irixsig.c~make-used_math-smp-safe arch/mips/kernel/irixsig.c
--- 25/arch/mips/kernel/irixsig.c~make-used_math-smp-safe	2005-01-22 23:05:59.742460968 -0800
+++ 25-akpm/arch/mips/kernel/irixsig.c	2005-01-22 23:05:59.798452456 -0800
@@ -99,7 +99,7 @@ static void setup_irix_frame(struct k_si
 	__put_user((u64) regs->hi, &ctx->hi);
 	__put_user((u64) regs->lo, &ctx->lo);
 	__put_user((u64) regs->cp0_epc, &ctx->pc);
-	__put_user(current->used_math, &ctx->usedfp);
+	__put_user(!!used_math(), &ctx->usedfp);
 	__put_user((u64) regs->cp0_cause, &ctx->cp0_cause);
 	__put_user((u64) regs->cp0_badvaddr, &ctx->cp0_badvaddr);
 
@@ -725,7 +725,7 @@ asmlinkage int irix_getcontext(struct pt
 	__put_user(regs->cp0_epc, &ctx->regs[35]);
 
 	flags = 0x0f;
-	if(!current->used_math) {
+	if(!used_math()) {
 		flags &= ~(0x08);
 	} else {
 		/* XXX wheee... */
diff -puN arch/mips/kernel/process.c~make-used_math-smp-safe arch/mips/kernel/process.c
--- 25/arch/mips/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.743460816 -0800
+++ 25-akpm/arch/mips/kernel/process.c	2005-01-22 23:05:59.798452456 -0800
@@ -76,7 +76,7 @@ void start_thread(struct pt_regs * regs,
 #endif
 	status |= KU_USER;
 	regs->cp0_status = status;
-	current->used_math = 0;
+	clear_used_math();
 	lose_fpu();
 	regs->cp0_epc = pc;
 	regs->regs[29] = sp;
diff -puN arch/mips/kernel/ptrace32.c~make-used_math-smp-safe arch/mips/kernel/ptrace32.c
--- 25/arch/mips/kernel/ptrace32.c~make-used_math-smp-safe	2005-01-22 23:05:59.744460664 -0800
+++ 25-akpm/arch/mips/kernel/ptrace32.c	2005-01-22 23:05:59.799452304 -0800
@@ -112,7 +112,7 @@ asmlinkage int sys32_ptrace(int request,
 			tmp = regs->regs[addr];
 			break;
 		case FPR_BASE ... FPR_BASE + 31:
-			if (child->used_math) {
+			if (tsk_used_math(child)) {
 				fpureg_t *fregs = get_fpu_regs(child);
 
 				/*
@@ -193,7 +193,7 @@ asmlinkage int sys32_ptrace(int request,
 		case FPR_BASE ... FPR_BASE + 31: {
 			fpureg_t *fregs = get_fpu_regs(child);
 
-			if (!child->used_math) {
+			if (!tsk_used_math(child)) {
 				/* FP not yet used  */
 				memset(&child->thread.fpu.hard, ~0,
 				       sizeof(child->thread.fpu.hard));
diff -puN arch/mips/kernel/ptrace.c~make-used_math-smp-safe arch/mips/kernel/ptrace.c
--- 25/arch/mips/kernel/ptrace.c~make-used_math-smp-safe	2005-01-22 23:05:59.746460360 -0800
+++ 25-akpm/arch/mips/kernel/ptrace.c	2005-01-22 23:05:59.799452304 -0800
@@ -119,7 +119,7 @@ asmlinkage int sys_ptrace(long request, 
 			tmp = regs->regs[addr];
 			break;
 		case FPR_BASE ... FPR_BASE + 31:
-			if (child->used_math) {
+			if (tsk_used_math(child)) {
 				fpureg_t *fregs = get_fpu_regs(child);
 
 #ifdef CONFIG_MIPS32
@@ -205,7 +205,7 @@ asmlinkage int sys_ptrace(long request, 
 		case FPR_BASE ... FPR_BASE + 31: {
 			fpureg_t *fregs = get_fpu_regs(child);
 
-			if (!child->used_math) {
+			if (!tsk_used_math(child)) {
 				/* FP not yet used  */
 				memset(&child->thread.fpu.hard, ~0,
 				       sizeof(child->thread.fpu.hard));
diff -puN arch/mips/kernel/signal32.c~make-used_math-smp-safe arch/mips/kernel/signal32.c
--- 25/arch/mips/kernel/signal32.c~make-used_math-smp-safe	2005-01-22 23:05:59.747460208 -0800
+++ 25-akpm/arch/mips/kernel/signal32.c	2005-01-22 23:05:59.800452152 -0800
@@ -361,11 +361,11 @@ static asmlinkage int restore_sigcontext
 	restore_gp_reg(31);
 #undef restore_gp_reg
 
-	err |= __get_user(current->used_math, &sc->sc_used_math);
+	err |= __get_user(!!used_math(), &sc->sc_used_math);
 
 	preempt_disable();
 
-	if (current->used_math) {
+	if (used_math()) {
 		/* restore fpu context if we have used it before */
 		own_fpu();
 		err |= restore_fp_context32(sc);
@@ -552,9 +552,9 @@ static inline int setup_sigcontext32(str
 	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
 	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
 
-	err |= __put_user(current->used_math, &sc->sc_used_math);
+	err |= __put_user(!!used_math(), &sc->sc_used_math);
 
-	if (!current->used_math)
+	if (!used_math())
 		goto out;
 
 	/* 
diff -puN arch/mips/kernel/signal.c~make-used_math-smp-safe arch/mips/kernel/signal.c
--- 25/arch/mips/kernel/signal.c~make-used_math-smp-safe	2005-01-22 23:05:59.749459904 -0800
+++ 25-akpm/arch/mips/kernel/signal.c	2005-01-22 23:05:59.801452000 -0800
@@ -178,11 +178,11 @@ asmlinkage int restore_sigcontext(struct
 	restore_gp_reg(31);
 #undef restore_gp_reg
 
-	err |= __get_user(current->used_math, &sc->sc_used_math);
+	err |= __get_user(!!used_math(), &sc->sc_used_math);
 
 	preempt_disable();
 
-	if (current->used_math) {
+	if (used_math()) {
 		/* restore fpu context if we have used it before */
 		own_fpu();
 		err |= restore_fp_context(sc);
@@ -323,9 +323,9 @@ inline int setup_sigcontext(struct pt_re
 	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
 	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
 
-	err |= __put_user(current->used_math, &sc->sc_used_math);
+	err |= __put_user(!!used_math(), &sc->sc_used_math);
 
-	if (!current->used_math)
+	if (!used_math())
 		goto out;
 
 	/*
diff -puN arch/mips/kernel/traps.c~make-used_math-smp-safe arch/mips/kernel/traps.c
--- 25/arch/mips/kernel/traps.c~make-used_math-smp-safe	2005-01-22 23:05:59.750459752 -0800
+++ 25-akpm/arch/mips/kernel/traps.c	2005-01-22 23:05:59.802451848 -0800
@@ -655,11 +655,11 @@ asmlinkage void do_cpu(struct pt_regs *r
 		preempt_disable();
 
 		own_fpu();
-		if (current->used_math) {	/* Using the FPU again.  */
+		if (used_math()) {	/* Using the FPU again.  */
 			restore_fp(current);
 		} else {			/* First time FPU user.  */
 			init_fpu();
-			current->used_math = 1;
+			set_used_math();
 		}
 
 		if (!cpu_has_fpu) {
diff -puN arch/s390/kernel/process.c~make-used_math-smp-safe arch/s390/kernel/process.c
--- 25/arch/s390/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.752459448 -0800
+++ 25-akpm/arch/s390/kernel/process.c	2005-01-22 23:05:59.802451848 -0800
@@ -215,8 +215,7 @@ void exit_thread(void)
 
 void flush_thread(void)
 {
-
-        current->used_math = 0;
+	clear_used_math();
 	clear_tsk_thread_flag(current, TIF_USEDFPU);
 }
 
diff -puN arch/s390/kernel/setup.c~make-used_math-smp-safe arch/s390/kernel/setup.c
--- 25/arch/s390/kernel/setup.c~make-used_math-smp-safe	2005-01-22 23:05:59.753459296 -0800
+++ 25-akpm/arch/s390/kernel/setup.c	2005-01-22 23:05:59.803451696 -0800
@@ -96,7 +96,7 @@ void __devinit cpu_init (void)
          * Force FPU initialization:
          */
         clear_thread_flag(TIF_USEDFPU);
-        current->used_math = 0;
+        clear_used_math();
 
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
diff -puN arch/sh64/kernel/fpu.c~make-used_math-smp-safe arch/sh64/kernel/fpu.c
--- 25/arch/sh64/kernel/fpu.c~make-used_math-smp-safe	2005-01-22 23:05:59.754459144 -0800
+++ 25-akpm/arch/sh64/kernel/fpu.c	2005-01-22 23:05:59.803451696 -0800
@@ -158,12 +158,12 @@ do_fpu_state_restore(unsigned long ex, s
 		fpsave(&last_task_used_math->thread.fpu.hard);
         }
         last_task_used_math = current;
-        if (current->used_math) {
+        if (used_math()) {
                 fpload(&current->thread.fpu.hard);
         } else {
 		/* First time FPU user.  */
 		fpload(&init_fpuregs.hard);
-                current->used_math = 1;
+                set_used_math();
         }
 	release_fpu();
 }
diff -puN arch/sh64/kernel/process.c~make-used_math-smp-safe arch/sh64/kernel/process.c
--- 25/arch/sh64/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.756458840 -0800
+++ 25-akpm/arch/sh64/kernel/process.c	2005-01-22 23:05:59.804451544 -0800
@@ -688,7 +688,7 @@ void flush_thread(void)
 		last_task_used_math = NULL;
 	}
 	/* Force FPU state to be reinitialised after exec */
-	current->used_math = 0;
+	clear_used_math();
 #endif
 
 	/* if we are a kernel thread, about to change to user thread,
@@ -713,7 +713,7 @@ int dump_fpu(struct pt_regs *regs, elf_f
 	int fpvalid;
 	struct task_struct *tsk = current;
 
-	fpvalid = tsk->used_math;
+	fpvalid = !!tsk_used_math(tsk);
 	if (fpvalid) {
 		if (current == last_task_used_math) {
 			grab_fpu();
diff -puN arch/sh64/kernel/ptrace.c~make-used_math-smp-safe arch/sh64/kernel/ptrace.c
--- 25/arch/sh64/kernel/ptrace.c~make-used_math-smp-safe	2005-01-22 23:05:59.757458688 -0800
+++ 25-akpm/arch/sh64/kernel/ptrace.c	2005-01-22 23:05:59.805451392 -0800
@@ -63,7 +63,7 @@ get_fpu_long(struct task_struct *task, u
 	struct pt_regs *regs;
 	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
 
-	if (!task->used_math) {
+	if (!tsk_used_math(task)) {
 		if (addr == offsetof(struct user_fpu_struct, fpscr)) {
 			tmp = FPSCR_INIT;
 		} else {
@@ -105,9 +105,9 @@ put_fpu_long(struct task_struct *task, u
 
 	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
 
-	if (!task->used_math) {
+	if (!tsk_used_math(task)) {
 		fpinit(&task->thread.fpu.hard);
-		task->used_math = 1;
+		set_stopped_child_used_math(task);
 	} else if (last_task_used_math == task) {
 		grab_fpu();
 		fpsave(&task->thread.fpu.hard);
@@ -187,7 +187,7 @@ asmlinkage int sys_ptrace(long request, 
 			 (addr <  offsetof(struct user, u_fpvalid))) {
 			tmp = get_fpu_long(child, addr - offsetof(struct user, fpu));
 		} else if (addr == offsetof(struct user, u_fpvalid)) {
-			tmp = child->used_math;
+			tmp = !!tsk_used_math(child);
 		} else {
 			break;
 		}
diff -puN arch/sh64/kernel/signal.c~make-used_math-smp-safe arch/sh64/kernel/signal.c
--- 25/arch/sh64/kernel/signal.c~make-used_math-smp-safe	2005-01-22 23:05:59.758458536 -0800
+++ 25-akpm/arch/sh64/kernel/signal.c	2005-01-22 23:05:59.806451240 -0800
@@ -186,7 +186,7 @@ restore_sigcontext_fpu(struct pt_regs *r
 	int fpvalid;
 
 	err |= __get_user (fpvalid, &sc->sc_fpvalid);
-	current->used_math = fpvalid;
+	conditional_used_math(fpvalid);
 	if (! fpvalid)
 		return err;
 
@@ -207,7 +207,7 @@ setup_sigcontext_fpu(struct pt_regs *reg
 	int err = 0;
 	int fpvalid;
 
-	fpvalid = current->used_math;
+	fpvalid = !!used_math();
 	err |= __put_user(fpvalid, &sc->sc_fpvalid);
 	if (! fpvalid)
 		return err;
@@ -222,7 +222,7 @@ setup_sigcontext_fpu(struct pt_regs *reg
 
 	err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.fpu.hard,
 			      (sizeof(long long) * 32) + (sizeof(int) * 1));
-	current->used_math = 0;
+	clear_used_math();
 
 	return err;
 }
diff -puN arch/sh/kernel/cpu/init.c~make-used_math-smp-safe arch/sh/kernel/cpu/init.c
--- 25/arch/sh/kernel/cpu/init.c~make-used_math-smp-safe	2005-01-22 23:05:59.760458232 -0800
+++ 25-akpm/arch/sh/kernel/cpu/init.c	2005-01-22 23:05:59.806451240 -0800
@@ -194,7 +194,7 @@ asmlinkage void __init sh_cpu_init(void)
 	/* FPU initialization */
 	if ((cpu_data->flags & CPU_HAS_FPU)) {
 		clear_thread_flag(TIF_USEDFPU);
-		current->used_math = 0;
+		clear_used_math();
 	}
 
 #ifdef CONFIG_SH_DSP
diff -puN arch/sh/kernel/cpu/sh4/fpu.c~make-used_math-smp-safe arch/sh/kernel/cpu/sh4/fpu.c
--- 25/arch/sh/kernel/cpu/sh4/fpu.c~make-used_math-smp-safe	2005-01-22 23:05:59.761458080 -0800
+++ 25-akpm/arch/sh/kernel/cpu/sh4/fpu.c	2005-01-22 23:05:59.807451088 -0800
@@ -323,13 +323,13 @@ do_fpu_state_restore(unsigned long r4, u
 		return;
 	}
 
-	if (tsk->used_math) {
+	if (used_math()) {
 		/* Using the FPU again.  */
 		restore_fpu(tsk);
 	} else	{
 		/* First time FPU user.  */
 		fpu_init();
-		tsk->used_math = 1;
+		set_used_math();
 	}
 	set_tsk_thread_flag(tsk, TIF_USEDFPU);
 }
diff -puN arch/sh/kernel/process.c~make-used_math-smp-safe arch/sh/kernel/process.c
--- 25/arch/sh/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.762457928 -0800
+++ 25-akpm/arch/sh/kernel/process.c	2005-01-22 23:05:59.807451088 -0800
@@ -208,7 +208,7 @@ void flush_thread(void)
 
 	/* Forget lazy FPU state */
 	clear_fpu(tsk, regs);
-	tsk->used_math = 0;
+	clear_used_math();
 #endif
 }
 
@@ -225,7 +225,7 @@ int dump_fpu(struct pt_regs *regs, elf_f
 #if defined(CONFIG_SH_FPU)
 	struct task_struct *tsk = current;
 
-	fpvalid = tsk->used_math;
+	fpvalid = !!tsk_used_math(tsk);
 	if (fpvalid) {
 		unlazy_fpu(tsk, regs);
 		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
@@ -260,7 +260,7 @@ dump_task_fpu (struct task_struct *tsk, 
 	int fpvalid = 0;
 
 #if defined(CONFIG_SH_FPU)
-	fpvalid = tsk->used_math;
+	fpvalid = !!tsk_used_math(tsk);
 	if (fpvalid) {
 		struct pt_regs *regs = (struct pt_regs *)
 					((unsigned long)tsk->thread_info
@@ -286,7 +286,7 @@ int copy_thread(int nr, unsigned long cl
 
 	unlazy_fpu(tsk, regs);
 	p->thread.fpu = tsk->thread.fpu;
-	p->used_math = tsk->used_math;
+	copy_to_stopped_child_used_math(p);
 #endif
 
 	childregs = ((struct pt_regs *)
diff -puN arch/sh/kernel/ptrace.c~make-used_math-smp-safe arch/sh/kernel/ptrace.c
--- 25/arch/sh/kernel/ptrace.c~make-used_math-smp-safe	2005-01-22 23:05:59.764457624 -0800
+++ 25-akpm/arch/sh/kernel/ptrace.c	2005-01-22 23:05:59.808450936 -0800
@@ -150,7 +150,7 @@ asmlinkage int sys_ptrace(long request, 
 			tmp = get_stack_long(child, addr);
 		else if (addr >= (long) &dummy->fpu &&
 			 addr < (long) &dummy->u_fpvalid) {
-			if (!child->used_math) {
+			if (!tsk_used_math(child)) {
 				if (addr == (long)&dummy->fpu.fpscr)
 					tmp = FPSCR_INIT;
 				else
@@ -159,7 +159,7 @@ asmlinkage int sys_ptrace(long request, 
 				tmp = ((long *)&child->thread.fpu)
 					[(addr - (long)&dummy->fpu) >> 2];
 		} else if (addr == (long) &dummy->u_fpvalid)
-			tmp = child->used_math;
+			tmp = !!tsk_used_math(child);
 		else
 			tmp = 0;
 		ret = put_user(tmp, (unsigned long *)data);
@@ -185,12 +185,12 @@ asmlinkage int sys_ptrace(long request, 
 			ret = put_stack_long(child, addr, data);
 		else if (addr >= (long) &dummy->fpu &&
 			 addr < (long) &dummy->u_fpvalid) {
-			child->used_math = 1;
+			set_stopped_child_used_math(child);
 			((long *)&child->thread.fpu)
 				[(addr - (long)&dummy->fpu) >> 2] = data;
 			ret = 0;
 		} else if (addr == (long) &dummy->u_fpvalid) {
-			child->used_math = data?1:0;
+			conditional_stopped_child_used_math(data, child);
 			ret = 0;
 		}
 		break;
diff -puN arch/sh/kernel/signal.c~make-used_math-smp-safe arch/sh/kernel/signal.c
--- 25/arch/sh/kernel/signal.c~make-used_math-smp-safe	2005-01-22 23:05:59.765457472 -0800
+++ 25-akpm/arch/sh/kernel/signal.c	2005-01-22 23:05:59.809450784 -0800
@@ -162,7 +162,7 @@ static inline int restore_sigcontext_fpu
 	if (!(cpu_data->flags & CPU_HAS_FPU))
 		return 0;
 
-	tsk->used_math = 1;
+	set_used_math();
 	return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
 				sizeof(long)*(16*2+2));
 }
@@ -175,7 +175,7 @@ static inline int save_sigcontext_fpu(st
 	if (!(cpu_data->flags & CPU_HAS_FPU))
 		return 0;
 
-	if (!tsk->used_math) {
+	if (!used_math()) {
 		__put_user(0, &sc->sc_ownedfp);
 		return 0;
 	}
@@ -185,7 +185,7 @@ static inline int save_sigcontext_fpu(st
 	/* This will cause a "finit" to be triggered by the next
 	   attempted FPU operation by the 'current' process.
 	   */
-	tsk->used_math = 0;
+	clear_used_math();
 
 	unlazy_fpu(tsk, regs);
 	return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
@@ -219,7 +219,7 @@ restore_sigcontext(struct pt_regs *regs,
 
 		regs->sr |= SR_FD; /* Release FPU */
 		clear_fpu(tsk, regs);
-		tsk->used_math = 0;
+		clear_used_math();
 		__get_user (owned_fp, &sc->sc_ownedfp);
 		if (owned_fp)
 			err |= restore_sigcontext_fpu(sc);
diff -puN arch/sparc/kernel/process.c~make-used_math-smp-safe arch/sparc/kernel/process.c
--- 25/arch/sparc/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.766457320 -0800
+++ 25-akpm/arch/sparc/kernel/process.c	2005-01-22 23:05:59.810450632 -0800
@@ -599,7 +599,7 @@ void dump_thread(struct pt_regs * regs, 
  */
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 {
-	if (current->used_math == 0) {
+	if (used_math()) {
 		memset(fpregs, 0, sizeof(*fpregs));
 		fpregs->pr_q_entrysize = 8;
 		return 1;
diff -puN arch/sparc/kernel/signal.c~make-used_math-smp-safe arch/sparc/kernel/signal.c
--- 25/arch/sparc/kernel/signal.c~make-used_math-smp-safe	2005-01-22 23:05:59.768457016 -0800
+++ 25-akpm/arch/sparc/kernel/signal.c	2005-01-22 23:05:59.811450480 -0800
@@ -202,7 +202,7 @@ restore_fpu_state(struct pt_regs *regs, 
 		regs->psr &= ~PSR_EF;
 	}
 #endif
-	current->used_math = 1;
+	set_used_math();
 	clear_tsk_thread_flag(current, TIF_USEDFPU);
 
 	if (verify_area(VERIFY_READ, fpu, sizeof(*fpu)))
@@ -584,7 +584,7 @@ save_fpu_state(struct pt_regs *regs, __s
 				      &current->thread.fpqueue[0],
 				      ((sizeof(unsigned long) +
 				      (sizeof(unsigned long *)))*16));
-	current->used_math = 0;
+	clear_used_math();
 	return err;
 }
 
@@ -599,7 +599,7 @@ new_setup_frame(struct k_sigaction *ka, 
 	synchronize_user_stack();
 
 	sigframe_size = NF_ALIGNEDSZ;
-	if (!current->used_math)
+	if (!used_math())
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 
 	sf = (struct new_signal_frame __user *)
@@ -616,7 +616,7 @@ new_setup_frame(struct k_sigaction *ka, 
 	
 	err |= __put_user(0, &sf->extra_size);
 
-	if (current->used_math) {
+	if (used_math()) {
 		err |= save_fpu_state(regs, &sf->fpu_state);
 		err |= __put_user(&sf->fpu_state, &sf->fpu_save);
 	} else {
@@ -677,7 +677,7 @@ new_setup_rt_frame(struct k_sigaction *k
 
 	synchronize_user_stack();
 	sigframe_size = RT_ALIGNEDSZ;
-	if (!current->used_math)
+	if (!used_math())
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 	sf = (struct rt_signal_frame __user *)
 		get_sigframe(&ka->sa, regs, sigframe_size);
@@ -690,7 +690,7 @@ new_setup_rt_frame(struct k_sigaction *k
 	err |= __put_user(regs->npc, &sf->regs.npc);
 	err |= __put_user(regs->y, &sf->regs.y);
 	psr = regs->psr;
-	if (current->used_math)
+	if (used_math())
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sf->regs.psr);
 	err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
diff -puN arch/sparc/kernel/traps.c~make-used_math-smp-safe arch/sparc/kernel/traps.c
--- 25/arch/sparc/kernel/traps.c~make-used_math-smp-safe	2005-01-22 23:05:59.769456864 -0800
+++ 25-akpm/arch/sparc/kernel/traps.c	2005-01-22 23:05:59.812450328 -0800
@@ -246,17 +246,17 @@ void do_fpd_trap(struct pt_regs *regs, u
 		       &fptask->thread.fpqueue[0], &fptask->thread.fpqdepth);
 	}
 	last_task_used_math = current;
-	if(current->used_math) {
+	if(used_math()) {
 		fpload(&current->thread.float_regs[0], &current->thread.fsr);
 	} else {
 		/* Set initial sane state. */
 		fpload(&init_fregs[0], &init_fsr);
-		current->used_math = 1;
+		set_used_math();
 	}
 #else
-	if(!current->used_math) {
+	if(!used_math()) {
 		fpload(&init_fregs[0], &init_fsr);
-		current->used_math = 1;
+		set_used_math();
 	} else {
 		fpload(&current->thread.float_regs[0], &current->thread.fsr);
 	}
diff -puN arch/x86_64/ia32/fpu32.c~make-used_math-smp-safe arch/x86_64/ia32/fpu32.c
--- 25/arch/x86_64/ia32/fpu32.c~make-used_math-smp-safe	2005-01-22 23:05:59.771456560 -0800
+++ 25-akpm/arch/x86_64/ia32/fpu32.c	2005-01-22 23:05:59.812450328 -0800
@@ -157,7 +157,7 @@ int restore_i387_ia32(struct task_struct
 				     sizeof(struct i387_fxsave_struct)))
 			return -1;
 		tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
-		tsk->used_math = 1;
+		set_stopped_child_used_math(tsk);
 	} 
 	return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
 }  
diff -puN arch/x86_64/ia32/ia32_binfmt.c~make-used_math-smp-safe arch/x86_64/ia32/ia32_binfmt.c
--- 25/arch/x86_64/ia32/ia32_binfmt.c~make-used_math-smp-safe	2005-01-22 23:05:59.772456408 -0800
+++ 25-akpm/arch/x86_64/ia32/ia32_binfmt.c	2005-01-22 23:05:59.813450176 -0800
@@ -214,7 +214,7 @@ elf_core_copy_task_fpregs(struct task_st
 	struct _fpstate_ia32 *fpstate = (void*)fpu; 
 	mm_segment_t oldfs = get_fs();
 
-	if (!tsk->used_math) 
+	if (!tsk_used_math(tsk))
 		return 0;
 	if (!regs)
 		regs = (struct pt_regs *)tsk->thread.rsp0;
@@ -235,7 +235,7 @@ static inline int 
 elf_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregset_t *xfpu)
 {
 	struct pt_regs *regs = ((struct pt_regs *)(t->thread.rsp0))-1; 
-	if (!t->used_math) 
+	if (!tsk_used_math(t))
 		return 0;
 	if (t == current)
 		unlazy_fpu(t); 
diff -puN arch/x86_64/ia32/ia32_signal.c~make-used_math-smp-safe arch/x86_64/ia32/ia32_signal.c
--- 25/arch/x86_64/ia32/ia32_signal.c~make-used_math-smp-safe	2005-01-22 23:05:59.773456256 -0800
+++ 25-akpm/arch/x86_64/ia32/ia32_signal.c	2005-01-22 23:05:59.813450176 -0800
@@ -263,9 +263,9 @@ ia32_restore_sigcontext(struct pt_regs *
 			err |= restore_i387_ia32(current, buf, 0);
 		} else {
 			struct task_struct *me = current;
-			if (me->used_math) {
+			if (used_math()) {
 				clear_fpu(me);
-				me->used_math = 0;
+				clear_used_math();
 			}
 		}
 	}
@@ -389,7 +389,7 @@ ia32_setup_sigcontext(struct sigcontext_
 	if (tmp < 0)
 	  err = -EFAULT;
 	else { 
-		current->used_math = 0;
+		clear_used_math();
 		stts();
 	  err |= __put_user((u32)(u64)(tmp ? fpstate : NULL), &sc->fpstate);
 	}
diff -puN arch/x86_64/ia32/ptrace32.c~make-used_math-smp-safe arch/x86_64/ia32/ptrace32.c
--- 25/arch/x86_64/ia32/ptrace32.c~make-used_math-smp-safe	2005-01-22 23:05:59.775455952 -0800
+++ 25-akpm/arch/x86_64/ia32/ptrace32.c	2005-01-22 23:05:59.814450024 -0800
@@ -358,7 +358,7 @@ asmlinkage long sys32_ptrace(long reques
 			break;
 		/* no checking to be bug-to-bug compatible with i386 */
 		__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
-		child->used_math = 1;
+		set_stopped_child_used_math(child);
 		child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
 		ret = 0; 
 		break;
diff -puN arch/x86_64/kernel/i387.c~make-used_math-smp-safe arch/x86_64/kernel/i387.c
--- 25/arch/x86_64/kernel/i387.c~make-used_math-smp-safe	2005-01-22 23:05:59.776455800 -0800
+++ 25-akpm/arch/x86_64/kernel/i387.c	2005-01-22 23:05:59.814450024 -0800
@@ -57,12 +57,12 @@ void __init fpu_init(void)
 	mxcsr_feature_mask_init();
 	/* clean state in init */
 	current_thread_info()->status = 0;
-	current->used_math = 0;
+	clear_used_math();
 }
 
 void init_fpu(struct task_struct *child)
 {
-	if (child->used_math) { 
+	if (tsk_used_math(child)) {
 		if (child == current)
 			unlazy_fpu(child);
 		return;
@@ -70,7 +70,8 @@ void init_fpu(struct task_struct *child)
 	memset(&child->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
 	child->thread.i387.fxsave.cwd = 0x37f;
 	child->thread.i387.fxsave.mxcsr = 0x1f80;
-	child->used_math = 1;
+	/* only the device not available exception or ptrace can call init_fpu */
+	set_stopped_child_used_math(child);
 }
 
 /*
@@ -91,9 +92,9 @@ int save_i387(struct _fpstate __user *bu
 	if ((unsigned long)buf % 16) 
 		printk("save_i387: bad fpstate %p\n",buf); 
 
-	if (!tsk->used_math) 
+	if (!used_math())
 		return 0;
-	tsk->used_math = 0; /* trigger finit */ 
+	clear_used_math(); /* trigger finit */
 	if (tsk->thread_info->status & TS_USEDFPU) {
 		err = save_i387_checking((struct i387_fxsave_struct __user *)buf);
 		if (err) return err;
@@ -133,7 +134,7 @@ int dump_fpu( struct pt_regs *regs, stru
 {
 	struct task_struct *tsk = current;
 
-	if (!tsk->used_math) 
+	if (!used_math())
 		return 0;
 
 	unlazy_fpu(tsk);
@@ -143,7 +144,7 @@ int dump_fpu( struct pt_regs *regs, stru
 
 int dump_task_fpu(struct task_struct *tsk, struct user_i387_struct *fpu)
 {
-	int fpvalid = tsk->used_math;
+	int fpvalid = !!tsk_used_math(tsk);
 
 	if (fpvalid) {
 		if (tsk == current)
diff -puN arch/x86_64/kernel/process.c~make-used_math-smp-safe arch/x86_64/kernel/process.c
--- 25/arch/x86_64/kernel/process.c~make-used_math-smp-safe	2005-01-22 23:05:59.777455648 -0800
+++ 25-akpm/arch/x86_64/kernel/process.c	2005-01-22 23:05:59.815449872 -0800
@@ -314,7 +314,7 @@ void flush_thread(void)
 	 * Forget coprocessor state..
 	 */
 	clear_fpu(tsk);
-	tsk->used_math = 0;
+	clear_used_math();
 }
 
 void release_thread(struct task_struct *dead_task)
diff -puN arch/x86_64/kernel/ptrace.c~make-used_math-smp-safe arch/x86_64/kernel/ptrace.c
--- 25/arch/x86_64/kernel/ptrace.c~make-used_math-smp-safe	2005-01-22 23:05:59.779455344 -0800
+++ 25-akpm/arch/x86_64/kernel/ptrace.c	2005-01-22 23:05:59.816449720 -0800
@@ -480,7 +480,7 @@ asmlinkage long sys_ptrace(long request,
 			ret = -EIO;
 			break;
 		}
-		child->used_math = 1;
+		set_stopped_child_used_math(child);
 		ret = set_fpregs(child, (struct user_i387_struct __user *)data);
 		break;
 	}
diff -puN arch/x86_64/kernel/signal.c~make-used_math-smp-safe arch/x86_64/kernel/signal.c
--- 25/arch/x86_64/kernel/signal.c~make-used_math-smp-safe	2005-01-22 23:05:59.780455192 -0800
+++ 25-akpm/arch/x86_64/kernel/signal.c	2005-01-22 23:05:59.816449720 -0800
@@ -126,9 +126,9 @@ restore_sigcontext(struct pt_regs *regs,
 			err |= restore_i387(buf);
 		} else {
 			struct task_struct *me = current;
-			if (me->used_math) {
+			if (used_math()) {
 				clear_fpu(me);
-				me->used_math = 0;
+				clear_used_math();
 			}
 		}
 	}
@@ -251,7 +251,7 @@ static void setup_rt_frame(int sig, stru
 	int err = 0;
 	struct task_struct *me = current;
 
-	if (me->used_math) {
+	if (used_math()) {
 		fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
 		frame = (void __user *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
diff -puN arch/x86_64/kernel/traps.c~make-used_math-smp-safe arch/x86_64/kernel/traps.c
--- 25/arch/x86_64/kernel/traps.c~make-used_math-smp-safe	2005-01-22 23:05:59.781455040 -0800
+++ 25-akpm/arch/x86_64/kernel/traps.c	2005-01-22 23:05:59.817449568 -0800
@@ -901,7 +901,7 @@ asmlinkage void math_state_restore(void)
 	struct task_struct *me = current;
 	clts();			/* Allow maths ops (or we recurse) */
 
-	if (!me->used_math)
+	if (!used_math())
 		init_fpu(me);
 	restore_fpu_checking(&me->thread.i387.fxsave);
 	me->thread_info->status |= TS_USEDFPU;
diff -puN include/asm-arm26/constants.h~make-used_math-smp-safe include/asm-arm26/constants.h
--- 25/include/asm-arm26/constants.h~make-used_math-smp-safe	2005-01-22 23:05:59.783454736 -0800
+++ 25-akpm/include/asm-arm26/constants.h	2005-01-22 23:05:59.817449568 -0800
@@ -7,7 +7,6 @@
  *
  */
 
-#define TSK_USED_MATH 788 /* offsetof(struct task_struct, used_math) */
 #define TSK_ACTIVE_MM 96 /* offsetof(struct task_struct, active_mm) */
 
 #define VMA_VM_MM 0 /* offsetof(struct vm_area_struct, vm_mm) */
diff -puN include/asm-x86_64/i387.h~make-used_math-smp-safe include/asm-x86_64/i387.h
--- 25/include/asm-x86_64/i387.h~make-used_math-smp-safe	2005-01-22 23:05:59.784454584 -0800
+++ 25-akpm/include/asm-x86_64/i387.h	2005-01-22 23:05:59.818449416 -0800
@@ -25,16 +25,6 @@ extern void mxcsr_feature_mask_init(void
 extern void init_fpu(struct task_struct *child);
 extern int save_i387(struct _fpstate __user *buf);
 
-static inline int need_signal_i387(struct task_struct *me) 
-{ 
-	if (!me->used_math)
-		return 0;
-	me->used_math = 0; 
-	if (me->thread_info->status & TS_USEDFPU)
-		return 0;
-	return 1;
-} 
-
 /*
  * FPU lazy state save handling...
  */
diff -puN include/linux/sched.h~make-used_math-smp-safe include/linux/sched.h
--- 25/include/linux/sched.h~make-used_math-smp-safe	2005-01-22 23:05:59.785454432 -0800
+++ 25-akpm/include/linux/sched.h	2005-01-22 23:05:59.819449264 -0800
@@ -614,19 +614,7 @@ struct task_struct {
 	struct key *process_keyring;	/* keyring private to this process (CLONE_THREAD) */
 	struct key *thread_keyring;	/* keyring private to this thread */
 #endif
-/*
- * Must be changed atomically so it shouldn't be
- * be a shareable bitflag.
- */
-	unsigned char used_math;
-/*
- * OOM kill score adjustment (bit shift).
- * Cannot live together with used_math since
- * used_math and oomkilladj can be changed at the
- * same time, so they would race if they're in the
- * same atomic block.
- */
-	short oomkilladj;
+	int oomkilladj; /* OOM kill score adjustment (bit shift). */
 	char comm[TASK_COMM_LEN];
 /* file system info */
 	int link_count, total_link_count;
@@ -695,7 +683,7 @@ struct task_struct {
 #endif
 #ifdef CONFIG_NUMA
   	struct mempolicy *mempolicy;
-  	short il_next;		/* could be shared with used_math */
+	short il_next;
 #endif
 };
 
@@ -737,7 +725,7 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_SIGNALED	0x00000400	/* killed by a signal */
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_FLUSHER	0x00001000	/* responsible for disk writeback */
-
+#define PF_USED_MATH	0x00002000	/* if unset the fpu must be initialized before use */
 #define PF_FREEZE	0x00004000	/* this task is being frozen for suspend now */
 #define PF_NOFREEZE	0x00008000	/* this thread should not be frozen */
 #define PF_FROZEN	0x00010000	/* frozen for system suspend */
@@ -748,6 +736,31 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
 #define PF_BORROWED_MM	0x00400000	/* I am a kthread doing use_mm */
 
+/*
+ * Only the _current_ task can read/write to tsk->flags, but other
+ * tasks can access tsk->flags in readonly mode for example
+ * with tsk_used_math (like during threaded core dumping).
+ * There is however an exception to this rule during ptrace
+ * or during fork: the ptracer task is allowed to write to the
+ * child->flags of its traced child (same goes for fork, the parent
+ * can write to the child->flags), because we're guaranteed the
+ * child is not running and in turn not changing child->flags
+ * at the same time the parent does it.
+ */
+#define clear_stopped_child_used_math(child) do { (child)->flags &= ~PF_USED_MATH; } while (0)
+#define set_stopped_child_used_math(child) do { (child)->flags |= PF_USED_MATH; } while (0)
+#define clear_used_math() clear_stopped_child_used_math(current)
+#define set_used_math() set_stopped_child_used_math(current)
+#define conditional_stopped_child_used_math(condition, child) \
+	do { (child)->flags &= ~PF_USED_MATH, (child)->flags |= (condition) ? PF_USED_MATH : 0; } while (0)
+#define conditional_used_math(condition) \
+	conditional_stopped_child_used_math(condition, current)
+#define copy_to_stopped_child_used_math(child) \
+	do { (child)->flags &= ~PF_USED_MATH, (child)->flags |= current->flags & PF_USED_MATH; } while (0)
+/* NOTE: this will return 0 or PF_USED_MATH, it will never return 1 */
+#define tsk_used_math(p) ((p)->flags & PF_USED_MATH)
+#define used_math() tsk_used_math(current)
+
 #ifdef CONFIG_SMP
 extern int set_cpus_allowed(task_t *p, cpumask_t new_mask);
 #else
_