Skip to contentSkip to conversation

x86, fpu: misc fixes/cleanups, more to come

PATCH New Oleg Nesterov 2 participants 15 messages Sep 2, 2014 x86

lore
Share & tools
lore
#0 lore raw

cover x86, fpu: misc fixes/cleanups, more to come

Peter, please consider this series for inclusion.

I added v2 tag to avoid the confusion but the patches are the same, except the new/offtopic but hopefully trivial 7/7.

2-6 were acked by Suresh (thanks!), the 1st patch still has no acks although iiuc Linus seems to agree with this change.

Oleg.

 arch/x86/include/asm/fpu-internal.h |    2 +-
 arch/x86/kernel/process.c           |   16 +++++++++-------
 arch/x86/kernel/process_32.c        |    6 +-----
 arch/x86/kernel/process_64.c        |    3 ---
 arch/x86/kernel/signal.c            |    5 +++++
 arch/x86/kernel/xsave.c             |    7 ++++---
 6 files changed, 20 insertions(+), 19 deletions(-)
#1 lore raw

PATCH v2 1/7 x86, fpu: shift drop_init_fpu() from save_xstate_sig() to handle_signal()

save_xstate_sig()->drop_init_fpu() doesn't look right. setup_rt_frame() can fail after that, in this case the next setup_rt_frame() triggered by SIGSEGV won't save fpu simply because the old state was lost. This obviously mean that fpu won't be restored after sys_rt_sigreturn() from SIGSEGV handler.

Shift drop_init_fpu() into !failed branch in handle_signal().

Test-case (needs -O2):

	#include <stdio.h>
	#include <signal.h>
	#include <unistd.h>
	#include <sys/syscall.h>
	#include <sys/mman.h>
	#include <pthread.h>
	#include <assert.h>

	volatile double D;

	void test(double d)
	{
		int pid = getpid();

		for (D = d; D == d; ) {
			/* sys_tkill(pid, SIGHUP); asm to avoid save/reload
			 * fp regs around "C" call */
			asm ("" : : "a"(200), "D"(pid), "S"(1));
			asm ("syscall" : : : "ax");
		}

		printf("ERR!!\n");
	}

	void sigh(int sig)
	{
	}

	char altstack[4096 * 10] __attribute__((aligned(4096)));

	void *tfunc(void *arg)
	{
		for (;;) {
			mprotect(altstack, sizeof(altstack), PROT_READ);
			mprotect(altstack, sizeof(altstack), PROT_READ|PROT_WRITE);
		}
	}

	int main(void)
	{
		stack_t st = {
			.ss_sp = altstack,
			.ss_size = sizeof(altstack),
			.ss_flags = SS_ONSTACK,
		};

		struct sigaction sa = {
			.sa_handler = sigh,
		};

		pthread_t pt;

		sigaction(SIGSEGV, &sa, NULL);
		sigaltstack(&st, NULL);
		sa.sa_flags = SA_ONSTACK;
		sigaction(SIGHUP, &sa, NULL);

		pthread_create(&pt, NULL, tfunc, NULL);

		test(123.456);
		return 0;
	}
---
 arch/x86/kernel/signal.c |    5 +++++
 arch/x86/kernel/xsave.c  |    2 --
 2 files changed, 5 insertions(+), 2 deletions(-)
arch/x86/kernel/signal.c +5 -0
index 2851d63..ed37a76 100644
@@ -675,6 +675,11 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 		 * handler too.
 		 */
 		regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF);
+		/*
+		 * Ensure the signal handler starts with the new fpu state.
+		 */
+		if (used_math())
+			drop_init_fpu(current);
 	}
 	signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP));
 }
arch/x86/kernel/xsave.c +0 -2
index a4b451c..74b34c2 100644
@@ -268,8 +268,6 @@ int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
 	if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
 		return -1;
 
-	drop_init_fpu(tsk);	/* trigger finit */
-
 	return 0;
 }
 
Signature · 1 line
1.5.5.1
#2 lore raw

[tip:x86/fpu] x86, fpu: shift drop_init_fpu() from save_xstate_sig() to handle_signal()

x86, fpu: shift drop_init_fpu() from save_xstate_sig() to handle_signal()
Commit-ID:  66463db4fc5605d51c7bb81d009d5bf30a783a2c
Gitweb:     http://git.kernel.org/tip/66463db4fc5605d51c7bb81d009d5bf30a783a2c
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Tue, 2 Sep 2014 19:57:13 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 2 Sep 2014 14:51:14 -0700

