Re: [PATCH] fix possible sleeping in atomic on setup/restore sigcontext

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>>>>> On Thu, 13 Oct 2005 15:04:15 +0100, Ralf Baechle <ralf@xxxxxxxxxxxxxx> said:
ralf> I think much of the 87d54649f67d8ffe0a8d8176de8c210a6c4bb4a7
ralf> preemption patch is flawed and the problem you were trying to
ralf> fix are in part just caused by it.

Well... the patch fixed some problem because preempt_disable/enable is
actually needed for lazy fpu switch, but some of the fixes was wrong
(as I wrote at that time ;-)).

Anyway, I create an another patch by rewriting
restore_fp_context/save_fp_context.  While thread.fpu.hard and
thread.fpu.soft are completely same, things are quite simple.

Description:
The setup_sigcontect/restore_sigcontext might sleep on
put_user/get_user with preemption disabled (i.e. atomic context).
Sleeping in atomic context is not allowed.  This patch fixes this
problem rewriting restore_fp_context/save_fp_context.

fp context saving path is:
BEFORE:  (thread.fpu -> ) real FPU -> sigcontext
AFTER:  (real FPU -> ) thread.fpu -> sigcontext

 arch/mips/kernel/signal-common.h    |   56 +++++++++++++++++++++------
 arch/mips/kernel/signal32.c         |   54 ++++++++++++++++++++------
 arch/mips/kernel/traps.c            |   54 --------------------------
 arch/mips/math-emu/kernel_linkage.c |   73 ------------------------------------ include/asm-mips/fpu.h              |    9 ----
 5 files changed, 86 insertions(+), 160 deletions(-)

Then we can remove all arch/mips/kernel/*_fpu.S and some (all?) SC_
symbols from asm-offset.c file.

Signed-off-by: Atsushi Nemoto <anemo@xxxxxxxxxxxxx>

diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
--- a/arch/mips/kernel/signal-common.h
+++ b/arch/mips/kernel/signal-common.h
@@ -10,6 +10,42 @@
 
 #include <linux/config.h>
 
+/*
+ * Emulator context save/restore to/from a signal context
+ * presumed to be on the user stack, and therefore accessed
+ * with appropriate macros from uaccess.h
+ */
+
+static inline int save_fp_context(struct sigcontext *sc)
+{
+	int i;
+	int err = 0;
+
+	for (i = 0; i < 32; i++) {
+		err |=
+		    __put_user(current->thread.fpu.soft.fpr[i],
+			       &sc->sc_fpregs[i]);
+	}
+	err |= __put_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
+
+	return err;
+}
+
+static inline int restore_fp_context(struct sigcontext *sc)
+{
+	int i;
+	int err = 0;
+
+	for (i = 0; i < 32; i++) {
+		err |=
+		    __get_user(current->thread.fpu.soft.fpr[i],
+			       &sc->sc_fpregs[i]);
+	}
+	err |= __get_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
+
+	return err;
+}
+
 static inline int
 setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
 {
@@ -68,15 +104,14 @@ setup_sigcontext(struct pt_regs *regs, s
 	 * current FPU state.
 	 */
 	preempt_disable();
-
-	if (!is_fpu_owner()) {
-		own_fpu();
-		restore_fp(current);
+	if (is_fpu_owner()) {
+		/* save current context to task_struct */
+		save_fp(current);
+		/* no need to call lose_fpu here. */
 	}
-	err |= save_fp_context(sc);
-
 	preempt_enable();
 
+	err |= save_fp_context(sc);
 out:
 	return err;
 }
@@ -138,19 +173,16 @@ restore_sigcontext(struct pt_regs *regs,
 	err |= __get_user(used_math, &sc->sc_used_math);
 	conditional_used_math(used_math);
 
+	/* signal handler may have used FPU.  Give it up. */
 	preempt_disable();
+	lose_fpu();
+	preempt_enable();
 
 	if (used_math()) {
 		/* restore fpu context if we have used it before */
-		own_fpu();
 		err |= restore_fp_context(sc);
-	} else {
-		/* signal handler may have used FPU.  Give it up. */
-		lose_fpu();
 	}
 
-	preempt_enable();
-
 	return err;
 }
 
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -335,6 +335,40 @@ asmlinkage int sys32_sigaltstack(nabi_no
 	return ret;
 }
 
+/*
+ * This is the o32 version
+ */
+
+static inline int save_fp_context32(struct sigcontext32 *sc)
+{
+	int i;
+	int err = 0;
+
+	for (i = 0; i < 32; i+=2) {
+		err |=
+		    __put_user(current->thread.fpu.soft.fpr[i],
+			       &sc->sc_fpregs[i]);
+	}
+	err |= __put_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
+
+	return err;
+}
+
+static inline int restore_fp_context32(struct sigcontext32 *sc)
+{
+	int i;
+	int err = 0;
+
+	for (i = 0; i < 32; i+=2) {
+		err |=
+		    __get_user(current->thread.fpu.soft.fpr[i],
+			       &sc->sc_fpregs[i]);
+	}
+	err |= __get_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
+
+	return err;
+}
+
 static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc)
 {
 	u32 used_math;
@@ -376,19 +410,16 @@ static int restore_sigcontext32(struct p
 	err |= __get_user(used_math, &sc->sc_used_math);
 	conditional_used_math(used_math);
 
+	/* signal handler may have used FPU.  Give it up. */
 	preempt_disable();
+	lose_fpu();
+	preempt_enable();
 
 	if (used_math()) {
 		/* restore fpu context if we have used it before */
-		own_fpu();
 		err |= restore_fp_context32(sc);
-	} else {
-		/* signal handler may have used FPU.  Give it up. */
-		lose_fpu();
 	}
 
-	preempt_enable();
-
 	return err;
 }
 
@@ -609,15 +640,14 @@ static inline int setup_sigcontext32(str
 	 * current FPU state.
 	 */
 	preempt_disable();
-
-	if (!is_fpu_owner()) {
-		own_fpu();
-		restore_fp(current);
+	if (is_fpu_owner()) {
+		/* save current context to task_struct */
+		save_fp(current);
+		/* no need to call lose_fpu here. */
 	}
-	err |= save_fp_context32(sc);
-
 	preempt_enable();
 
+	err |= save_fp_context32(sc);
 out:
 	return err;
 }
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1098,55 +1098,6 @@ void *set_vi_handler (int n, void *addr)
 }
 #endif
 
-/*
- * This is used by native signal handling
- */
-asmlinkage int (*save_fp_context)(struct sigcontext *sc);
-asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
-
-extern asmlinkage int _save_fp_context(struct sigcontext *sc);
-extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
-
-extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
-extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
-
-static inline void signal_init(void)
-{
-	if (cpu_has_fpu) {
-		save_fp_context = _save_fp_context;
-		restore_fp_context = _restore_fp_context;
-	} else {
-		save_fp_context = fpu_emulator_save_context;
-		restore_fp_context = fpu_emulator_restore_context;
-	}
-}
-
-#ifdef CONFIG_MIPS32_COMPAT
-
-/*
- * This is used by 32-bit signal stuff on the 64-bit kernel
- */
-asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc);
-asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc);
-
-extern asmlinkage int _save_fp_context32(struct sigcontext32 *sc);
-extern asmlinkage int _restore_fp_context32(struct sigcontext32 *sc);
-
-extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 *sc);
-extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 *sc);
-
-static inline void signal32_init(void)
-{
-	if (cpu_has_fpu) {
-		save_fp_context32 = _save_fp_context32;
-		restore_fp_context32 = _restore_fp_context32;
-	} else {
-		save_fp_context32 = fpu_emulator_save_context32;
-		restore_fp_context32 = fpu_emulator_restore_context32;
-	}
-}
-#endif
-
 extern void cpu_cache_init(void);
 extern void tlb_init(void);
 
