From 55ccf3fe3f9a3441731aa79cf42a628fc4ecace9 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Wed, 16 May 2012 15:03:51 -0700 Subject: fork: move the real prepare_to_copy() users to arch_dup_task_struct() Historical prepare_to_copy() is mostly a no-op, duplicated for majority of the architectures and the rest following the x86 model of flushing the extended register state like fpu there. Remove it and use the arch_dup_task_struct() instead. Suggested-by: Oleg Nesterov Suggested-by: Linus Torvalds Signed-off-by: Suresh Siddha Link: http://lkml.kernel.org/r/1336692811-30576-1-git-send-email-suresh.b.siddha@intel.com Acked-by: Benjamin Herrenschmidt Cc: David Howells Cc: Koichi Yasutake Cc: Paul Mackerras Cc: Paul Mundt Cc: Chris Zankel Cc: Richard Henderson Cc: Russell King Cc: Haavard Skinnemoen Cc: Mike Frysinger Cc: Mark Salter Cc: Aurelien Jacquiot Cc: Mikael Starvik Cc: Yoshinori Sato Cc: Richard Kuo Cc: Tony Luck Cc: Michal Simek Cc: Ralf Baechle Cc: Jonas Bonn Cc: James E.J. Bottomley Cc: Helge Deller Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: Chen Liqin Cc: Lennox Wu Cc: David S. Miller Cc: Chris Metcalf Cc: Jeff Dike Cc: Richard Weinberger Cc: Guan Xuetao Signed-off-by: H. Peter Anvin --- arch/alpha/include/asm/processor.h | 3 --- arch/arm/include/asm/processor.h | 3 --- arch/avr32/include/asm/processor.h | 3 --- arch/blackfin/include/asm/processor.h | 2 -- arch/c6x/include/asm/processor.h | 3 --- arch/cris/include/asm/processor.h | 4 ---- arch/frv/include/asm/processor.h | 2 -- arch/frv/kernel/process.c | 11 ----------- arch/h8300/include/asm/processor.h | 2 -- arch/hexagon/include/asm/processor.h | 7 ------- arch/ia64/include/asm/processor.h | 3 --- arch/m32r/include/asm/processor.h | 2 -- arch/m68k/include/asm/processor.h | 3 --- arch/microblaze/include/asm/processor.h | 1 - arch/mips/include/asm/processor.h | 3 --- arch/mn10300/include/asm/processor.h | 3 --- arch/mn10300/kernel/process.c | 10 ++++++---- arch/openrisc/include/asm/processor.h | 4 ---- arch/parisc/include/asm/processor.h | 3 --- arch/powerpc/include/asm/processor.h | 3 --- arch/powerpc/kernel/process.c | 19 +++++++++++-------- arch/s390/include/asm/processor.h | 3 --- arch/score/include/asm/processor.h | 1 - arch/sh/include/asm/processor_32.h | 3 --- arch/sh/include/asm/processor_64.h | 1 - arch/sh/kernel/process.c | 7 +++++++ arch/sh/kernel/process_32.c | 9 --------- arch/sparc/include/asm/processor_32.h | 3 --- arch/sparc/include/asm/processor_64.h | 3 --- arch/tile/include/asm/processor.h | 3 --- arch/um/include/asm/processor-generic.h | 5 ----- arch/unicore32/include/asm/processor.h | 3 --- arch/x86/include/asm/processor.h | 3 --- arch/x86/kernel/process.c | 6 ++++++ arch/x86/kernel/process_32.c | 9 --------- arch/x86/kernel/process_64.c | 9 --------- arch/xtensa/include/asm/processor.h | 3 --- arch/xtensa/kernel/process.c | 9 ++++++--- kernel/fork.c | 2 -- 39 files changed, 36 insertions(+), 140 deletions(-) diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h index 94afe5859301..e37b887b3d9f 100644 --- a/arch/alpha/include/asm/processor.h +++ b/arch/alpha/include/asm/processor.h @@ -49,9 +49,6 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long); /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - /* Create a kernel thread without removing it from tasklists. */ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 5ac8d3d3e025..6354224f980d 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -77,9 +77,6 @@ struct task_struct; /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - unsigned long get_wchan(struct task_struct *p); #if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327) diff --git a/arch/avr32/include/asm/processor.h b/arch/avr32/include/asm/processor.h index 108502bc6770..87d8baccc60e 100644 --- a/arch/avr32/include/asm/processor.h +++ b/arch/avr32/include/asm/processor.h @@ -145,9 +145,6 @@ extern void release_thread(struct task_struct *); /* Create a kernel thread without removing it from tasklists */ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while(0) - /* Return saved PC of a blocked thread */ #define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc) diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h index 8af7772e84cc..4ef7cfe43ceb 100644 --- a/arch/blackfin/include/asm/processor.h +++ b/arch/blackfin/include/asm/processor.h @@ -75,8 +75,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -#define prepare_to_copy(tsk) do { } while (0) - extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags); /* diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h index 3ff7fab956ba..c50af7ef1c96 100644 --- a/arch/c6x/include/asm/processor.h +++ b/arch/c6x/include/asm/processor.h @@ -92,9 +92,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); #define copy_segments(tsk, mm) do { } while (0) diff --git a/arch/cris/include/asm/processor.h b/arch/cris/include/asm/processor.h index 4210d72a6667..37f522feabc1 100644 --- a/arch/cris/include/asm/processor.h +++ b/arch/cris/include/asm/processor.h @@ -50,10 +50,6 @@ struct task_struct; #define task_pt_regs(task) user_regs(task_thread_info(task)) #define current_regs() task_pt_regs(current) -static inline void prepare_to_copy(struct task_struct *tsk) -{ -} - extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); unsigned long get_wchan(struct task_struct *p); diff --git a/arch/frv/include/asm/processor.h b/arch/frv/include/asm/processor.h index 81c2e271d620..9c768170b304 100644 --- a/arch/frv/include/asm/processor.h +++ b/arch/frv/include/asm/processor.h @@ -103,8 +103,6 @@ do { \ __frame->sp = (_usp); \ } while(0) -extern void prepare_to_copy(struct task_struct *tsk); - /* Free all resources held by a thread. */ static inline void release_thread(struct task_struct *dead_task) { diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index d4de48bd5efe..9f3dfadee09e 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -180,17 +180,6 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, return do_fork(clone_flags, newsp, __frame, 0, parent_tidptr, child_tidptr); } /* end sys_clone() */ -/*****************************************************************************/ -/* - * This gets called before we allocate a new thread and copy - * the current task into it. - */ -void prepare_to_copy(struct task_struct *tsk) -{ - //unlazy_fpu(tsk); -} /* end prepare_to_copy() */ - -/*****************************************************************************/ /* * set up the kernel stack and exception frames for a new process */ diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h index 61fabf1788c6..4c9f6f87b617 100644 --- a/arch/h8300/include/asm/processor.h +++ b/arch/h8300/include/asm/processor.h @@ -109,8 +109,6 @@ static inline void release_thread(struct task_struct *dead_task) extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -#define prepare_to_copy(tsk) do { } while (0) - /* * Free current thread data structures etc.. */ diff --git a/arch/hexagon/include/asm/processor.h b/arch/hexagon/include/asm/processor.h index 20c5ddabbd8b..e8ea459002a4 100644 --- a/arch/hexagon/include/asm/processor.h +++ b/arch/hexagon/include/asm/processor.h @@ -58,13 +58,6 @@ struct thread_struct { #define cpu_relax() __vmyield() -/* - * "Unlazying all lazy status" occurs here. - */ -static inline void prepare_to_copy(struct task_struct *tsk) -{ -} - /* * Decides where the kernel will search for a free chunk of vm space during * mmaps. diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h index 483f6c6a4238..efcca1b601c5 100644 --- a/arch/ia64/include/asm/processor.h +++ b/arch/ia64/include/asm/processor.h @@ -343,9 +343,6 @@ struct task_struct; */ #define release_thread(dead_task) -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - /* * This is the mechanism for creating a new kernel thread. * diff --git a/arch/m32r/include/asm/processor.h b/arch/m32r/include/asm/processor.h index e1f46d757460..da17253b5735 100644 --- a/arch/m32r/include/asm/processor.h +++ b/arch/m32r/include/asm/processor.h @@ -118,8 +118,6 @@ struct mm_struct; /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -#define prepare_to_copy(tsk) do { } while (0) - /* * create a kernel thread without removing it from tasklists */ diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index 46460fa15d5c..f17c42aff7ff 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -153,9 +153,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index bffb54527299..af2bb9652392 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h @@ -23,7 +23,6 @@ extern const struct seq_operations cpuinfo_op; # define cpu_relax() barrier() # define cpu_sleep() do {} while (0) -# define prepare_to_copy(tsk) do {} while (0) #define task_pt_regs(tsk) \ (((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 20e9dcf42b27..5e33fabe354d 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -310,9 +310,6 @@ struct task_struct; /* Free all resources held by a thread. */ #define release_thread(thread) do { } while(0) -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern unsigned long thread_saved_pc(struct task_struct *tsk); diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h index f7b3c9ab2cb5..247928c9f549 100644 --- a/arch/mn10300/include/asm/processor.h +++ b/arch/mn10300/include/asm/processor.h @@ -139,9 +139,6 @@ static inline void start_thread(struct pt_regs *regs, /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -/* Prepare to copy thread state - unlazy all lazy status */ -extern void prepare_to_copy(struct task_struct *tsk); - /* * create a kernel thread without removing it from tasklists */ diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 14707f25153b..7dab0cd36466 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -208,12 +208,14 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm) } /* - * this gets called before we allocate a new thread and copy the current task - * into it so that we can store lazy state into memory + * this gets called so that we can store lazy state into memory and copy the + * current task into the new thread. */ -void prepare_to_copy(struct task_struct *tsk) +int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { - unlazy_fpu(tsk); + unlazy_fpu(src); + *dst = *src; + return 0; } /* diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h index f7516fa78b58..30462f1fe959 100644 --- a/arch/openrisc/include/asm/processor.h +++ b/arch/openrisc/include/asm/processor.h @@ -72,10 +72,6 @@ struct thread_struct { #define task_pt_regs(task) user_regs(task_thread_info(task)) #define current_regs() user_regs(current_thread_info()) -extern inline void prepare_to_copy(struct task_struct *tsk) -{ -} - #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) #define INIT_THREAD { } diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index acdf4cad6125..0e8b7b8ce8a2 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h @@ -328,9 +328,6 @@ struct mm_struct; extern void release_thread(struct task_struct *); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm); extern unsigned long get_wchan(struct task_struct *p); diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 8e2d0371fe1e..854f899d0c34 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -74,9 +74,6 @@ struct task_struct; void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp); void release_thread(struct task_struct *); -/* Prepare to copy thread state - unlazy all lazy status */ -extern void prepare_to_copy(struct task_struct *tsk); - /* Create a new kernel thread. */ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 4937c9690090..bc129f24e11f 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -711,18 +711,21 @@ release_thread(struct task_struct *t) } /* - * This gets called before we allocate a new thread and copy - * the current task into it. + * this gets called so that we can store coprocessor state into memory and + * copy the current task into the new thread. */ -void prepare_to_copy(struct task_struct *tsk) +int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { - flush_fp_to_thread(current); - flush_altivec_to_thread(current); - flush_vsx_to_thread(current); - flush_spe_to_thread(current); + flush_fp_to_thread(src); + flush_altivec_to_thread(src); + flush_vsx_to_thread(src); + flush_spe_to_thread(src); #ifdef CONFIG_HAVE_HW_BREAKPOINT - flush_ptrace_hw_breakpoint(tsk); + flush_ptrace_hw_breakpoint(src); #endif /* CONFIG_HAVE_HW_BREAKPOINT */ + + *dst = *src; + return 0; } /* diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index d499b30ea487..6cbf31311673 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -141,9 +141,6 @@ struct seq_file; extern void release_thread(struct task_struct *); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - /* * Return saved PC of a blocked thread. */ diff --git a/arch/score/include/asm/processor.h b/arch/score/include/asm/processor.h index 7e22f216d771..ab3aceb54209 100644 --- a/arch/score/include/asm/processor.h +++ b/arch/score/include/asm/processor.h @@ -26,7 +26,6 @@ extern unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() #define release_thread(thread) do {} while (0) -#define prepare_to_copy(tsk) do {} while (0) /* * User space process size: 2GB. This is hardcoded into a few places, diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 900f8d72ffe2..b6311fd2d066 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -126,9 +126,6 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned lo /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -/* Prepare to copy thread state - unlazy all lazy status */ -void prepare_to_copy(struct task_struct *tsk); - /* * create a kernel thread without removing it from tasklists */ diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index e25c4c7d6b63..fe99afecfbc5 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h @@ -172,7 +172,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); #define copy_segments(p, mm) do { } while (0) #define release_segments(mm) do { } while (0) #define forget_segments() do { } while (0) -#define prepare_to_copy(tsk) do { } while (0) /* * FPU lazy state save handling. */ diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 325f98b1736d..2bde59eae10d 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -6,8 +6,15 @@ struct kmem_cache *task_xstate_cachep = NULL; unsigned int xstate_size; +/* + * this gets called so that we can store lazy state into memory and copy the + * current task into the new thread. + */ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { +#ifdef CONFIG_SUPERH32 + unlazy_fpu(src, task_pt_regs(src)); +#endif *dst = *src; if (src->thread.xstate) { diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 94273aaf78c1..dee596113cc1 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -155,15 +155,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) } EXPORT_SYMBOL(dump_fpu); -/* - * This gets called before we allocate a new thread and copy - * the current task into it. - */ -void prepare_to_copy(struct task_struct *tsk) -{ - unlazy_fpu(tsk, task_pt_regs(tsk)); -} - asmlinkage void ret_from_fork(void); int copy_thread(unsigned long clone_flags, unsigned long usp, diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h index 09521c6a5edb..c9c760fdc713 100644 --- a/arch/sparc/include/asm/processor_32.h +++ b/arch/sparc/include/asm/processor_32.h @@ -109,9 +109,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, #define release_thread(tsk) do { } while(0) extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - extern unsigned long get_wchan(struct task_struct *); #define task_pt_regs(tsk) ((tsk)->thread.kregs) diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index e713db249931..67df5cc10011 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h @@ -186,9 +186,6 @@ do { \ /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while (0) -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern unsigned long get_wchan(struct task_struct *task); diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index 34c1e01ffb5e..15cd8a4a06ce 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h @@ -210,9 +210,6 @@ static inline void release_thread(struct task_struct *dead_task) /* Nothing for now */ } -/* Prepare to copy thread state - unlazy all lazy status. */ -#define prepare_to_copy(tsk) do { } while (0) - extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); extern int do_work_pending(struct pt_regs *regs, u32 flags); diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index 98d01bc4fa92..63b716052d20 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h @@ -76,11 +76,6 @@ static inline void release_thread(struct task_struct *task) extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -static inline void prepare_to_copy(struct task_struct *tsk) -{ -} - - extern unsigned long thread_saved_pc(struct task_struct *t); static inline void mm_copy_segments(struct mm_struct *from_mm, diff --git a/arch/unicore32/include/asm/processor.h b/arch/unicore32/include/asm/processor.h index f0d780a51f9b..14382cb09657 100644 --- a/arch/unicore32/include/asm/processor.h +++ b/arch/unicore32/include/asm/processor.h @@ -68,9 +68,6 @@ struct task_struct; /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 4fa7dcceb6c0..97fe04318e95 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -579,9 +579,6 @@ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -/* Prepare to copy thread state - unlazy all lazy state */ -extern void prepare_to_copy(struct task_struct *tsk); - unsigned long get_wchan(struct task_struct *p); /* diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 1d92a5ab6e8b..b7e1e0e53987 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -47,10 +47,16 @@ EXPORT_SYMBOL_GPL(idle_notifier_unregister); struct kmem_cache *task_xstate_cachep; EXPORT_SYMBOL_GPL(task_xstate_cachep); +/* + * this gets called so that we can store lazy state into memory and copy the + * current task into the new thread. + */ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { int ret; + unlazy_fpu(src); + *dst = *src; if (fpu_allocated(&src->thread.fpu)) { memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu)); diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index ae6847303e26..2aa57dc909d6 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -126,15 +126,6 @@ void release_thread(struct task_struct *dead_task) release_vm86_irqs(dead_task); } -/* - * This gets called before we allocate a new thread and copy - * the current task into it. - */ -void prepare_to_copy(struct task_struct *tsk) -{ - unlazy_fpu(tsk); -} - int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 43d8b48b23e6..c4c0645a4011 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -145,15 +145,6 @@ static inline u32 read_32bit_tls(struct task_struct *t, int tls) return get_desc_base(&t->thread.tls_array[tls]); } -/* - * This gets called before we allocate a new thread and copy - * the current task into it. - */ -void prepare_to_copy(struct task_struct *tsk) -{ - unlazy_fpu(tsk); -} - int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 3acb26e8dead..5c371d8d4528 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -168,9 +168,6 @@ struct mm_struct; /* Free all resources held by a thread. */ #define release_thread(thread) do { } while(0) -/* Prepare to copy thread state - unlazy all lazy status */ -extern void prepare_to_copy(struct task_struct*); - /* Create a kernel thread without removing it from tasklists */ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 6a2d6edf8f72..9b306e550e3f 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -140,13 +140,16 @@ void flush_thread(void) } /* - * This is called before the thread is copied. + * this gets called so that we can store coprocessor state into memory and + * copy the current task into the new thread. */ -void prepare_to_copy(struct task_struct *tsk) +int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { #if XTENSA_HAVE_COPROCESSORS - coprocessor_flush_all(task_thread_info(tsk)); + coprocessor_flush_all(task_thread_info(src)); #endif + *dst = *src; + return 0; } /* diff --git a/kernel/fork.c b/kernel/fork.c index 687a15d56243..7aed746ff47c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -261,8 +261,6 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) int node = tsk_fork_get_node(orig); int err; - prepare_to_copy(orig); - tsk = alloc_task_struct_node(node); if (!tsk) return NULL; -- cgit v1.2.3 From 11aeca0b3a083a457f5c34fe8c677d5e86a0c6b3 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Wed, 16 May 2012 15:03:52 -0700 Subject: coredump: ensure the fpu state is flushed for proper multi-threaded core dump Nalluru reported hitting the BUG_ON(__thread_has_fpu(tsk)) in arch/x86/kernel/xsave.c:__sanitize_i387_state() during the coredump of a multi-threaded application. A look at the exit seqeuence shows that other threads can still be on the runqueue potentially at the below shown exit_mm() code snippet: if (atomic_dec_and_test(&core_state->nr_threads)) complete(&core_state->startup); ===> other threads can still be active here, but we notify the thread ===> dumping core to wakeup from the coredump_wait() after the last thread ===> joins this point. Core dumping thread will continue dumping ===> all the threads state to the core file. for (;;) { set_task_state(tsk, TASK_UNINTERRUPTIBLE); if (!self.task) /* see coredump_finish() */ break; schedule(); } As some of those threads are on the runqueue and didn't call schedule() yet, their fpu state is still active in the live registers and the thread proceeding with the coredump will hit the above mentioned BUG_ON while trying to dump other threads fpustate to the coredump file. BUG_ON() in arch/x86/kernel/xsave.c:__sanitize_i387_state() is in the code paths for processors supporting xsaveopt. With or without xsaveopt, multi-threaded coredump is broken and maynot contain the correct fpustate at the time of exit. In coredump_wait(), wait for all the threads to be come inactive, so that we are sure all the extended register state is flushed to the memory, so that it can be reliably copied to the core file. Reported-by: Suresh Nalluru Signed-off-by: Suresh Siddha Link: http://lkml.kernel.org/r/1336692811-30576-2-git-send-email-suresh.b.siddha@intel.com Acked-by: Oleg Nesterov Signed-off-by: H. Peter Anvin --- fs/exec.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/exec.c b/fs/exec.c index b1fd2025e59a..8e2ddebaccdd 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1930,8 +1930,21 @@ static int coredump_wait(int exit_code, struct core_state *core_state) core_waiters = zap_threads(tsk, mm, core_state, exit_code); up_write(&mm->mmap_sem); - if (core_waiters > 0) + if (core_waiters > 0) { + struct core_thread *ptr; + wait_for_completion(&core_state->startup); + /* + * Wait for all the threads to become inactive, so that + * all the thread context (extended register state, like + * fpu etc) gets copied to the memory. + */ + ptr = core_state->dumper.next; + while (ptr != NULL) { + wait_task_inactive(ptr->task, 0); + ptr = ptr->next; + } + } return core_waiters; } -- cgit v1.2.3 From d75f1b391f5ef73016d14bc6f7e4725820ebaa5b Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Wed, 16 May 2012 15:03:53 -0700 Subject: x86, xsave: remove thread_has_fpu() bug check in __sanitize_i387_state() Code paths like fork(), exit() and signal handling flush the fpu state explicitly to the structures in memory. BUG_ON() in __sanitize_i387_state() is checking that the fpu state is not live any more. But for preempt kernels, task can be scheduled out and in at any place and the preload_fpu logic during context switch can make the fpu registers live again. For example, consider a 64-bit Task which uses fpu frequently and as such you will find its fpu_counter mostly non-zero. During its time slice, kernel used fpu by doing kernel_fpu_begin/kernel_fpu_end(). After this, in the same scheduling slice, task-A got a signal to handle. Then during the signal setup path we got preempted when we are just before the sanitize_i387_state() in arch/x86/kernel/xsave.c:save_i387_xstate(). And when we come back we will have the fpu registers live that can hit the bug_on. Similarly during core dump, other threads can context-switch in and out (because of spurious wakeups while waiting for the coredump to finish in kernel/exit.c:exit_mm()) and the main thread dumping core can run into this bug when it finds some other thread with its fpu registers live on some other cpu. So remove the paranoid check for now, even though it caught a bug in the multi-threaded core dump case (fixed in the previous patch). Signed-off-by: Suresh Siddha Link: http://lkml.kernel.org/r/1336692811-30576-3-git-send-email-suresh.b.siddha@intel.com Cc: Oleg Nesterov Cc: Linus Torvalds Signed-off-by: H. Peter Anvin --- arch/x86/kernel/xsave.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index e62728e30b01..bd18149b2b0f 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -48,8 +48,6 @@ void __sanitize_i387_state(struct task_struct *tsk) if (!fx) return; - BUG_ON(__thread_has_fpu(tsk)); - xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv; /* -- cgit v1.2.3 From 1dcc8d7ba235a316a056f993e88f0d18b92c60d9 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Wed, 16 May 2012 15:03:54 -0700 Subject: x86, fpu: drop the fpu state during thread exit There is no need to save any active fpu state to the task structure memory if the task is dead. Just drop the state instead. For example, this saved some 1770 xsave's during the system boot of a two socket Xeon system. Suggested-by: Linus Torvalds Signed-off-by: Suresh Siddha Link: http://lkml.kernel.org/r/1336692811-30576-4-git-send-email-suresh.b.siddha@intel.com Cc: Oleg Nesterov Signed-off-by: H. Peter Anvin --- arch/x86/kernel/process.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b7e1e0e53987..1219fe2be8f3 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -87,6 +87,16 @@ void arch_task_cache_init(void) SLAB_PANIC | SLAB_NOTRACK, NULL); } +static inline void drop_fpu(struct task_struct *tsk) +{ + /* + * Forget coprocessor state.. + */ + tsk->fpu_counter = 0; + clear_fpu(tsk); + clear_used_math(); +} + /* * Free current thread data structures etc.. */ @@ -109,6 +119,8 @@ void exit_thread(void) put_cpu(); kfree(bp); } + + drop_fpu(me); } void show_regs(struct pt_regs *regs) @@ -149,12 +161,7 @@ void flush_thread(void) flush_ptrace_hw_breakpoint(tsk); memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); - /* - * Forget coprocessor state.. - */ - tsk->fpu_counter = 0; - clear_fpu(tsk); - clear_used_math(); + drop_fpu(tsk); } static void hard_disable_TSC(void) -- cgit v1.2.3