x86, fpu: shift drop_init_fpu() from save_xstate_sig() to handle_signal()

save_xstate_sig()->drop_init_fpu() doesn't look right. setup_rt_frame() can fail after that, in this case the next setup_rt_frame() triggered by SIGSEGV won't save fpu simply because the old state was lost. This obviously mean that fpu won't be restored after sys_rt_sigreturn() from SIGSEGV handler.

Shift drop_init_fpu() into !failed branch in handle_signal().

Test-case (needs -O2):

	#include <stdio.h>
	#include <signal.h>
	#include <unistd.h>
	#include <sys/syscall.h>
	#include <sys/mman.h>
	#include <pthread.h>
	#include <assert.h>

	volatile double D;

	void test(double d)
	{
		int pid = getpid();

		for (D = d; D == d; ) {
			/* sys_tkill(pid, SIGHUP); asm to avoid save/reload
			 * fp regs around "C" call */
			asm ("" : : "a"(200), "D"(pid), "S"(1));
			asm ("syscall" : : : "ax");
		}

		printf("ERR!!\n");
	}

	void sigh(int sig)
	{
	}

	char altstack[4096 * 10] __attribute__((aligned(4096)));

	void *tfunc(void *arg)
	{
		for (;;) {
			mprotect(altstack, sizeof(altstack), PROT_READ);
			mprotect(altstack, sizeof(altstack), PROT_READ|PROT_WRITE);
		}
	}

	int main(void)
	{
		stack_t st = {
			.ss_sp = altstack,
			.ss_size = sizeof(altstack),
			.ss_flags = SS_ONSTACK,
		};

		struct sigaction sa = {
			.sa_handler = sigh,
		};

		pthread_t pt;

		sigaction(SIGSEGV, &sa, NULL);
		sigaltstack(&st, NULL);
		sa.sa_flags = SA_ONSTACK;
		sigaction(SIGHUP, &sa, NULL);

		pthread_create(&pt, NULL, tfunc, NULL);

		test(123.456);
		return 0;
	}
---
 arch/x86/kernel/signal.c | 5 +++++
 arch/x86/kernel/xsave.c  | 2 --
 2 files changed, 5 insertions(+), 2 deletions(-)
arch/x86/kernel/signal.c +5 -0
index 2851d63..ed37a76 100644
@@ -675,6 +675,11 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 		 * handler too.
 		 */
 		regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF);
+		/*
+		 * Ensure the signal handler starts with the new fpu state.
+		 */
+		if (used_math())
+			drop_init_fpu(current);
 	}
 	signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP));
 }
arch/x86/kernel/xsave.c +0 -2
index 940b142..cf0b830 100644
@@ -271,8 +271,6 @@ int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
 	if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
 		return -1;
 
-	drop_init_fpu(tsk);	/* trigger finit */
-
 	return 0;
 }
 
#3 lore raw

PATCH v2 2/7 x86, fpu: __restore_xstate_sig()->math_state_restore() needs preempt_disable()

In reply to Oleg Nesterov

Add preempt_disable() + preempt_enable() around math_state_restore() in __restore_xstate_sig(). Otherwise __switch_to() after __thread_fpu_begin() can overwrite fpu->state we are going to restore.

---
 arch/x86/kernel/xsave.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)
arch/x86/kernel/xsave.c +4 -1
index 74b34c2..dd50e26 100644
@@ -397,8 +397,11 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
 			set_used_math();
 		}
 
-		if (use_eager_fpu())
+		if (use_eager_fpu()) {
+			preempt_disable();
 			math_state_restore();
+			preempt_enable();
+		}
 
 		return err;
 	} else {
Signature · 1 line
1.5.5.1
#4 lore raw

[tip:x86/fpu] x86, fpu: __restore_xstate_sig()-> math_state_restore() needs preempt_disable()

x86, fpu: __restore_xstate_sig()->math_state_restore() needs preempt_disable()
Commit-ID:  df24fb859a4e200d9324e2974229fbb7adf00aef
Gitweb:     http://git.kernel.org/tip/df24fb859a4e200d9324e2974229fbb7adf00aef
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Tue, 2 Sep 2014 19:57:17 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 2 Sep 2014 14:51:15 -0700

x86, fpu: __restore_xstate_sig()->math_state_restore() needs preempt_disable()

Add preempt_disable() + preempt_enable() around math_state_restore() in __restore_xstate_sig(). Otherwise __switch_to() after __thread_fpu_begin() can overwrite fpu->state we are going to restore.

---
 arch/x86/kernel/xsave.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/x86/kernel/xsave.c +4 -1
index cf0b830..4c540c4 100644
@@ -400,8 +400,11 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
 			set_used_math();
 		}
 