@@ -1350,10 +1301,5 @@ void __init trap_init(void)
 	else
 		memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80);
 
-	signal_init();
-#ifdef CONFIG_MIPS32_COMPAT
-	signal32_init();
-#endif
-
 	flush_icache_range(ebase, ebase + 0x400);
 }
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -44,76 +44,3 @@ void fpu_emulator_init_fpu(void)
 		current->thread.fpu.soft.fpr[i] = SIGNALLING_NAN;
 	}
 }
-
-
-/*
- * Emulator context save/restore to/from a signal context
- * presumed to be on the user stack, and therefore accessed
- * with appropriate macros from uaccess.h
- */
-
-int fpu_emulator_save_context(struct sigcontext *sc)
-{
-	int i;
-	int err = 0;
-
-	for (i = 0; i < 32; i++) {
-		err |=
-		    __put_user(current->thread.fpu.soft.fpr[i],
-			       &sc->sc_fpregs[i]);
-	}
-	err |= __put_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
-
-	return err;
-}
-
-int fpu_emulator_restore_context(struct sigcontext *sc)
-{
-	int i;
-	int err = 0;
-
-	for (i = 0; i < 32; i++) {
-		err |=
-		    __get_user(current->thread.fpu.soft.fpr[i],
-			       &sc->sc_fpregs[i]);
-	}
-	err |= __get_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
-
-	return err;
-}
-
-#ifdef CONFIG_64BIT
-/*
- * This is the o32 version
- */
-
-int fpu_emulator_save_context32(struct sigcontext32 *sc)
-{
-	int i;
-	int err = 0;
-
-	for (i = 0; i < 32; i+=2) {
-		err |=
-		    __put_user(current->thread.fpu.soft.fpr[i],
-			       &sc->sc_fpregs[i]);
-	}
-	err |= __put_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
-
-	return err;
-}
-
-int fpu_emulator_restore_context32(struct sigcontext32 *sc)
-{
-	int i;
-	int err = 0;
-
-	for (i = 0; i < 32; i+=2) {
-		err |=
-		    __get_user(current->thread.fpu.soft.fpr[i],
-			       &sc->sc_fpregs[i]);
-	}
-	err |= __get_user(current->thread.fpu.soft.fcr31, &sc->sc_fpc_csr);
-
-	return err;
-}
-#endif
diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h
--- a/include/asm-mips/fpu.h
+++ b/include/asm-mips/fpu.h
@@ -21,15 +21,6 @@
 #include <asm/processor.h>
 #include <asm/current.h>
 
-struct sigcontext;
-struct sigcontext32;
-
-extern asmlinkage int (*save_fp_context)(struct sigcontext *sc);
-extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
-
-extern asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc);
-extern asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc);
-
 extern void fpu_emulator_init_fpu(void);
 extern void _init_fpu(void);
 extern void _save_fp(struct task_struct *);


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux