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 <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>
This commit is contained in:
parent
6a81d7eb33
commit
343763c3b0
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue