From 343763c3b0a4fa2d29f7c3ba405abf8771b90876 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 May 2015 12:22:29 +0200 Subject: [PATCH] x86/fpu: Optimize fpu__activate_fpstate_write() fpu__activate_fpstate_write() is used before ptrace writes to the fpstate context. Because it expects the modified registers to be reloaded on the nexts context switch, it's only valid to call this function for stopped child tasks. - add a debugging check for this assumption - remove code that only runs if the current task's FPU state needs to be saved, which cannot occur here - update comments to match the implementation Cc: Andy Lutomirski Cc: Bobby Powers Cc: Borislav Petkov Cc: Dave Hansen Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/fpu/core.c | 53 ++++++++++++++------------------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 6b0955a62d34..86a9a9a086fa 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -322,47 +322,34 @@ void fpu__activate_fpstate_read(struct fpu *fpu) } /* - * This function must be called before we read or write a task's fpstate. + * This function must be called before we write a task's fpstate. * - * If the task has not used the FPU before then initialize its - * fpstate. + * If the task has used the FPU before then unlazy it. + * If the task has not used the FPU before then initialize its fpstate. * - * If the task has used the FPU before then save and unlazy it. - * - * [ If this function is used for non-current child tasks, then - * after this function call, after registers in the fpstate are - * modified and the child task has woken up, the child task will - * restore the modified FPU state from the modified context. If we - * didn't clear its lazy status here then the lazy in-registers - * state pending on its former CPU could be restored, corrupting - * the modifications. - * - * This function can be used for the current task as well, but - * only for reading the fpstate. Modifications to the fpstate - * will be lost on eagerfpu systems. ] - * - * TODO: A future optimization would be to skip the unlazying in - * the read-only case, it's not strictly necessary for - * read-only access to the context. + * After this function call, after registers in the fpstate are + * modified and the child task has woken up, the child task will + * restore the modified FPU state from the modified context. If we + * didn't clear its lazy status here then the lazy in-registers + * state pending on its former CPU could be restored, corrupting + * the modifications. */ void fpu__activate_fpstate_write(struct fpu *fpu) { /* - * If fpregs are active (in the current CPU), then - * copy them to the fpstate: + * Only stopped child tasks can be used to modify the FPU + * state in the fpstate buffer: */ - if (fpu->fpregs_active) { - fpu__save(fpu); - } else { - if (fpu->fpstate_active) { - /* Invalidate any lazy state: */ - fpu->last_cpu = -1; - } else { - fpstate_init(&fpu->state); + WARN_ON_FPU(fpu == ¤t->thread.fpu); - /* Safe to do for current and for stopped child tasks: */ - fpu->fpstate_active = 1; - } + if (fpu->fpstate_active) { + /* Invalidate any lazy state: */ + fpu->last_cpu = -1; + } else { + fpstate_init(&fpu->state); + + /* Safe to do for stopped child tasks: */ + fpu->fpstate_active = 1; } }