x86/fpu: Optimize fpu__activate_fpstate_write()
authorIngo Molnar <mingo@kernel.org>
Wed, 27 May 2015 10:22:29 +0000 (12:22 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 27 May 2015 12:11:27 +0000 (14:11 +0200)
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 <luto@amacapital.net>
Cc: Bobby Powers <bobbypowers@gmail.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/kernel/fpu/core.c

index 6b0955a62d340c36d57f82410594b3259b7b408f..86a9a9a086fad3704291148c7c458dd795fb2ae1 100644 (file)
@@ -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 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.
+ * If the task has used the FPU before then unlazy it.
+ * If the task has not used the FPU before then initialize its fpstate.
  *
- *   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);
+       WARN_ON_FPU(fpu == &current->thread.fpu);
+
+       if (fpu->fpstate_active) {
+               /* Invalidate any lazy state: */
+               fpu->last_cpu = -1;
        } else {
-               if (fpu->fpstate_active) {
-                       /* Invalidate any lazy state: */
-                       fpu->last_cpu = -1;
-               } else {
-                       fpstate_init(&fpu->state);
+               fpstate_init(&fpu->state);
 
-                       /* Safe to do for current and for stopped child tasks: */
-                       fpu->fpstate_active = 1;
-               }
+               /* Safe to do for stopped child tasks: */
+               fpu->fpstate_active = 1;
        }
 }