-		if (use_eager_fpu())
+		if (use_eager_fpu()) {
+			preempt_disable();
 			math_state_restore();
+			preempt_enable();
+		}
 
 		return err;
 	} else {
#5 lore raw

PATCH v2 3/7 x86, fpu: change __thread_fpu_begin() to use use_eager_fpu()

In reply to Oleg Nesterov

__thread_fpu_begin() checks X86_FEATURE_EAGER_FPU by hand, we have a helper for that.

---
 arch/x86/include/asm/fpu-internal.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/include/asm/fpu-internal.h +1 -1
index e3b8542..37506df 100644
@@ -344,7 +344,7 @@ static inline void __thread_fpu_end(struct task_struct *tsk)
 
 static inline void __thread_fpu_begin(struct task_struct *tsk)
 {
-	if (!static_cpu_has_safe(X86_FEATURE_EAGER_FPU))
+	if (!use_eager_fpu())
 		clts();
 	__thread_set_has_fpu(tsk);
 }
Signature · 1 line
1.5.5.1
#6 lore raw

[tip:x86/fpu] x86, fpu: Change __thread_fpu_begin() to use use_eager_fpu()

x86, fpu: Change __thread_fpu_begin() to use use_eager_fpu()
Commit-ID:  31d963389f67165402aa447a8e8ce5ffb9188b3d
Gitweb:     http://git.kernel.org/tip/31d963389f67165402aa447a8e8ce5ffb9188b3d
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Tue, 2 Sep 2014 19:57:20 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 2 Sep 2014 14:51:15 -0700

x86, fpu: Change __thread_fpu_begin() to use use_eager_fpu()

__thread_fpu_begin() checks X86_FEATURE_EAGER_FPU by hand, we have a helper for that.

---
 arch/x86/include/asm/fpu-internal.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/fpu-internal.h +1 -1
index 412ecec..e97622f 100644
@@ -344,7 +344,7 @@ static inline void __thread_fpu_end(struct task_struct *tsk)
 
 static inline void __thread_fpu_begin(struct task_struct *tsk)
 {
-	if (!static_cpu_has_safe(X86_FEATURE_EAGER_FPU))
+	if (!use_eager_fpu())
 		clts();
 	__thread_set_has_fpu(tsk);
 }
#7 lore raw

PATCH v2 4/7 x86, fpu: copy_process: avoid fpu_alloc/copy if !used_math()

In reply to Oleg Nesterov

arch_dup_task_struct() copies thread.fpu if fpu_allocated(), this looks suboptimal and misleading. Say, a forking process could use FPU only once in a signal handler but now tsk_used_math(src) == F, in this case the child gets a copy of fpu->state for no reason. The child won't use the saved registers anyway even if it starts to use FPU, this can only avoid fpu_alloc() in do_device_not_available().

Change this code to check tsk_used_math(current) instead. We still need to clear fpu->has_fpu/state, we could do this memset(0) under fpu_allocated() check but I think this doesn't make sense. See also the next change.

use_eager_fpu() assumes that fpu_allocated() is always true, but a forking task (and thus its child) must always have PF_USED_MATH set, otherwise the child can either use FPU without used_math() (note that switch_fpu_prepare() doesn't do stts() in this case), or it will be killed by do_device_not_available()->BUG_ON(use_eager_fpu).

---
 arch/x86/kernel/process.c |   13 ++++++-------
 1 files changed, 6 insertions(+), 7 deletions(-)
arch/x86/kernel/process.c +6 -7
index 4505e2a..1dfdd69 100644
@@ -64,14 +64,13 @@ EXPORT_SYMBOL_GPL(task_xstate_cachep);
  */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-	int ret;
-
 	*dst = *src;
-	if (fpu_allocated(&src->thread.fpu)) {
-		memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
-		ret = fpu_alloc(&dst->thread.fpu);
-		if (ret)
-			return ret;
+
+	memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
+	if (tsk_used_math(src)) {
+		int err = fpu_alloc(&dst->thread.fpu);
+		if (err)
+			return err;
 		fpu_copy(dst, src);
 	}
 	return 0;
Signature · 1 line
1.5.5.1
#8 lore raw

[tip:x86/fpu] x86, fpu: copy_process: Avoid fpu_alloc/ copy if !used_math()

x86, fpu: copy_process: Avoid fpu_alloc/copy if !used_math()
Commit-ID:  f1853505d9ca1c3ea27c29cf83c24661531c527b
Gitweb:     http://git.kernel.org/tip/f1853505d9ca1c3ea27c29cf83c24661531c527b
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Tue, 2 Sep 2014 19:57:23 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 2 Sep 2014 14:51:16 -0700

x86, fpu: copy_process: Avoid fpu_alloc/copy if !used_math()

arch_dup_task_struct() copies thread.fpu if fpu_allocated(), this looks suboptimal and misleading. Say, a forking process could use FPU only once in a signal handler but now tsk_used_math(src) == F, in this case the child gets a copy of fpu->state for no reason. The child won't use the saved registers anyway even if it starts to use FPU, this can only avoid fpu_alloc() in do_device_not_available().

Change this code to check tsk_used_math(current) instead. We still need to clear fpu->has_fpu/state, we could do this memset(0) under fpu_allocated() check but I think this doesn't make sense. See also the next change.

use_eager_fpu() assumes that fpu_allocated() is always true, but a forking task (and thus its child) must always have PF_USED_MATH set, otherwise the child can either use FPU without used_math() (note that switch_fpu_prepare() doesn't do stts() in this case), or it will be killed by do_device_not_available()->BUG_ON(use_eager_fpu).

---
 arch/x86/kernel/process.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)
arch/x86/kernel/process.c +6 -7
index f804dc9..b9ba9d5 100644
@@ -64,14 +64,13 @@ EXPORT_SYMBOL_GPL(task_xstate_cachep);
  */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-	int ret;
-
 	*dst = *src;
-	if (fpu_allocated(&src->thread.fpu)) {
-		memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
-		ret = fpu_alloc(&dst->thread.fpu);
-		if (ret)
-			return ret;
+
+	memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
+	if (tsk_used_math(src)) {
+		int err = fpu_alloc(&dst->thread.fpu);
+		if (err)
+			return err;
 		fpu_copy(dst, src);
 	}
 	return 0;
#9 lore raw

PATCH v2 5/7 x86, fpu: copy_process: sanitize fpu->last_cpu initialization

In reply to Oleg Nesterov

Cosmetic, but imho memset(&dst->thread.fpu, 0) is not good simply because it hides the (important) usage of ->has_fpu/etc from grep. Change this code to initialize the members explicitly.

And note that ->last_cpu = 0 looks simply wrong, this can confuse fpu_lazy_restore() if per_cpu(fpu_owner_task, 0) has already exited and copy_process() re-allocated the same task_struct. Fortunately this is not actually possible because child->fpu_counter == 0 and thus fpu_lazy_restore() will not be called, but still this is not clean/robust.

---
 arch/x86/kernel/process.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
arch/x86/kernel/process.c +3 -1
index 1dfdd69..9b9f088 100644
@@ -66,7 +66,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	*dst = *src;
 
-	memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
+	dst->thread.fpu.has_fpu = 0;
+	dst->thread.fpu.last_cpu = ~0;
+	dst->thread.fpu.state = NULL;
 	if (tsk_used_math(src)) {
 		int err = fpu_alloc(&dst->thread.fpu);
 		if (err)
Signature · 1 line
1.5.5.1
#10 lore raw

[tip:x86/fpu] x86, fpu: copy_process: Sanitize fpu-> last_cpu initialization

x86, fpu: copy_process: Sanitize fpu->last_cpu initialization
Commit-ID:  5e23fee23ea10730c752edce1777e6b7e727290f
Gitweb:     http://git.kernel.org/tip/5e23fee23ea10730c752edce1777e6b7e727290f
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Tue, 2 Sep 2014 19:57:27 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 2 Sep 2014 14:51:16 -0700

x86, fpu: copy_process: Sanitize fpu->last_cpu initialization

Cosmetic, but imho memset(&dst->thread.fpu, 0) is not good simply because it hides the (important) usage of ->has_fpu/etc from grep. Change this code to initialize the members explicitly.

And note that ->last_cpu = 0 looks simply wrong, this can confuse fpu_lazy_restore() if per_cpu(fpu_owner_task, 0) has already exited and copy_process() re-allocated the same task_struct. Fortunately this is not actually possible because child->fpu_counter == 0 and thus fpu_lazy_restore() will not be called, but still this is not clean/robust.

---
 arch/x86/kernel/process.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
arch/x86/kernel/process.c +3 -1
index b9ba9d5..a44268c 100644
@@ -66,7 +66,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	*dst = *src;
 
-	memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
+	dst->thread.fpu.has_fpu = 0;
+	dst->thread.fpu.last_cpu = ~0;
+	dst->thread.fpu.state = NULL;
 	if (tsk_used_math(src)) {
 		int err = fpu_alloc(&dst->thread.fpu);
 		if (err)
#11 lore raw

PATCH v2 6/7 x86, fpu: shift "fpu_counter = 0" from copy_thread() to arch_dup_task_struct()

In reply to Oleg Nesterov

Cosmetic, but I think thread.fpu_counter should be initialized in arch_dup_task_struct() too, along with other "fpu" variables. And probably it make sense to turn it into thread.fpu->counter.

---
 arch/x86/kernel/process.c    |    1 +
 arch/x86/kernel/process_32.c |    2 --
 arch/x86/kernel/process_64.c |    1 -
 3 files changed, 1 insertions(+), 3 deletions(-)
arch/x86/kernel/process.c +1 -0
index 9b9f088..5df9447 100644
@@ -66,6 +66,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	*dst = *src;
 
+	dst->thread.fpu_counter = 0;
 	dst->thread.fpu.has_fpu = 0;
 	dst->thread.fpu.last_cpu = ~0;
 	dst->thread.fpu.state = NULL;
arch/x86/kernel/process_32.c +0 -2
index 7bc86bb..c73b3c1 100644
@@ -152,7 +152,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		childregs->orig_ax = -1;
 		childregs->cs = __KERNEL_CS | get_kernel_rpl();
 		childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
-		p->thread.fpu_counter = 0;
 		p->thread.io_bitmap_ptr = NULL;
 		memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 		return 0;
@@ -165,7 +164,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 	p->thread.ip = (unsigned long) ret_from_fork;
 	task_user_gs(p) = get_user_gs(current_pt_regs());
 
-	p->thread.fpu_counter = 0;
 	p->thread.io_bitmap_ptr = NULL;
 	tsk = current;
 	err = -ENOMEM;
arch/x86/kernel/process_64.c +0 -1
index ca5b02d..593257d 100644
@@ -163,7 +163,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 	p->thread.sp = (unsigned long) childregs;
 	p->thread.usersp = me->thread.usersp;
 	set_tsk_thread_flag(p, TIF_FORK);
-	p->thread.fpu_counter = 0;
 	p->thread.io_bitmap_ptr = NULL;
 
 	savesegment(gs, p->thread.gsindex);
Signature · 1 line
1.5.5.1
#12 lore raw

[tip:x86/fpu] x86, fpu: Shift "fpu_counter = 0" from copy_thread( ) to arch_dup_task_struct()

x86, fpu: Shift "fpu_counter = 0" from copy_thread() to arch_dup_task_struct()
Commit-ID:  dc56c0f9b870fba7a4eef2bb463db6881284152b
Gitweb:     http://git.kernel.org/tip/dc56c0f9b870fba7a4eef2bb463db6881284152b
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Tue, 2 Sep 2014 19:57:30 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 2 Sep 2014 14:51:16 -0700

x86, fpu: Shift "fpu_counter = 0" from copy_thread() to arch_dup_task_struct()

Cosmetic, but I think thread.fpu_counter should be initialized in arch_dup_task_struct() too, along with other "fpu" variables. And probably it make sense to turn it into thread.fpu->counter.

---
 arch/x86/kernel/process.c    | 1 +
 arch/x86/kernel/process_32.c | 2 --
 arch/x86/kernel/process_64.c | 1 -
 3 files changed, 1 insertion(+), 3 deletions(-)
arch/x86/kernel/process.c +1 -0
index a44268c..e127dda 100644
@@ -66,6 +66,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	*dst = *src;
 
+	dst->thread.fpu_counter = 0;
 	dst->thread.fpu.has_fpu = 0;
 	dst->thread.fpu.last_cpu = ~0;
 	dst->thread.fpu.state = NULL;
arch/x86/kernel/process_32.c +0 -2
index 7bc86bb..c73b3c1 100644
@@ -152,7 +152,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		childregs->orig_ax = -1;
 		childregs->cs = __KERNEL_CS | get_kernel_rpl();
 		childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
-		p->thread.fpu_counter = 0;
 		p->thread.io_bitmap_ptr = NULL;
 		memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 		return 0;
@@ -165,7 +164,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 	p->thread.ip = (unsigned long) ret_from_fork;
 	task_user_gs(p) = get_user_gs(current_pt_regs());
 
-	p->thread.fpu_counter = 0;
 	p->thread.io_bitmap_ptr = NULL;
 	tsk = current;
 	err = -ENOMEM;
arch/x86/kernel/process_64.c +0 -1
index ca5b02d..593257d 100644
@@ -163,7 +163,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 	p->thread.sp = (unsigned long) childregs;
 	p->thread.usersp = me->thread.usersp;
 	set_tsk_thread_flag(p, TIF_FORK);
-	p->thread.fpu_counter = 0;
 	p->thread.io_bitmap_ptr = NULL;
 
 	savesegment(gs, p->thread.gsindex);
#13 lore raw

PATCH v2 7/7 x86: copy_thread: don't nullify ->ptrace_bps twice

In reply to Oleg Nesterov

Both 32bit and 64bit versions of copy_thread() do memset(ptrace_bps) twice for no reason, kill the 2nd memset().

---
 arch/x86/kernel/process_32.c |    4 +---
 arch/x86/kernel/process_64.c |    2 --
 2 files changed, 1 insertions(+), 5 deletions(-)
arch/x86/kernel/process_32.c +1 -3
index c73b3c1..8f3ebfe 100644
@@ -138,6 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 
 	p->thread.sp = (unsigned long) childregs;
 	p->thread.sp0 = (unsigned long) (childregs+1);
+	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 
 	if (unlikely(p->flags & PF_KTHREAD)) {
 		/* kernel thread */
@@ -153,7 +154,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		childregs->cs = __KERNEL_CS | get_kernel_rpl();
 		childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
 		p->thread.io_bitmap_ptr = NULL;
-		memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 		return 0;
 	}
 	*childregs = *current_pt_regs();
@@ -168,8 +168,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 	tsk = current;
 	err = -ENOMEM;
 
-	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
-
 	if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
 		p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
 						IO_BITMAP_BYTES, GFP_KERNEL);
arch/x86/kernel/process_64.c +0 -2
index 593257d..3ed4a68 100644
@@ -192,8 +192,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		childregs->sp = sp;
 
 	err = -ENOMEM;
-	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
-
 	if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
 		p->thread.io_bitmap_ptr = kmemdup(me->thread.io_bitmap_ptr,
 						  IO_BITMAP_BYTES, GFP_KERNEL);
Signature · 1 line
1.5.5.1
#14 lore raw

[tip:x86/fpu] x86: copy_thread: Don't nullify ->ptrace_bps twice

x86: copy_thread: Don't nullify ->ptrace_bps twice
Commit-ID:  6f46b3aef0031c08a7b439d63013dad2aeb093b2
Gitweb:     http://git.kernel.org/tip/6f46b3aef0031c08a7b439d63013dad2aeb093b2
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Tue, 2 Sep 2014 19:57:33 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Tue, 2 Sep 2014 14:51:17 -0700

x86: copy_thread: Don't nullify ->ptrace_bps twice

Both 32bit and 64bit versions of copy_thread() do memset(ptrace_bps) twice for no reason, kill the 2nd memset().

---
 arch/x86/kernel/process_32.c | 4 +---
 arch/x86/kernel/process_64.c | 2 --
 2 files changed, 1 insertion(+), 5 deletions(-)
arch/x86/kernel/process_32.c +1 -3
index c73b3c1..8f3ebfe 100644
@@ -138,6 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 
 	p->thread.sp = (unsigned long) childregs;
 	p->thread.sp0 = (unsigned long) (childregs+1);
+	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 
 	if (unlikely(p->flags & PF_KTHREAD)) {
 		/* kernel thread */
@@ -153,7 +154,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		childregs->cs = __KERNEL_CS | get_kernel_rpl();
 		childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
 		p->thread.io_bitmap_ptr = NULL;
-		memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 		return 0;
 	}
 	*childregs = *current_pt_regs();
@@ -168,8 +168,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 	tsk = current;
 	err = -ENOMEM;
 
-	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
-
 	if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
 		p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
 						IO_BITMAP_BYTES, GFP_KERNEL);
arch/x86/kernel/process_64.c +0 -2
index 593257d..3ed4a68 100644
@@ -192,8 +192,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 		childregs->sp = sp;
 
 	err = -ENOMEM;
-	memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
-
 	if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
 		p->thread.io_bitmap_ptr = kmemdup(me->thread.io_bitmap_ptr,
 						  IO_BITMAP_BYTES, GFP_KERNEL);