Skip to contentSkip to conversation

question about save_xstate_sig() - WHY DOES THIS WORK?

RFC PATCH New Rik van Riel 6 participants 61 messages Jan 23, 2015 – Feb 19, 2015

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

While working on a patch series to defer FPU state loading until kernel -> user space transition, and be more lazy with FPU state while in the kernel, I came across this code in save_xstate_sig().

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Specifically, save_user_xstate() may page fault and sleep. After returning from the page fault, there is no guarantee that the FPU state will be restored into the CPU, when the system is not running with eager fpu mode.

In that case, what prevents us from saving random FPU register state to the user's stack frame? Potentially state containing data from other programs...

        if (user_has_fpu()) {
                /* Save the live register state to the user directly. */
                if (save_user_xstate(buf_fx))
                        return -1;
                /* Update the thread's fxstate to save the fsave header. */
                if (ia32_fxstate)
                        fpu_fxsave(&tsk->thread.fpu);
        } else {
                sanitize_i387_state(tsk);
                if (__copy_to_user(buf_fx, xsave, xstate_size))
                        return -1;
        }

Is this code safe for some reason I have overlooked?

If not, should I post the patch turning the above into "save FPU state atomically, then copy it to user space" independently from my optimizations, and submit it for inclusion in -stable as well?

#1 lore raw

RFC PATCH 1/1 x86,fpu: make signal handling xstate save & restore preemption safe

Saving xstate directly to userspace, or restoring it directly from userspace could result in a page fault, which can lead to the task context switching and sleeping.

There is no guarantee that after the context switch the FPU state for the task will be loaded back into the FPU registers, and it looks like that could potentially cause corruption of the FPU state.

The straightforward solution is to do the FPU save and restore with preemption disabled, which requires using a kernel buffer. That in turn allows us to use the same save and restore routines that are used at context switch and math exception time, allowing us to remove the direct-to-userspace variants.

I have only tested this code as part of my larger FPU optimization series, not yet stand-alone.

---
 arch/x86/include/asm/fpu-internal.h | 14 ++++----
 arch/x86/kernel/xsave.c             | 72 ++++++++++---------------------------
 2 files changed, 26 insertions(+), 60 deletions(-)
arch/x86/include/asm/fpu-internal.h +8 -6
index 68089ef86907..724f3e4faf34 100644
@@ -508,16 +508,18 @@ static inline void __save_fpu(struct task_struct *tsk)
  */
 static inline void save_init_fpu(struct task_struct *tsk)
 {
-	WARN_ON_ONCE(!__thread_has_fpu(tsk));
+	preempt_disable();
+
+	if (!__thread_has_fpu(tsk))
+		goto out;
 
-	if (use_eager_fpu()) {
+	if (use_eager_fpu())
 		__save_fpu(tsk);
-		return;
-	}
+	else
+		__save_init_fpu(tsk);
 
-	preempt_disable();
-	__save_init_fpu(tsk);
 	__thread_fpu_end(tsk);
+ out:
 	preempt_enable();
 }
 
arch/x86/kernel/xsave.c +18 -54

101 lines not on this page · raw message

#2 lore raw
In reply to Rik van Riel
Quoted 7 lines · Rik van Riel

While working on a patch series to defer FPU state loading until kernel -> user space transition, and be more lazy with FPU state while in the kernel, I came across this code in save_xstate_sig().

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Quoted 9 lines

Specifically, save_user_xstate() may page fault and sleep. After returning from the page fault, there is no guarantee that the FPU state will be restored into the CPU, when the system is not running with eager fpu mode.

In that case, what prevents us from saving random FPU register state to the user's stack frame? Potentially state containing data from other programs...

If the FPU state is not current, we'll have CR0.TS = 1 and the XSAVE will cause an #NM exception, which will cause the FPU state to be swapped in.

-hpa

#3 lore raw

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 14 lines · H. Peter Anvin
Quoted 13 lines · Rik van Riel

While working on a patch series to defer FPU state loading until kernel -> user space transition, and be more lazy with FPU state while in the kernel, I came across this code in save_xstate_sig().

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Specifically, save_user_xstate() may page fault and sleep. After returning from the page fault, there is no guarantee that the FPU state will be restored into the CPU, when the system is not running with eager fpu mode.

Quoted 8 lines
Quoted 4 lines

In that case, what prevents us from saving random FPU register state to the user's stack frame? Potentially state containing data from other programs...

If the FPU state is not current, we'll have CR0.TS = 1 and the XSAVE will cause an #NM exception, which will cause the FPU state to be swapped in.

OK, so the code works as it is right now, but I still need to have the patch in my "defer FPU state loading and CR0.TS switching to kernel -> user space transition" patch series.

Thanks for explaining why the current code is safe, Peter.

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUw6CNAAoJEM553pKExN6DIkIH/jYpLRfVSbx+JBuFtOibA6jk wwWnwNdPRUiWf0v0lSNX4phk9f7VCy8WKbrFtC0IYdGLL0zCY94dN7us4hNYo9fE btdb/qsvqq8w2esPuUczAgaxwipYVliDUDOHSXTRbPS2upBuLHl/CVIVb1A+HVC7 gB6GF4ZLa2P1ygcjuWDNDNtx04QWTi7K80eWtWAQ7U4OK9Y4fSgR3hOIJS79M/aJ P9YGaTyo0zDQcKx1rFXTjl9A0slCFZ+QkAeCwLZRkXc1K9n50GANuYeg53/ATYey 7x0FjZEBD2ipX60FqZ+mYAiA7rqw4RYKgAttszy9b9bgKY/fzHy87z2YS8Umplg= =55wt
-----END PGP SIGNATURE-----

#4 lore raw
In reply to Rik van Riel

Let me abuse this thread to ask more questions.

Peter, could you help?

Quoted 3 lines · Rik van Riel

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

As I already mentioned, at least math_error()->save_init_fpu() looks buggy. And unlazy_fpu() doesn't look right too.

Note that save_init_fpu() is calles after conditional_sti(), so unless I missed something the task can be preempted and we can actually hit WARN_ON_ONCE(!__thread_has_fpu()) if !use_eager_fpu() && .fpu_counter == 0.

Worse, the unconditional __save_init_fpu() is obviously wrong in this case.

I already have a patch which (like the patch from Rik) turns it into

	static inline void save_init_fpu(struct task_struct *tsk)
	{
		preempt_disable();
		if (__thread_has_fpu(tsk)) {
			if (use_eager_fpu()) {
				__save_fpu(tsk);
			} else {
				__save_init_fpu(tsk);
				__thread_fpu_end(tsk);
			}
		}
		preempt_enable();
	}

and I think this fix needs the separate patch/changelog.

Now the questions:

- This doesn't hurt, but does it really need __thread_fpu_end?

Perhaps this is because we do not check the error code returned by __save_init_fpu? although I am not sure I understand the comment above fpu_save_init correctly...

- What about do_bounds() ? Should not it use save_init_fpu() rather than fpu_save_init() ?

- Why unlazy_fpu() always does __save_init_fpu() even if use_eager_fpu?

and note that in this case __thread_fpu_end() is wrong if use_eager_fpu, but fortunately the only possible caller of unlazy_fpu() is coredump. fpu_copy() checks use_eager_fpu().

- Is unlazy_fpu()->__save_init_fpu() safe wrt __kernel_fpu_begin() from irq?

I mean, is it safe if __save_init_fpu() path is interrupted by another __save_init_fpu() + restore_fpu_checking() from __kernel_fpu_begin/end?

Thanks,

Oleg.

#5 lore raw

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 29 lines · Oleg Nesterov

Let me abuse this thread to ask more questions.

Peter, could you help?

Quoted 3 lines · Rik van Riel

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

As I already mentioned, at least math_error()->save_init_fpu() looks buggy. And unlazy_fpu() doesn't look right too.

Note that save_init_fpu() is calles after conditional_sti(), so unless I missed something the task can be preempted and we can actually hit WARN_ON_ONCE(!__thread_has_fpu()) if !use_eager_fpu() && .fpu_counter == 0.

Worse, the unconditional __save_init_fpu() is obviously wrong in this case.

I already have a patch which (like the patch from Rik) turns it into

static inline void save_init_fpu(struct task_struct *tsk) { preempt_disable(); if (__thread_has_fpu(tsk)) { if (use_eager_fpu()) { __save_fpu(tsk); } else { __save_init_fpu(tsk); __thread_fpu_end(tsk); } } preempt_enable(); }

Quoted 7 lines

Now the questions:

- This doesn't hurt, but does it really need __thread_fpu_end?

Perhaps this is because we do not check the error code returned by __save_init_fpu? although I am not sure I understand the comment above fpu_save_init correctly...

Looking at the code some more, I do not see any call site of save_init_fpu() that actually needs or wants __thread_fpu_end(), with or without eager fpu mode.

It looks like we can get rid of that.

Quoted 2 lines

- What about do_bounds() ? Should not it use save_init_fpu() rather than fpu_save_init() ?

I suppose do_bounds() probably should save the fpu context while not preemptible, but that may also mean moving conditional_sti() until after save_init_fpu() or __save_init_fpu() has been called.

Quoted 7 lines

- Why unlazy_fpu() always does __save_init_fpu() even if use_eager_fpu?

and note that in this case __thread_fpu_end() is wrong if use_eager_fpu, but fortunately the only possible caller of unlazy_fpu() is coredump. fpu_copy() checks use_eager_fpu().

Quoted 6 lines

- Is unlazy_fpu()->__save_init_fpu() safe wrt __kernel_fpu_begin() from irq?

I mean, is it safe if __save_init_fpu() path is interrupted by another __save_init_fpu() + restore_fpu_checking() from __kernel_fpu_begin/end?

I got lost in the core dump code trying to figure out whether this is safe or broken. I'll need some more time to look through that code...

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUxs1kAAoJEM553pKExN6DacoH/jlSeftktuzKNN1lc8f1o1Uw 3f4i/SLjleHa00xayaG2RMrYpRtMAVMHqgG+3ltmF9cHZj3LUrYl8p5QlQTO+jMS 53B/U/GCHrBWyziQgUHvGmw6WyVSDlTEej0gb91WW0pKEvuUrDdCTTwhNFqp649b jRw5F+LGIvYB99ICI5hLEMzbbKhMOpyiG4c3qmU41xsfnEWly50YdFKfetXm79E0 MF1xN4trwqv7JOoBGfKwH8aUGe/n6B9e/QHAu7JMIuryjZK/cSug/4lH0QR0xMni NUzqKaE8xCDW5LQMLAg+7ZYhvdR/o3EbV4Lk90RCBF1KTTSFKorhUavwZLu/M3M= =QlMj
-----END PGP SIGNATURE-----

#6 lore raw
Quoted 7 lines · Rik van Riel
Quoted 4 lines · Oleg Nesterov

Now the questions:

- This doesn't hurt, but does it really need __thread_fpu_end?

Quoted 7 lines
Quoted 3 lines

Perhaps this is because we do not check the error code returned by __save_init_fpu? although I am not sure I understand the comment above fpu_save_init correctly...

Looking at the code some more, I do not see any call site of save_init_fpu() that actually needs or wants __thread_fpu_end(), with or without eager fpu mode.

Yes. But probably it is needed if __save_init_fpu() returns 0. But this is minor, __thread_fpu_end() doesn't hurt correctness-wise if !eager.

Quoted 1 line

It looks like we can get rid of that.

Agreed, but probably this needs a separate change.

Quoted 5 lines
Quoted 2 lines

- What about do_bounds() ? Should not it use save_init_fpu() rather than fpu_save_init() ?

I suppose do_bounds() probably should save the fpu context while not preemptible,

plus it also needs the __thread_has_fpu() check. Otherwise fpu_save_init() can save the wrong FPU state afaics.

Quoted 2 lines

but that may also mean moving conditional_sti()
until after save_init_fpu() or __save_init_fpu() has been called.

Agreed, this can work too.

Quoted 10 lines
Quoted 10 lines

- Why unlazy_fpu() always does __save_init_fpu() even if use_eager_fpu?

and note that in this case __thread_fpu_end() is wrong if use_eager_fpu, but fortunately the only possible caller of unlazy_fpu() is coredump. fpu_copy() checks use_eager_fpu().

- Is unlazy_fpu()->__save_init_fpu() safe wrt __kernel_fpu_begin() from irq?

Quoted 6 lines
Quoted 3 lines

I mean, is it safe if __save_init_fpu() path is interrupted by another __save_init_fpu() + restore_fpu_checking() from __kernel_fpu_begin/end?

I got lost in the core dump code trying to figure out whether this is safe or broken. I'll need some more time to look through that code...

It is called indirectly by regset code, see xstateregs_get()->init_fpu().

The coredumping task can't return to user-mode and use FPU in this case, so this is not that bad. Still unlazy_fpu()->__thread_fpu_end() is wrong if eager.

And I forgot to mention, the "else" branch in unlazy_fpu() makes no sense. And note that save_init_fpu() and unlazy_fpu() is the same thing (if we fix/cleanup them).

Oh. I'll try to finish my cleanups and send them tomorrow. Unless you do this ;)

Oleg.

#7 lore raw

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 30 lines · Oleg Nesterov
Quoted 7 lines · Rik van Riel
Quoted 4 lines · Oleg Nesterov

Now the questions:

- This doesn't hurt, but does it really need __thread_fpu_end?

Quoted 7 lines
Quoted 3 lines

Perhaps this is because we do not check the error code returned by __save_init_fpu? although I am not sure I understand the comment above fpu_save_init correctly...

Looking at the code some more, I do not see any call site of save_init_fpu() that actually needs or wants __thread_fpu_end(), with or without eager fpu mode.

Yes. But probably it is needed if __save_init_fpu() returns 0. But this is minor, __thread_fpu_end() doesn't hurt correctness-wise if !eager.

Quoted 1 line

It looks like we can get rid of that.

Agreed, but probably this needs a separate change.

Quoted 5 lines
Quoted 2 lines

- What about do_bounds() ? Should not it use save_init_fpu() rather than fpu_save_init() ?

I suppose do_bounds() probably should save the fpu context while not preemptible,

Quoted 17 lines

plus it also needs the __thread_has_fpu() check. Otherwise fpu_save_init() can save the wrong FPU state afaics.

Quoted 2 lines

but that may also mean moving conditional_sti() until after save_init_fpu() or __save_init_fpu() has been called.

Agreed, this can work too.

Quoted 9 lines
Quoted 9 lines

- Why unlazy_fpu() always does __save_init_fpu() even if use_eager_fpu?

and note that in this case __thread_fpu_end() is wrong if use_eager_fpu, but fortunately the only possible caller of unlazy_fpu() is coredump. fpu_copy() checks use_eager_fpu().

- Is unlazy_fpu()->__save_init_fpu() safe wrt
__kernel_fpu_begin() from irq?

It looks like it should be safe, as long as __save_init_fpu() knows that the task no longer has the FPU after __kernel_fpu_end(), so it does not try to save the kernel FPU state to the user's task->thread.fpu.state->xstate

The caveat here is that __kernel_fpu_begin()/__kernel_fpu_end() needs to be kept from running during unlazy_fpu().

This means interrupted_kernel_fpu_idle and/or irq_fpu_usable need to check whether preemption is disabled, and lock out __kernel_fpu_begin() when preemption is disabled.

It does not look like it currently does that...

Quoted 11 lines
Quoted 7 lines
Quoted 3 lines

I mean, is it safe if __save_init_fpu() path is interrupted by another __save_init_fpu() + restore_fpu_checking() from __kernel_fpu_begin/end?

I got lost in the core dump code trying to figure out whether this is safe or broken. I'll need some more time to look through that code...

It is called indirectly by regset code, see
xstateregs_get()->init_fpu().

Quoted 7 lines

The coredumping task can't return to user-mode and use FPU in this case, so this is not that bad. Still unlazy_fpu()->__thread_fpu_end() is wrong if eager.

And I forgot to mention, the "else" branch in unlazy_fpu() makes no sense. And note that save_init_fpu() and unlazy_fpu() is the same thing (if we fix/cleanup them).

I was wondering why there were several functions doing essentially the same thing...

Quoted 2 lines

Oh. I'll try to finish my cleanups and send them tomorrow. Unless you do this ;)

If you tell me what you would like to see done, I'd be more than happy to do it :)

I can certainly merge unlazy_fpu() and save_init_fpu() into the same function, but I am not sure whether or not it should call __thread_fpu_end() - it looks like that would be desirable in some cases, but not in others...

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUx/S6AAoJEM553pKExN6DCJwH/0US/6JXKxX0vYOuaw9SKzhX fgkxWbHFtJ7qn/tXBJqKgQQr5RIJ8dH6opoGNzzeOGeNMISoo9EZrVYxO1mv/Lrk GoPjFDVyhm/hc74Bvpm7Xtzai7JJanTyLj63pLPu4wm+0+QKPEoRUMvtyLuLe0nM 5GMpnW0wWZn/c0JWLihfKRCK5FecP9Tv9y/1gXGkLWymMw8PDpXxIqo+VJJM86ow eUrPTFHeAvYh1m0lsxOr4JMUB5+VeZV9zXNPefNHlMcBNchVGvDhxWpdqtGyROd4 A+tMBM4EymrJoTeJrcxuFSdKFcCW0T/9JOHm3tb4B9Qjsk7/ROzp0d/s7bKyyKw= =9h6C
-----END PGP SIGNATURE-----

#8 lore raw

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 17 lines · Rik van Riel
Quoted 9 lines · Oleg Nesterov
Quoted 9 lines
Quoted 9 lines

- Why unlazy_fpu() always does __save_init_fpu() even if use_eager_fpu?

and note that in this case __thread_fpu_end() is wrong if use_eager_fpu, but fortunately the only possible caller of unlazy_fpu() is coredump. fpu_copy() checks use_eager_fpu().

- Is unlazy_fpu()->__save_init_fpu() safe wrt
__kernel_fpu_begin() from irq?

It looks like it should be safe, as long as __save_init_fpu() knows that the task no longer has the FPU after __kernel_fpu_end(), so it does not try to save the kernel FPU state to the user's task->thread.fpu.state->xstate

Quoted 8 lines

The caveat here is that __kernel_fpu_begin()/__kernel_fpu_end() needs to be kept from running during unlazy_fpu().

This means interrupted_kernel_fpu_idle and/or irq_fpu_usable need to check whether preemption is disabled, and lock out __kernel_fpu_begin() when preemption is disabled.

It does not look like it currently does that...

... and that won't work, because preempt_disable() is a noop without CONFIG_PREEMPT enabled. Sigh.

Not sure how to work around that, except by having __Kernel_fpu_end() always restore the task FPU state, if the task had the FPU when entering.

This suggests it may be advantageous to be liberal with __thread_fpu_end() when we know user space will not be touching the FPU again for a while, since that would reduce the work done by __kernel_fpu_begin()/__kernel_fpu_end().

Does that make sense?

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUx/oJAAoJEM553pKExN6Dh4YH/AtVOza5VeZuz55s59LifpLt 5eXMQBxQt0JiX9NACc+7qXDuEFfkmnzhNpNT98abuic7/1dvj2TfcoXSnkysDaNb WojFW0gMc973G4UA6ZPsqScxz7jdfaqNrFdFEaTPM6URClIllVXTgnCcDoWCFfR2 627s6vyOW//BgXnedHraGGqnBVpCBLWrsVnhJ0RbPd2cjrrwKPXcbLnk6+uzZqLY /7Zp2fSDjuAY6PhxRZM529vyJNqIM2mhlKFG8/xnch95mlXwtOQvLuuJmkwbKabb 6Z1gqpyEXbWyB2riD/pQrIlkOg2P4UuLONM7fgFY4Dzc8MEM7UmNR4mWoPAeBuU= =SSqD
-----END PGP SIGNATURE-----

#9 lore raw
Quoted 26 lines · Rik van Riel
Quoted 24 lines · Rik van Riel
Quoted 9 lines · Oleg Nesterov
Quoted 9 lines
Quoted 9 lines

- Why unlazy_fpu() always does __save_init_fpu() even if use_eager_fpu?

and note that in this case __thread_fpu_end() is wrong if use_eager_fpu, but fortunately the only possible caller of unlazy_fpu() is coredump. fpu_copy() checks use_eager_fpu().

- Is unlazy_fpu()->__save_init_fpu() safe wrt
__kernel_fpu_begin() from irq?

It looks like it should be safe, as long as __save_init_fpu() knows that the task no longer has the FPU after __kernel_fpu_end(), so it does not try to save the kernel FPU state to the user's task->thread.fpu.state->xstate

The caveat here is that __kernel_fpu_begin()/__kernel_fpu_end() needs to be kept from running during unlazy_fpu().

This means interrupted_kernel_fpu_idle and/or irq_fpu_usable need to check whether preemption is disabled, and lock out __kernel_fpu_begin() when preemption is disabled.

Quoted 8 lines
Quoted 1 line

It does not look like it currently does that...

... and that won't work, because preempt_disable() is a noop without CONFIG_PREEMPT enabled. Sigh.

Not sure how to work around that, except by having __Kernel_fpu_end() always restore the task FPU state, if the task had the FPU when entering.

This is what it does after

	[PATCH 2/3] x86, fpu: don't abuse ->has_fpu in __kernel_fpu_{begin,end}()
	http://marc.info/?l=linux-kernel&m=142134967718861&w=2

(acked by you and already applied).

But probably I misunderstood you, I do not see how this can help... OK, lets discuss this later.

Oleg.

#10 lore raw
In reply to Rik van Riel
Quoted 10 lines · Rik van Riel
Quoted 3 lines · Oleg Nesterov
Quoted 3 lines
Quoted 3 lines

- Is unlazy_fpu()->__save_init_fpu() safe wrt
__kernel_fpu_begin() from irq?

It looks like it should be safe, as long as __save_init_fpu() knows that the task no longer has the FPU after __kernel_fpu_end(), so it does not try to save the kernel FPU state to the user's task->thread.fpu.state->xstate

Not sure this is enough, but...

Quoted 2 lines

The caveat here is that __kernel_fpu_begin()/__kernel_fpu_end() needs to be kept from running during unlazy_fpu().

Yes,

Quoted 3 lines

This means interrupted_kernel_fpu_idle and/or irq_fpu_usable need to check whether preemption is disabled, and lock out __kernel_fpu_begin() when preemption is disabled.

But we already have kernel_fpu_disable/enable. unlazy_cpu() can use it to avoid the race ?

Quoted 4 lines

I can certainly merge unlazy_fpu() and save_init_fpu() into the same function, but I am not sure whether or not it should call __thread_fpu_end() - it looks like that would be desirable in some cases, but not in others...

I _think_ that we never actually want __thread_fpu_end(), although it doesn't really hurt if !eager. Probably ulazy/save should do

	if (!__save_init_fpu())
		__thread_fpu_end();

But again, this is minor.

Oleg.

#11 lore raw
Quoted 17 lines · Oleg Nesterov
Quoted 10 lines · Rik van Riel
Quoted 3 lines · Oleg Nesterov
Quoted 3 lines
Quoted 3 lines

- Is unlazy_fpu()->__save_init_fpu() safe wrt
__kernel_fpu_begin() from irq?

It looks like it should be safe, as long as __save_init_fpu() knows that the task no longer has the FPU after __kernel_fpu_end(), so it does not try to save the kernel FPU state to the user's task->thread.fpu.state->xstate

Not sure this is enough, but...

Quoted 2 lines

The caveat here is that __kernel_fpu_begin()/__kernel_fpu_end() needs to be kept from running during unlazy_fpu().

Quoted 8 lines

Yes,

Quoted 3 lines

This means interrupted_kernel_fpu_idle and/or irq_fpu_usable need to check whether preemption is disabled, and lock out __kernel_fpu_begin() when preemption is disabled.

But we already have kernel_fpu_disable/enable. unlazy_cpu() can use it to avoid the race ?

I suspect this will be fine, if __kernel_fpu_end() from IRQ context always restores the FPU context, or calls stts, so things like save_init_fpu() will either continue where they left off, or trap and then continue where they left off.

__kernel_fpu_end() from process context can be lazier, something I can work on in my next version of the "defer FPU loading to kernel -> user space boundary" patch series.

Quoted 10 lines
Quoted 4 lines

I can certainly merge unlazy_fpu() and save_init_fpu() into the same function, but I am not sure whether or not it should call __thread_fpu_end() - it looks like that would be desirable in some cases, but not in others...

I _think_ that we never actually want __thread_fpu_end(), although it doesn't really hurt if !eager. Probably ulazy/save should do

	if (!__save_init_fpu())
		__thread_fpu_end();

There is at least one case where we want __thread_fpu_end(), and that is xstateregs_set. I got this by moving the __thread_fpu_end() call from save_init_fpu() into init_fpu().

I am not sure about __math_error. I suspect we may need __thread_fpu_end() in there so the math state can be re-initialized if the task catches SIGFPE and continues.

On the other hand, I do not see code in there that actually does that at the moment...

Let me send my RFC patch to clean up & merge unlazy_fpu and save_init_fpu() in the next email.

#12 lore raw

RFC PATCH 1/1 x86,fpu: merge save_init_fpu & unlazy_fpu

In reply to Oleg Nesterov

The functions save_init_fpu and unlazy_fpu do essentially the same thing: save the fpu context to memory, and call __thread_fpu_end, which most of the callers do not need or want.

Get rid of the function unlazy_fpu and make sure save_init_fpu does what unlazy_fpu does today, including preemption safe state saving in potentially unusual conditions.

Callers of init_fpu do want __thread_fpu_end, so move the call to __thread_fpu_end into init_fpu.

I am not sure whether math_error requires __thread_fpu_end. One would think that it would require that in order to sanitize the math state, before do_device_not_available and math_state_restore restore it, but those do not currently seem to do that. I am not sure how a task that catches SIGFPE is supposed to recover and continue...

---
 arch/x86/include/asm/fpu-internal.h | 18 ++++++++----------
 arch/x86/include/asm/i387.h         |  2 --
 arch/x86/kernel/i387.c              | 18 ++++--------------
 arch/x86/kernel/traps.c             |  1 +
 4 files changed, 13 insertions(+), 26 deletions(-)
arch/x86/include/asm/fpu-internal.h +8 -10
index 0dbc08282291..c7e440ddd269 100644
@@ -524,16 +524,14 @@ static inline void __save_fpu(struct task_struct *tsk)
  */
 static inline void save_init_fpu(struct task_struct *tsk)
 {
-	WARN_ON_ONCE(!__thread_has_fpu(tsk));
-
-	if (use_eager_fpu()) {
-		__save_fpu(tsk);
-		return;
-	}
-
 	preempt_disable();
-	__save_init_fpu(tsk);
-	__thread_fpu_end(tsk);
+	if (__thread_has_fpu(tsk)) {
+		if (use_eager_fpu())
+			__save_fpu(tsk);
+		else
+			__save_init_fpu(tsk);
+	} else if (!use_eager_fpu())
+		tsk->thread.fpu_counter = 0;
 	preempt_enable();
 }
 
@@ -600,7 +598,7 @@ static inline void fpu_copy(struct task_struct *dst, struct task_struct *src)
 		struct fpu *dfpu = &dst->thread.fpu;
 		struct fpu *sfpu = &src->thread.fpu;
 
-		unlazy_fpu(src);
+		save_init_fpu(src);
 		memcpy(dfpu->state, sfpu->state, xstate_size);
 	}
 }
arch/x86/include/asm/i387.h +0 -2
index 6eb6fcb83f63..07836671acfb 100644
@@ -101,8 +101,6 @@ static inline int user_has_fpu(void)
 	return current->thread.fpu.has_fpu;
 }
 
-extern void unlazy_fpu(struct task_struct *tsk);
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_X86_I387_H */
arch/x86/kernel/i387.c +4 -14
index 47348653503a..3afc4e73b07f 100644
@@ -116,18 +116,6 @@ void __kernel_fpu_end(void)
 }
 EXPORT_SYMBOL(__kernel_fpu_end);
 
-void unlazy_fpu(struct task_struct *tsk)
-{
-	preempt_disable();
-	if (__thread_has_fpu(tsk)) {
-		__save_init_fpu(tsk);
-		__thread_fpu_end(tsk);
-	} else
-		tsk->thread.fpu_counter = 0;
-	preempt_enable();
-}
-EXPORT_SYMBOL(unlazy_fpu);
-
 unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
 unsigned int xstate_size;
 EXPORT_SYMBOL_GPL(xstate_size);
@@ -245,8 +233,10 @@ int init_fpu(struct task_struct *tsk)
 	int ret;
 
 	if (tsk_used_math(tsk)) {
-		if (cpu_has_fpu && tsk == current)
-			unlazy_fpu(tsk);
+		if (cpu_has_fpu && tsk == current) {
+			save_init_fpu(tsk);
+			__thread_fpu_end(tsk);
+		}
 		tsk->thread.fpu.last_cpu = ~0;
 		return 0;
 	}
arch/x86/kernel/traps.c +1 -0
index fb4cb6adf225..201522fd2c96 100644
@@ -664,6 +664,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
 	 * Save the info for the exception handler and clear the error.
 	 */
 	save_init_fpu(task);
+	__thread_fpu_end(task);
 	task->thread.trap_nr = trapnr;
 	task->thread.error_code = error_code;
 	info.si_signo = SIGFPE;
#13 lore raw

Re: [PATCH RFC] x86,fpu: merge save_init_fpu & unlazy_fpu

Quoted 3 lines · Rik van Riel

The functions save_init_fpu and unlazy_fpu do essentially the same thing:

Yes ;) Could you look at 1-3 I sent ?

Quoted 2 lines

Callers of init_fpu do want __thread_fpu_end, so move the call to __thread_fpu_end into init_fpu.

I don't think so... Contrary, I think this __thread_fpu_end() is simply wrong.

Quoted 7 lines

static inline void save_init_fpu(struct task_struct *tsk) {

arch/x86/include/asm/fpu-internal.h +0 -5
-	WARN_ON_ONCE(!__thread_has_fpu(tsk));
-
-	if (use_eager_fpu()) {
-		__save_fpu(tsk);
-		return;

arch/x86/include/asm/fpu-internal.h static inline void __save_fpu(struct task_struct *tsk) · line 532

Quoted 10 lines
arch/x86/include/asm/fpu-internal.h +5 -4
-	}
-
 	preempt_disable();
-	__save_init_fpu(tsk);
-	__thread_fpu_end(tsk);
+	if (__thread_has_fpu(tsk)) {
+		if (use_eager_fpu())
+			__save_fpu(tsk);
+		else
+			__save_init_fpu(tsk);

See the changelog in 2/3. I think we still need __thread_fpu_end() if __save_init_fpu() returns 0. In this case (_I think_) the state of FPU doesn't match the saved state. IOW, "save_init" == "save" + "init" (I guess), and that "init" can (say) reset some control register to default value.

arch/x86/include/asm/fpu-internal.h static inline void __save_fpu(struct task_struct *tsk) · line 534

Quoted 2 lines
arch/x86/include/asm/fpu-internal.h +2 -0
+	} else if (!use_eager_fpu())
+		tsk->thread.fpu_counter = 0;

See 1/3, I think this should be simply removed.

arch/x86/kernel/i387.c int init_fpu(struct task_struct *tsk) · line 238

Quoted 9 lines
arch/x86/kernel/i387.c +3 -2
@@ -245,8 +233,10 @@ int init_fpu(struct task_struct *tsk)
 	int ret;
 
 	if (tsk_used_math(tsk)) {
-		if (cpu_has_fpu && tsk == current)
-			unlazy_fpu(tsk);
+		if (cpu_has_fpu && tsk == current) {
+			save_init_fpu(tsk);
+			__thread_fpu_end(tsk);

See above.

Oleg.

#14 lore raw

cover : x86, fpu: unlazy_fpu fixes/cleanups

In reply to Rik van Riel
Quoted 3 lines · Rik van Riel

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Lets (try to) fix unlazy_fpu/save_init_fpu at least.

Dave, fpu_save_init() in do_bounds() and task_get_bounds_dir() looks wrong too, shouldn't it use unlazy_fpu() ? See the changelog in 3/3.

Oleg.

#15 lore raw

PATCH 1/3 x86, fpu: unlazy_fpu: don't reset thread.fpu_counter

It is not clear why the "else" branch clears ->fpu_counter, this makes no sense.

If use_eager_fpu() then this has no effect. Otherwise, if we actually wanted to prevent fpu preload after the context switch we would need to reset it unconditionally, even if __thread_has_fpu().

---
 arch/x86/kernel/i387.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)
arch/x86/kernel/i387.c +1 -2
index 4734865..c3b92c0 100644
@@ -122,8 +122,7 @@ void unlazy_fpu(struct task_struct *tsk)
 	if (__thread_has_fpu(tsk)) {
 		__save_init_fpu(tsk);
 		__thread_fpu_end(tsk);
-	} else
-		tsk->thread.fpu_counter = 0;
+	}
 	preempt_enable();
 }
 EXPORT_SYMBOL(unlazy_fpu);
Signature · 1 line
1.5.5.1
author Reviewed-by on v1 1/3
#16 lore raw

Re: [PATCH 1/3] x86, fpu: unlazy_fpu: don't reset thread.fpu_counter

Quoted 8 lines · Oleg Nesterov

It is not clear why the "else" branch clears ->fpu_counter, this makes no sense.

If use_eager_fpu() then this has no effect. Otherwise, if we actually wanted to prevent fpu preload after the context switch we would need to reset it unconditionally, even if __thread_has_fpu().

#17 lore raw

PATCH 2/3 x86, fpu: unlazy_fpu: don't do __thread_fpu_end() if use_eager_fpu()

In reply to Oleg Nesterov

unlazy_fpu()->__thread_fpu_end() doesn't look right if use_eager_fpu(). Unconditional __thread_fpu_end() is only correct if we know that this thread can't return to user-mode and use FPU.

Fortunately it has only 2 callers. fpu_copy() checks use_eager_fpu(), and init_fpu(current) can be only called by the coredumping thread via regset->get(). But it is exported to modules, and imo this should be fixed anyway.

And if we check use_eager_fpu() we can use __save_fpu() like fpu_copy() and save_init_fpu() do.

- It seems that even !use_eager_fpu() case doesn't need the unconditional __thread_fpu_end(), we only need it if __save_init_fpu() returns 0.

- It is still not clear to me if __save_init_fpu() can safely nest with another save + restore from __kernel_fpu_begin(). If not, we can use kernel_fpu_disable() to fix the race.

---
 arch/x86/kernel/i387.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)
arch/x86/kernel/i387.c +6 -2
index c3b92c0..8e070a6 100644
@@ -120,8 +120,12 @@ void unlazy_fpu(struct task_struct *tsk)
 {
 	preempt_disable();
 	if (__thread_has_fpu(tsk)) {
-		__save_init_fpu(tsk);
-		__thread_fpu_end(tsk);
+		if (use_eager_fpu()) {
+			__save_fpu(tsk);
+		} else {
+			__save_init_fpu(tsk);
+			__thread_fpu_end(tsk);
+		}
 	}
 	preempt_enable();
 }
Signature · 1 line
1.5.5.1
#18 lore raw

Re: [PATCH 2/3] x86, fpu: unlazy_fpu: don't do __thread_fpu_end() if use_eager_fpu()

Quoted 8 lines · Oleg Nesterov

unlazy_fpu()->__thread_fpu_end() doesn't look right if use_eager_fpu(). Unconditional __thread_fpu_end() is only correct if we know that this thread can't return to user-mode and use FPU.

Fortunately it has only 2 callers. fpu_copy() checks use_eager_fpu(), and init_fpu(current) can be only called by the coredumping thread via regset->get(). But it is exported to modules, and imo this should be fixed anyway.

What about xfpregs_set?

It looks like that code copies an entire FPU state in from userspace, and expects the kernel to start using that new FPU state.

This is called from the ptrace code.

When we switch to the traced task, the __thread_fpu_end() that was called from init_fpu() ensures that switch_fpu_begin() will actually load the new FPU state from memory into the registers, and we will not take the fpu_lazy_restore() branch.

I believe that xstateregs_set and xfpregs_set still need __thread_fpu_end().

What am I missing?

Quoted 35 lines

And if we check use_eager_fpu() we can use __save_fpu() like fpu_copy() and save_init_fpu() do.

- It seems that even !use_eager_fpu() case doesn't need the unconditional __thread_fpu_end(), we only need it if __save_init_fpu() returns 0.

- It is still not clear to me if __save_init_fpu() can safely nest with another save + restore from __kernel_fpu_begin(). If not, we can use kernel_fpu_disable() to fix the race.

---
 arch/x86/kernel/i387.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)
arch/x86/kernel/i387.c +6 -2
index c3b92c0..8e070a6 100644
@@ -120,8 +120,12 @@ void unlazy_fpu(struct task_struct *tsk)
 {
 	preempt_disable();
 	if (__thread_has_fpu(tsk)) {
-		__save_init_fpu(tsk);
-		__thread_fpu_end(tsk);
+		if (use_eager_fpu()) {
+			__save_fpu(tsk);
+		} else {
+			__save_init_fpu(tsk);
+			__thread_fpu_end(tsk);
+		}
 	}
 	preempt_enable();
 }
#19 lore raw

Re: [PATCH 2/3] x86, fpu: unlazy_fpu: don't do __thread_fpu_end() if use_eager_fpu()

Quoted 11 lines · Rik van Riel
Quoted 8 lines · Oleg Nesterov

unlazy_fpu()->__thread_fpu_end() doesn't look right if use_eager_fpu(). Unconditional __thread_fpu_end() is only correct if we know that this thread can't return to user-mode and use FPU.

Fortunately it has only 2 callers. fpu_copy() checks use_eager_fpu(), and init_fpu(current) can be only called by the coredumping thread via regset->get(). But it is exported to modules, and imo this should be fixed anyway.

Quoted 7 lines

What about xfpregs_set?

It looks like that code copies an entire FPU state in from userspace, and expects the kernel to start using that new FPU state.

This is called from the ptrace code.

Yes. But in this case tsk != current, and we ensure that __switch_to() was finished. wait_task_inactive().

Quoted 5 lines

When we switch to the traced task, the __thread_fpu_end() that was called from init_fpu() ensures that switch_fpu_begin() will actually load the new FPU state from memory into the registers, and we will not take the fpu_lazy_restore() branch.

No. in this case we rely on "tsk->thread.fpu.last_cpu = ~0" which disables fpu_lazy_restore().

Quoted 1 line

What am I missing?

Or me ;)

Oleg.

#20 lore raw

Re: [PATCH 2/3] x86, fpu: unlazy_fpu: don't do __thread_fpu_end() if use_eager_fpu()

Quoted 11 lines · Oleg Nesterov

Yes. But in this case tsk != current, and we ensure that __switch_to() was finished. wait_task_inactive().

Quoted 5 lines

When we switch to the traced task, the __thread_fpu_end() that was called from init_fpu() ensures that switch_fpu_begin() will actually load the new FPU state from memory into the registers, and we will not take the fpu_lazy_restore() branch.

No. in this case we rely on "tsk->thread.fpu.last_cpu = ~0" which disables fpu_lazy_restore().

I should have known that.

Especially considering I have a patch here that
converts "tsk->thread.fpu.last_cpu = ~0" into
a disable_lazy_restore() call...

author Reviewed-by on v1 2/3
#21 lore raw

Re: [PATCH 2/3] x86, fpu: unlazy_fpu: don't do __thread_fpu_end() if use_eager_fpu()

In reply to Oleg Nesterov
Quoted 12 lines · Oleg Nesterov

unlazy_fpu()->__thread_fpu_end() doesn't look right if use_eager_fpu(). Unconditional __thread_fpu_end() is only correct if we know that this thread can't return to user-mode and use FPU.

Fortunately it has only 2 callers. fpu_copy() checks use_eager_fpu(), and init_fpu(current) can be only called by the coredumping thread via regset->get(). But it is exported to modules, and imo this should be fixed anyway.

And if we check use_eager_fpu() we can use __save_fpu() like fpu_copy() and save_init_fpu() do.

Quoted 8 lines

- It seems that even !use_eager_fpu() case doesn't need the unconditional __thread_fpu_end(), we only need it if __save_init_fpu() returns 0.

- It is still not clear to me if __save_init_fpu() can safely nest with another save + restore from __kernel_fpu_begin(). If not, we can use kernel_fpu_disable() to fix the race.

#22 lore raw

PATCH 3/3 x86, fpu: kill save_init_fpu(), change math_error() to use unlazy_fpu()

In reply to Oleg Nesterov

math_error() calls save_init_fpu() after conditional_sti(), this means that the caller can be preempted. If !use_eager_fpu() we can hit the WARN_ON_ONCE(!__thread_has_fpu(tsk)) and/or save the wrong FPU state.

Change math_error() to use unlazy_fpu() and kill save_init_fpu().

---
 arch/x86/include/asm/fpu-internal.h |   18 ------------------
 arch/x86/kernel/traps.c             |    2 +-
 2 files changed, 1 insertions(+), 19 deletions(-)
arch/x86/include/asm/fpu-internal.h +0 -18
index e97622f..02f2e08 100644
@@ -518,24 +518,6 @@ static inline void __save_fpu(struct task_struct *tsk)
 }
 
 /*
- * These disable preemption on their own and are safe
- */
-static inline void save_init_fpu(struct task_struct *tsk)
-{
-	WARN_ON_ONCE(!__thread_has_fpu(tsk));
-
-	if (use_eager_fpu()) {
-		__save_fpu(tsk);
-		return;
-	}
-
-	preempt_disable();
-	__save_init_fpu(tsk);
-	__thread_fpu_end(tsk);
-	preempt_enable();
-}
-
-/*
  * i387 state interaction
  */
 static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
arch/x86/kernel/traps.c +1 -1
index fb4cb6a..51c4658 100644
@@ -663,7 +663,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
 	/*
 	 * Save the info for the exception handler and clear the error.
 	 */
-	save_init_fpu(task);
+	unlazy_fpu(task);
 	task->thread.trap_nr = trapnr;
 	task->thread.error_code = error_code;
 	info.si_signo = SIGFPE;
Signature · 1 line
1.5.5.1
author Reviewed-by on v1 3/3
#23 lore raw

Re: [PATCH 3/3] x86, fpu: kill save_init_fpu(), change math_error() to use unlazy_fpu()

Quoted 7 lines · Oleg Nesterov

math_error() calls save_init_fpu() after conditional_sti(), this means that the caller can be preempted. If !use_eager_fpu() we can hit the WARN_ON_ONCE(!__thread_has_fpu(tsk)) and/or save the wrong FPU state.

Change math_error() to use unlazy_fpu() and kill save_init_fpu().

maintainer
#24 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

In reply to Oleg Nesterov
Quoted 7 lines · Oleg Nesterov
Quoted 2 lines · Rik van Riel
Quoted 2 lines

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Lets (try to) fix unlazy_fpu/save_init_fpu at least.

Dave, fpu_save_init() in do_bounds() and task_get_bounds_dir() looks wrong too, shouldn't it use unlazy_fpu() ? See the changelog in 3/3.

IIRC, the 'cpu_has_xsaveopt' on the CPUs that support will MPX will enable eagerfpu. It's a bit of an indirect way to avoid the WARN_ON() and probably needs a better comment.

#25 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

Quoted 5 lines · Dave Hansen
Quoted 3 lines · Oleg Nesterov
Quoted 2 lines · Rik van Riel
Quoted 2 lines

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Quoted 7 lines
Quoted 4 lines

Lets (try to) fix unlazy_fpu/save_init_fpu at least.

Dave, fpu_save_init() in do_bounds() and task_get_bounds_dir() looks wrong too, shouldn't it use unlazy_fpu() ? See the changelog in 3/3.

IIRC, the 'cpu_has_xsaveopt' on the CPUs that support will MPX will enable eagerfpu.

unless eagerfpu=off? but this doesn't matter.

Quoted 2 lines

It's a bit of an indirect way to avoid the WARN_ON() and probably needs a better comment.

I don't think it is safe to assume that current has FPU even if eagerfpu. And note that Rik is working on patches which can change this rule.

Or I misunderstood?

Oleg.

maintainer
#26 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

Quoted 8 lines · Oleg Nesterov
Quoted 7 lines · Dave Hansen
Quoted 5 lines · Oleg Nesterov
Quoted 2 lines · Rik van Riel
Quoted 2 lines

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Lets (try to) fix unlazy_fpu/save_init_fpu at least.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Dave, fpu_save_init() in do_bounds() and task_get_bounds_dir() looks wrong too, shouldn't it use unlazy_fpu() ? See the changelog in 3/3.

IIRC, the 'cpu_has_xsaveopt' on the CPUs that support will MPX will enable eagerfpu.

unless eagerfpu=off? but this doesn't matter.

Yeah, that's true. That would also explain why I haven't run in to this at all in testing.

Ugh, fpu_save_init() says it isn't preempt safe anyway, so we shouldn't be using it.

I'll send a fix.

#27 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

Quoted 16 lines · Dave Hansen
Quoted 14 lines · Oleg Nesterov
Quoted 12 lines · Dave Hansen
Quoted 7 lines · Oleg Nesterov
Quoted 2 lines · Rik van Riel
Quoted 2 lines

Not only is this broken with my new code, but it looks like it may be broken with the current code, too...

Lets (try to) fix unlazy_fpu/save_init_fpu at least.

Dave, fpu_save_init() in do_bounds() and task_get_bounds_dir() looks wrong too, shouldn't it use unlazy_fpu() ? See the changelog in 3/3.

IIRC, the 'cpu_has_xsaveopt' on the CPUs that support will MPX will enable eagerfpu.

Quoted 7 lines
Quoted 1 line

unless eagerfpu=off? but this doesn't matter.

Yeah, that's true. That would also explain why I haven't run in to this at all in testing.

Ugh, fpu_save_init() says it isn't preempt safe anyway, so we shouldn't be using it.

Yes, plus (I _think_) _init can add more problems.

Quoted 1 line

I'll send a fix.

How about the trivial patch below (on top of this series) ?

Oleg.

arch/x86/kernel/traps.c +1 -1
@@ -313,7 +313,7 @@ dotraplinkage void do_bounds(struct pt_r
 	 * It is not directly accessible, though, so we need to
 	 * do an xsave and then pull it out of the xsave buffer.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	xsave_buf = &(tsk->thread.fpu.state->xsave);
 	bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
 	if (!bndcsr)
arch/x86/mm/mpx.c +1 -1
@@ -352,7 +352,7 @@ static __user void *task_get_bounds_dir(
 	 * The bounds directory pointer is stored in a register
 	 * only accessible if we first do an xsave.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	bndcsr = get_xsave_addr(&tsk->thread.fpu.state->xsave, XSTATE_BNDCSR);
 	if (!bndcsr)
 		return MPX_INVALID_BOUNDS_DIR;
author Reviewed-by
#28 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

Quoted 1 line · Oleg Nesterov

How about the trivial patch below (on top of this series) ?

Hey, I just typed that, too! :)

Quoted 23 lines
arch/x86/kernel/traps.c +1 -1
@@ -313,7 +313,7 @@ dotraplinkage void do_bounds(struct pt_r
 	 * It is not directly accessible, though, so we need to
 	 * do an xsave and then pull it out of the xsave buffer.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	xsave_buf = &(tsk->thread.fpu.state->xsave);
 	bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
 	if (!bndcsr)
arch/x86/mm/mpx.c +1 -1
@@ -352,7 +352,7 @@ static __user void *task_get_bounds_dir(
 	 * The bounds directory pointer is stored in a register
 	 * only accessible if we first do an xsave.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	bndcsr = get_xsave_addr(&tsk->thread.fpu.state->xsave, XSTATE_BNDCSR);
 	if (!bndcsr)
 		return MPX_INVALID_BOUNDS_DIR;
maintainer
#29 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

In reply to Oleg Nesterov
Quoted 9 lines · Oleg Nesterov
arch/x86/kernel/traps.c +1 -1
@@ -313,7 +313,7 @@ dotraplinkage void do_bounds(struct pt_r
 	 * It is not directly accessible, though, so we need to
 	 * do an xsave and then pull it out of the xsave buffer.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	xsave_buf = &(tsk->thread.fpu.state->xsave);

...

Quoted 1 line
	bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);

Hmm, if the the thread was not using the FPU, and this fails to save anything in to the xsave_buf, what will bndcsr point to? It _looks_ to me like it will just point to uninitialized data since the xsave never happened.

Fenghua, shouldn't get_xsave_addr() be checking the xstate bit against the xsave->xstate_bv?

#30 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 7 lines · Dave Hansen
Quoted 6 lines · Oleg Nesterov

--- x/arch/x86/kernel/traps.c +++ x/arch/x86/kernel/traps.c @@ -313,7 +313,7 @@ dotraplinkage void do_bounds(struct pt_r * It is not directly accessible, though, so we need to * do an xsave and then pull it out of the xsave buffer. */ -
fpu_save_init(&tsk->thread.fpu); + unlazy_fpu(tsk); xsave_buf =
&(tsk->thread.fpu.state->xsave);

Quoted 5 lines

...

Quoted 1 line

bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);

Hmm, if the the thread was not using the FPU, and this fails to save anything in to the xsave_buf, what will bndcsr point to?

If the thread was not using the FPU, can we reach the bound range exception?

I believe the MPX feature uses information in the xstate.

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUyt9yAAoJEM553pKExN6D6U4H+QENaWW78N/A9MfdluF9j1c4 mLVjsna+PrdglRNMgZPIozD/V+aONiVbEvUYt2bGuBP7PaHdvasm+05/U+SJF37z SxdjH0+1U+IZPycf0eGRkrFpZvUuegNzJyQFcvPltjRNHc7faDm3nJv+xdjDd9DX NxcvexnjhkLpXvbEIOksv/41EMjyYtDBEWwenCANCLQaGyk4VJUxXqiZ0ivqtNJX WuzVydvtDebWKPHF61qqtDCGkuuJvypWR6Wbgqe1McKqNgElT4c3f5QDLG45fKrw YaiFzBGpeFEJtDe7XLCmdlp6xUGLL2SxFn5PVdyB1toHd+V6eN//QlwAOhDJPeA= =HPaU
-----END PGP SIGNATURE-----

maintainer
#31 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

Quoted 6 lines · Rik van Riel
Quoted 2 lines
Quoted 2 lines

Hmm, if the the thread was not using the FPU, and this fails to save anything in to the xsave_buf, what will bndcsr point to?

If the thread was not using the FPU, can we reach the bound range exception?

I believe the MPX feature uses information in the xstate.

There are really two kinds of bounds exceptions. There is an "old" 'BOUND' instruction that will generate #BR's as well as the new MPX instructions. The new ones require xstate and poking the FPU, etc... The old one did not.

So, we _can_ as far as I know get in to do_bounds() without using the FPU.

#32 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

In reply to Dave Hansen
Quoted 14 lines · Dave Hansen
Quoted 9 lines · Oleg Nesterov
arch/x86/kernel/traps.c +1 -1
@@ -313,7 +313,7 @@ dotraplinkage void do_bounds(struct pt_r
 	 * It is not directly accessible, though, so we need to
 	 * do an xsave and then pull it out of the xsave buffer.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	xsave_buf = &(tsk->thread.fpu.state->xsave);

...

Quoted 1 line
	bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
Quoted 7 lines

Hmm, if the the thread was not using the FPU, and this fails to save anything in to the xsave_buf, what will bndcsr point to? It _looks_ to me like it will just point to uninitialized data since the xsave never happened.

Fenghua, shouldn't get_xsave_addr() be checking the xstate bit against the xsave->xstate_bv?

Can't really comment, but let me clarify what I meant just in case...

If it was not using FPU then I guess do_bounds() can't happen. However, it can be preempted after conditional_sti(). fpu_save_init() is obviously wrong unless __thread_has_fpu() == T, and this can be false if !eagerfpu or if we add TIF_LOAD_FPU (defer FPU restore until return to userspace).

Oleg.

#33 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

Quoted 24 lines · Oleg Nesterov
Quoted 14 lines · Dave Hansen
Quoted 9 lines · Oleg Nesterov
arch/x86/kernel/traps.c +1 -1
@@ -313,7 +313,7 @@ dotraplinkage void do_bounds(struct pt_r
 	 * It is not directly accessible, though, so we need to
 	 * do an xsave and then pull it out of the xsave buffer.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	xsave_buf = &(tsk->thread.fpu.state->xsave);

...

Quoted 1 line
	bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
Quoted 7 lines

Hmm, if the the thread was not using the FPU, and this fails to save anything in to the xsave_buf, what will bndcsr point to? It _looks_ to me like it will just point to uninitialized data since the xsave never happened.

Fenghua, shouldn't get_xsave_addr() be checking the xstate bit against the xsave->xstate_bv?

Quoted 6 lines

Can't really comment, but let me clarify what I meant just in case...

If it was not using FPU then I guess do_bounds() can't happen. However, it can be preempted after conditional_sti(). fpu_save_init() is obviously wrong unless __thread_has_fpu() == T, and this can be false if !eagerfpu or if we add TIF_LOAD_FPU (defer FPU restore until return to userspace).

Forgot to mention... and if we use unlazy_fpu() we should not worry about preemption/__thread_has_fpu, we can rely on __save_init_fpu() in __switch_to() and/or __thread_has_fpu() check in unlazy_fpu().

But I am afraid I misunderstood your concerns, sorry for noise in this case.

Oleg.

#34 lore raw

Re: [PATCH 0/3]: x86, fpu: unlazy_fpu fixes/cleanups

Quoted 33 lines · Oleg Nesterov
Quoted 24 lines · Oleg Nesterov
Quoted 14 lines · Dave Hansen
Quoted 9 lines · Oleg Nesterov
arch/x86/kernel/traps.c +1 -1
@@ -313,7 +313,7 @@ dotraplinkage void do_bounds(struct pt_r
 	 * It is not directly accessible, though, so we need to
 	 * do an xsave and then pull it out of the xsave buffer.
 	 */
-	fpu_save_init(&tsk->thread.fpu);
+	unlazy_fpu(tsk);
 	xsave_buf = &(tsk->thread.fpu.state->xsave);

...

Quoted 1 line
	bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
Quoted 7 lines

Hmm, if the the thread was not using the FPU, and this fails to save anything in to the xsave_buf, what will bndcsr point to? It _looks_ to me like it will just point to uninitialized data since the xsave never happened.

Fenghua, shouldn't get_xsave_addr() be checking the xstate bit against the xsave->xstate_bv?

Quoted 6 lines

Can't really comment, but let me clarify what I meant just in case...

If it was not using FPU then I guess do_bounds() can't happen. However, it can be preempted after conditional_sti(). fpu_save_init() is obviously wrong unless __thread_has_fpu() == T, and this can be false if !eagerfpu or if we add TIF_LOAD_FPU (defer FPU restore until return to userspace).

Quoted 5 lines

Forgot to mention... and if we use unlazy_fpu() we should not worry about preemption/__thread_has_fpu, we can rely on __save_init_fpu() in __switch_to() and/or __thread_has_fpu() check in unlazy_fpu().

But I am afraid I misunderstood your concerns, sorry for noise in this case.

Yes ;)

Perhaps do_bounds() needs the additional

	if (!used_math())
		goto exit_trap;

check?

Oleg.

#35 lore raw

cover cleanups to the disable lazy fpu restore code

In reply to Oleg Nesterov

These go on top of Oleg's patches from yesterday.

The mechanism to disable lazy FPU restore is inscrutible in several places, and dubious at best in one.

These patches make things explicit.

#36 lore raw

PATCH 1/3 x86,fpu: move lazy restore functions up a few lines

From: Rik van Riel <[email protected]>

We need another lazy restore related function, that will be called from a function that is above where the lazy restore functions are now. It would be nice to keep all three functions grouped together.

---
 arch/x86/include/asm/fpu-internal.h | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)
arch/x86/include/asm/fpu-internal.h +18 -18
index 27d00e04f911..439ac3921a1e 100644
@@ -67,6 +67,24 @@ extern void finit_soft_fpu(struct i387_soft_struct *soft);
 static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
 #endif
 
+/*
+ * Must be run with preemption disabled: this clears the fpu_owner_task,
+ * on this CPU.
+ *
+ * This will disable any lazy FPU state restore of the current FPU state,
+ * but if the current thread owns the FPU, it will still be saved by.
+ */
+static inline void __cpu_disable_lazy_restore(unsigned int cpu)
+{
+	per_cpu(fpu_owner_task, cpu) = NULL;
+}
+
+static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
+{
+	return new == this_cpu_read_stable(fpu_owner_task) &&
+		cpu == new->thread.fpu.last_cpu;
+}
+
 static inline int is_ia32_compat_frame(void)
 {
 	return config_enabled(CONFIG_IA32_EMULATION) &&
@@ -400,24 +418,6 @@ static inline void drop_init_fpu(struct task_struct *tsk)
  */
 typedef struct { int preload; } fpu_switch_t;
 
-/*
- * Must be run with preemption disabled: this clears the fpu_owner_task,
- * on this CPU.
- *
- * This will disable any lazy FPU state restore of the current FPU state,
- * but if the current thread owns the FPU, it will still be saved by.
- */
-static inline void __cpu_disable_lazy_restore(unsigned int cpu)
-{
-	per_cpu(fpu_owner_task, cpu) = NULL;
-}
-
-static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
-{
-	return new == this_cpu_read_stable(fpu_owner_task) &&
-		cpu == new->thread.fpu.last_cpu;
-}
-
 static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu)
 {
 	fpu_switch_t fpu;
Signature · 1 line
1.9.3
#37 lore raw

PATCH 2/3 x86,fpu: introduce task_disable_lazy_fpu_restore helper

In reply to [email protected]

From: Rik van Riel <[email protected]>

Currently there are a few magic assignments sprinkled through the code that disable lazy FPU state restoring, some more effective than others, and all equally mystifying.

It would be easier to have a helper to explicitly disable lazy FPU state restoring for a task.

---
 arch/x86/include/asm/fpu-internal.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/x86/include/asm/fpu-internal.h +10 -0
index 439ac3921a1e..c1f66261ad12 100644
@@ -79,6 +79,16 @@ static inline void __cpu_disable_lazy_restore(unsigned int cpu)
 	per_cpu(fpu_owner_task, cpu) = NULL;
 }
 
+/*
+ * Used to indicate that the FPU state in memory is newer than the FPU
+ * state in registers, and the FPU state should be reloaded next time the
+ * task is run. Only safe on the current task, or non-running tasks.
+ */
+static inline void task_disable_lazy_fpu_restore(struct task_struct *tsk)
+{
+	tsk->thread.fpu.last_cpu = ~0;
+}
+
 static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
 {
 	return new == this_cpu_read_stable(fpu_owner_task) &&
Signature · 1 line
1.9.3
#38 lore raw

PATCH 3/3 x86,fpu: use disable_task_lazy_fpu_restore helper

In reply to [email protected]

From: Rik van Riel <[email protected]>

Replace magic assignments of fpu.last_cpu = ~0 with more explicit disable_task_lazy_fpu_restore calls.

This also fixes the lazy FPU restore disabling in drop_fpu, which only really works when !use_eager_fpu(). This is fine for now, because fpu_lazy_restore() is only used when !use_eager_fpu() currently, but we may want to expand that.

---
 arch/x86/include/asm/fpu-internal.h | 9 +++++----
 arch/x86/kernel/i387.c              | 2 +-
 arch/x86/kernel/process.c           | 2 +-
 3 files changed, 7 insertions(+), 6 deletions(-)
arch/x86/include/asm/fpu-internal.h +5 -4
index c1f66261ad12..e2832f9dfed5 100644
@@ -396,7 +396,7 @@ static inline void drop_fpu(struct task_struct *tsk)
 	 * Forget coprocessor state..
 	 */
 	preempt_disable();
-	tsk->thread.fpu_counter = 0;
+	task_disable_lazy_fpu_restore(tsk);
 	__drop_fpu(tsk);
 	clear_used_math();
 	preempt_enable();
@@ -440,8 +440,9 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 					     new->thread.fpu_counter > 5);
 	if (__thread_has_fpu(old)) {
 		if (!__save_init_fpu(old))
-			cpu = ~0;
-		old->thread.fpu.last_cpu = cpu;
+			task_disable_lazy_fpu_restore(old);
+		else
+			old->thread.fpu.last_cpu = cpu;
 		old->thread.fpu.has_fpu = 0;	/* But leave fpu_owner_task! */
 
 		/* Don't change CR0.TS if we just switch! */
@@ -453,7 +454,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 			stts();
 	} else {
 		old->thread.fpu_counter = 0;
-		old->thread.fpu.last_cpu = ~0;
+		task_disable_lazy_fpu_restore(old);
 		if (fpu.preload) {
 			new->thread.fpu_counter++;
 			if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
arch/x86/kernel/i387.c +1 -1
index 8e070a6c30e5..8416b5f85806 100644
@@ -250,7 +250,7 @@ int init_fpu(struct task_struct *tsk)
 	if (tsk_used_math(tsk)) {
 		if (cpu_has_fpu && tsk == current)
 			unlazy_fpu(tsk);
-		tsk->thread.fpu.last_cpu = ~0;
+		task_disable_lazy_fpu_restore(tsk);
 		return 0;
 	}
 
arch/x86/kernel/process.c +1 -1
index dd9a069a5ec5..83480373a642 100644
@@ -68,8 +68,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 
 	dst->thread.fpu_counter = 0;
 	dst->thread.fpu.has_fpu = 0;
-	dst->thread.fpu.last_cpu = ~0;
 	dst->thread.fpu.state = NULL;
+	task_disable_lazy_fpu_restore(dst);
 	if (tsk_used_math(src)) {
 		int err = fpu_alloc(&dst->thread.fpu);
 		if (err)
Signature · 1 line
1.9.3
maintainer
#39 lore raw

Re: [PATCH 3/3] x86,fpu: use disable_task_lazy_fpu_restore helper

arch/x86/include/asm/fpu-internal.h static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta · line 445

Quoted 9 lines · On 01/30/2015 09:49 AM, [email protected] wrote:
arch/x86/include/asm/fpu-internal.h +3 -2
@@ -440,8 +440,9 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 					     new->thread.fpu_counter > 5);
 	if (__thread_has_fpu(old)) {
 		if (!__save_init_fpu(old))
-			cpu = ~0;
-		old->thread.fpu.last_cpu = cpu;
+			task_disable_lazy_fpu_restore(old);
+		else
+			old->thread.fpu.last_cpu = cpu;

What is the 'else' doing here? It seems a bit disconnected from the other parts of the patch.

#40 lore raw

Re: [PATCH 3/3] x86,fpu: use disable_task_lazy_fpu_restore helper

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 10 lines · Dave Hansen
Quoted 6 lines · On 01/30/2015 09:49 AM, [email protected] wrote:
(quoted diff) +0 -0
@@ -440,8 +440,9 @@ static inline fpu_switch_t

switch_fpu_prepare(struct task_struct *old, struct ta new->thread.fpu_counter > 5); if (__thread_has_fpu(old)) { if
(!__save_init_fpu(old)) - cpu = ~0; - old->thread.fpu.last_cpu
= cpu; + task_disable_lazy_fpu_restore(old); + else +
old->thread.fpu.last_cpu = cpu;

What is the 'else' doing here? It seems a bit disconnected from the other parts of the patch.

The assignment was already there before, but we would set cpu to ~0 if __save_init_fpu failed.

Now there are different branches for failure and success, with the success branch having the same assignment that was there before.

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUy/w1AAoJEM553pKExN6D/fsH/RjpQE67P368cvHl6QKa0RUo TDF0iEl4XqLT9wlYPsr+NgVJG0rFK36iVrGtKVV/uziNmk+1H43WZUt/u8tsTC1k gYptwOeBpGVyktmwdperBejTm3q4k9WLYASOvU90S2fMO5IavCpafkM5CJwojFie 0fquULSkgmyxXIJrNTNYznA2YYZaiHcKY8i05H9W0iLYbYQseQhDKl7sZ5uWcfd2 ziWmWpMKSgD0AaC1PbMm8k4kKHkbaKlabR9AyOd+9Nk5voU/pPcJOm4QgQru2ZhR 2wRdVA+MMwoglsPygV3I2OPqJN95o0JAgSTJk5DXfPuiMYoAe2+KWy5pa0ERvMo= =Fmf0
-----END PGP SIGNATURE-----

#41 lore raw

Re: [PATCH 3/3] x86,fpu: use disable_task_lazy_fpu_restore helper

In reply to Dave Hansen

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 10 lines · Dave Hansen
Quoted 6 lines · On 01/30/2015 09:49 AM, [email protected] wrote:
(quoted diff) +0 -0
@@ -440,8 +440,9 @@ static inline fpu_switch_t

switch_fpu_prepare(struct task_struct *old, struct ta new->thread.fpu_counter > 5); if (__thread_has_fpu(old)) { if
(!__save_init_fpu(old)) - cpu = ~0; - old->thread.fpu.last_cpu
= cpu; + task_disable_lazy_fpu_restore(old); + else +
old->thread.fpu.last_cpu = cpu;

What is the 'else' doing here? It seems a bit disconnected from the other parts of the patch.

Let me break that out into a separate patch, for reviewing clarity.

INCOMING!

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUz7o7AAoJEM553pKExN6DekMIAIuAFk437HUVDviJX9tx8his 2Jec8932I2+nd8OBzqBdCjiSUimLCNdT7eygf2UUdMciaNuHQ1CU1GAkM2MOglvo /ZYAGoZPbqdJZOQZp0HIzpqBGaqTjNoNfY46EVZyQgc/e3LVAfMZEF/SHhjLESEt gaJ0/ucRxl8a5C4qd29Pdgbn6jaionmEA1xrdYqfvQM32JVt4B7Qu/v2ZVCWDsCt W+TIEWFJga7u6vtKkfC4eHB0PPliMTn0N5bzCSk4zGZRtj+T8rVJ1eFcxhmEsWFs N6EF5CwGMVU0QvsWHK6Js2ELHAo+I1KJ7e/m0dHeBj/P4To835tnMh3a+IK0XWo= =rIwr
-----END PGP SIGNATURE-----

#42 lore raw

cover cleanups to lazy FPU restore code

In reply to Oleg Nesterov

These go on top of Oleg's patches.

The mechanism to disable lazy FPU restore is inscrutible in several places, and dubious at best in one.

These patches make things explicit.

They also get rid of some apparently useless or redundant code, and make fpu_lazy_restore work when in eager FPU mode.

#43 lore raw

PATCH 1/6 x86,fpu: move lazy restore functions up a few lines

From: Rik van Riel <[email protected]>

We need another lazy restore related function, that will be called from a function that is above where the lazy restore functions are now. It would be nice to keep all three functions grouped together.

---
 arch/x86/include/asm/fpu-internal.h | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)
arch/x86/include/asm/fpu-internal.h +18 -18
index 27d00e04f911..439ac3921a1e 100644
@@ -67,6 +67,24 @@ extern void finit_soft_fpu(struct i387_soft_struct *soft);
 static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
 #endif
 
+/*
+ * Must be run with preemption disabled: this clears the fpu_owner_task,
+ * on this CPU.
+ *
+ * This will disable any lazy FPU state restore of the current FPU state,
+ * but if the current thread owns the FPU, it will still be saved by.
+ */
+static inline void __cpu_disable_lazy_restore(unsigned int cpu)
+{
+	per_cpu(fpu_owner_task, cpu) = NULL;
+}
+
+static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
+{
+	return new == this_cpu_read_stable(fpu_owner_task) &&
+		cpu == new->thread.fpu.last_cpu;
+}
+
 static inline int is_ia32_compat_frame(void)
 {
 	return config_enabled(CONFIG_IA32_EMULATION) &&
@@ -400,24 +418,6 @@ static inline void drop_init_fpu(struct task_struct *tsk)
  */
 typedef struct { int preload; } fpu_switch_t;
 
-/*
- * Must be run with preemption disabled: this clears the fpu_owner_task,
- * on this CPU.
- *
- * This will disable any lazy FPU state restore of the current FPU state,
- * but if the current thread owns the FPU, it will still be saved by.
- */
-static inline void __cpu_disable_lazy_restore(unsigned int cpu)
-{
-	per_cpu(fpu_owner_task, cpu) = NULL;
-}
-
-static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
-{
-	return new == this_cpu_read_stable(fpu_owner_task) &&
-		cpu == new->thread.fpu.last_cpu;
-}
-
 static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu)
 {
 	fpu_switch_t fpu;
Signature · 1 line
1.9.3
#44 lore raw

PATCH 2/6 x86,fpu: introduce task_disable_lazy_fpu_restore helper

In reply to [email protected]

From: Rik van Riel <[email protected]>

Currently there are a few magic assignments sprinkled through the code that disable lazy FPU state restoring, some more effective than others, and all equally mystifying.

It would be easier to have a helper to explicitly disable lazy FPU state restoring for a task.

---
 arch/x86/include/asm/fpu-internal.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/x86/include/asm/fpu-internal.h +10 -0
index 439ac3921a1e..c1f66261ad12 100644
@@ -79,6 +79,16 @@ static inline void __cpu_disable_lazy_restore(unsigned int cpu)
 	per_cpu(fpu_owner_task, cpu) = NULL;
 }
 
+/*
+ * Used to indicate that the FPU state in memory is newer than the FPU
+ * state in registers, and the FPU state should be reloaded next time the
+ * task is run. Only safe on the current task, or non-running tasks.
+ */
+static inline void task_disable_lazy_fpu_restore(struct task_struct *tsk)
+{
+	tsk->thread.fpu.last_cpu = ~0;
+}
+
 static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
 {
 	return new == this_cpu_read_stable(fpu_owner_task) &&
Signature · 1 line
1.9.3
#45 lore raw

PATCH 3/6 x86,fpu: use an explicit if/else in switch_fpu_prepare

In reply to [email protected]

From: Rik van Riel <[email protected]>

Use an explicit if/else branch after __save_init_fpu(old) in switch_fpu_prepare. This makes substituting the assignment with a call to task_disable_lazy_fpu() in the next patch easier to review.

---
 arch/x86/include/asm/fpu-internal.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
arch/x86/include/asm/fpu-internal.h +3 -2
index c1f66261ad12..04063751ac80 100644
@@ -440,8 +440,9 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 					     new->thread.fpu_counter > 5);
 	if (__thread_has_fpu(old)) {
 		if (!__save_init_fpu(old))
-			cpu = ~0;
-		old->thread.fpu.last_cpu = cpu;
+			old->thread.fpu.last_cpu = ~0;
+		else
+			old->thread.fpu.last_cpu = cpu;
 		old->thread.fpu.has_fpu = 0;	/* But leave fpu_owner_task! */
 
 		/* Don't change CR0.TS if we just switch! */
Signature · 1 line
1.9.3
#46 lore raw

PATCH 4/6 x86,fpu: use disable_task_lazy_fpu_restore helper

In reply to [email protected]

From: Rik van Riel <[email protected]>

Replace magic assignments of fpu.last_cpu = ~0 with more explicit disable_task_lazy_fpu_restore calls.

This also fixes the lazy FPU restore disabling in drop_fpu, which only really works when !use_eager_fpu(). This is fine for now, because fpu_lazy_restore() is only used when !use_eager_fpu() currently, but we may want to expand that.

---
 arch/x86/include/asm/fpu-internal.h | 6 +++---
 arch/x86/kernel/i387.c              | 2 +-
 arch/x86/kernel/process.c           | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)
arch/x86/include/asm/fpu-internal.h +3 -3
index 04063751ac80..e2832f9dfed5 100644
@@ -396,7 +396,7 @@ static inline void drop_fpu(struct task_struct *tsk)
 	 * Forget coprocessor state..
 	 */
 	preempt_disable();
-	tsk->thread.fpu_counter = 0;
+	task_disable_lazy_fpu_restore(tsk);
 	__drop_fpu(tsk);
 	clear_used_math();
 	preempt_enable();
@@ -440,7 +440,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 					     new->thread.fpu_counter > 5);
 	if (__thread_has_fpu(old)) {
 		if (!__save_init_fpu(old))
-			old->thread.fpu.last_cpu = ~0;
+			task_disable_lazy_fpu_restore(old);
 		else
 			old->thread.fpu.last_cpu = cpu;
 		old->thread.fpu.has_fpu = 0;	/* But leave fpu_owner_task! */
@@ -454,7 +454,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 			stts();
 	} else {
 		old->thread.fpu_counter = 0;
-		old->thread.fpu.last_cpu = ~0;
+		task_disable_lazy_fpu_restore(old);
 		if (fpu.preload) {
 			new->thread.fpu_counter++;
 			if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
arch/x86/kernel/i387.c +1 -1
index 8e070a6c30e5..8416b5f85806 100644
@@ -250,7 +250,7 @@ int init_fpu(struct task_struct *tsk)
 	if (tsk_used_math(tsk)) {
 		if (cpu_has_fpu && tsk == current)
 			unlazy_fpu(tsk);
-		tsk->thread.fpu.last_cpu = ~0;
+		task_disable_lazy_fpu_restore(tsk);
 		return 0;
 	}
 
arch/x86/kernel/process.c +1 -1
index dd9a069a5ec5..83480373a642 100644
@@ -68,8 +68,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 
 	dst->thread.fpu_counter = 0;
 	dst->thread.fpu.has_fpu = 0;
-	dst->thread.fpu.last_cpu = ~0;
 	dst->thread.fpu.state = NULL;
+	task_disable_lazy_fpu_restore(dst);
 	if (tsk_used_math(src)) {
 		int err = fpu_alloc(&dst->thread.fpu);
 		if (err)
Signature · 1 line
1.9.3
#47 lore raw

Re: [PATCH 4/6] x86,fpu: use disable_task_lazy_fpu_restore helper

I'll try to read this patch tomorrow. Too late for me.

I think it is fine, but

Quoted 8 lines · On 02/02, [email protected] wrote:

This also fixes the lazy FPU restore disabling in drop_fpu, which only really works when !use_eager_fpu().
...

arch/x86/include/asm/fpu-internal.h static inline void drop_fpu(struct task_struct *tsk) · line 401

Quoted 7 lines
arch/x86/include/asm/fpu-internal.h +1 -1
@@ -396,7 +396,7 @@ static inline void drop_fpu(struct task_struct *tsk)
 	 * Forget coprocessor state..
 	 */
 	preempt_disable();
-	tsk->thread.fpu_counter = 0;
+	task_disable_lazy_fpu_restore(tsk);
 	__drop_fpu(tsk);
 	clear_used_math();

perhaps this makes sense anyway, but I am not sure if the changelog is right.

Note that we clear PF_USED_MATH, last_fpu/has_fpu have no effect after this.

Quoted 11 lines
arch/x86/include/asm/fpu-internal.h +1 -1
 	preempt_enable();
@@ -440,7 +440,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 					     new->thread.fpu_counter > 5);
 	if (__thread_has_fpu(old)) {
 		if (!__save_init_fpu(old))
-			old->thread.fpu.last_cpu = ~0;
+			task_disable_lazy_fpu_restore(old);
 		else
 			old->thread.fpu.last_cpu = cpu;
 		old->thread.fpu.has_fpu = 0;	/* But leave fpu_owner_task! */

arch/x86/include/asm/fpu-internal.h static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta · line 457

Quoted 5 lines
arch/x86/include/asm/fpu-internal.h +1 -1
@@ -454,7 +454,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 			stts();
 	} else {
 		old->thread.fpu_counter = 0;
-		old->thread.fpu.last_cpu = ~0;
+		task_disable_lazy_fpu_restore(old);

I am also wondering if we can remove this task_disable_lazy_fpu_restore... I mean, perhaps we should shift this into __thread_fpu_end() path. But this is almost off-topic and in any case this patch should not do this.

Oleg.

#48 lore raw

Re: [PATCH 4/6] x86,fpu: use disable_task_lazy_fpu_restore helper

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 20 lines · Oleg Nesterov

I'll try to read this patch tomorrow. Too late for me.

I think it is fine, but

Quoted 11 lines · On 02/02, [email protected] wrote:

This also fixes the lazy FPU restore disabling in drop_fpu, which only really works when !use_eager_fpu(). ...

--- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -396,7 +396,7 @@ static inline void drop_fpu(struct task_struct *tsk) * Forget coprocessor state.. */ preempt_disable(); - tsk->thread.fpu_counter = 0; + task_disable_lazy_fpu_restore(tsk); __drop_fpu(tsk); clear_used_math();

perhaps this makes sense anyway, but I am not sure if the changelog is right.

Quoted 2 lines

Note that we clear PF_USED_MATH, last_fpu/has_fpu have no effect after this.

There are several code paths, including signal handler stack setup and teardown, where we first clear PF_USED_MATH, but later on set it again, after setting up a new math state for the task.

We need to ensure we always use that new math state, and never lazily re-use what is still in the FPU registers.

Quoted 11 lines
Quoted 10 lines

preempt_enable(); @@ -440,7 +440,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta new->thread.fpu_counter > 5); if (__thread_has_fpu(old)) { if
(!__save_init_fpu(old)) - old->thread.fpu.last_cpu = ~0; +
task_disable_lazy_fpu_restore(old); else old->thread.fpu.last_cpu
= cpu; old->thread.fpu.has_fpu = 0; /* But leave fpu_owner_task!
*/ @@ -454,7 +454,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta stts(); }
else { old->thread.fpu_counter = 0; - old->thread.fpu.last_cpu =
~0; + task_disable_lazy_fpu_restore(old);

Quoted 4 lines

I am also wondering if we can remove this task_disable_lazy_fpu_restore... I mean, perhaps we should shift this into __thread_fpu_end() path. But this is almost off-topic and in any case this patch should not do this.

Good question. I also wonder why this last_cpu = ~0 is there anyway. If !__thread_has_fpu(old), then I don't see how the lazy restore code would ever give a false positive on that CPU.

Either nobody else used the FPU and the task's state is still there, or somebody else did, and the fpu_owner_task will be pointing elsewhere.

It may be possible to simply remove this one completely, but like you said, that should probably be a different patch.

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUz9NaAAoJEM553pKExN6DuLwH/2tUl/BZ//yjXDuv9U8PeSP9 tgqyTIuM9j36qtT9jG+iX84IDGxm1AATLXI9HQbl3KkPuAYSKo9ECnxJZO0IaDeu vCuhtNlSnP/Fr/xe8CZ1LcWNgQBEJLINkYZn5paA5qQybsr+Z/Ll/c0/0DuGooRt 8iIGYAFHyaUJx8dkinbaaLCwP9Fg5oeXx7PAi7kpRsRtMOo1LSTZEbCTx/zIlc7L vjz+vipQuRJxzxzwqHhE6TFpCG7c/0QiUcECoVQ13zTPAumFX23w6BSr/4llWrr9 XV0Q9vExthrcIPZynchUnsTTBGT5gVYwXL1FI3b907gFqXYDXMWPRYlXm6pneY4= =2c6g
-----END PGP SIGNATURE-----

#49 lore raw

Re: [PATCH 4/6] x86,fpu: use disable_task_lazy_fpu_restore helper

Quoted 28 lines · Rik van Riel

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 20 lines · Oleg Nesterov

I'll try to read this patch tomorrow. Too late for me.

I think it is fine, but

Quoted 11 lines · On 02/02, [email protected] wrote:

This also fixes the lazy FPU restore disabling in drop_fpu, which only really works when !use_eager_fpu(). ...

--- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -396,7 +396,7 @@ static inline void drop_fpu(struct task_struct *tsk) * Forget coprocessor state.. */ preempt_disable(); - tsk->thread.fpu_counter = 0; + task_disable_lazy_fpu_restore(tsk); __drop_fpu(tsk); clear_used_math();

perhaps this makes sense anyway, but I am not sure if the changelog is right.

Quoted 2 lines

Note that we clear PF_USED_MATH, last_fpu/has_fpu have no effect after this.

Quoted 6 lines

There are several code paths, including signal handler stack setup and teardown, where we first clear PF_USED_MATH, but later on set it again, after setting up a new math state for the task.

We need to ensure we always use that new math state, and never lazily re-use what is still in the FPU registers.

Still can't understand....

I can only see only on example of re-setting PF_USED_MATH if eager_fpu, __restore_xstate_sig() does drop_fpu() + math_state_restore(). And this case looks fine in this sense...

Although let me repeat that imho math_state_restore() and all current users (including flush_thread() added by "don't abuse FPU in kernel threads") need cleanups in any case. I was going to (try to) do this if/when that series is applied. In particular, in this case math_state_restore() will wrongly return with irqs disabled or I am totally confused.

And set_used_math() if copy_from_user() fails doesn't look right, but this is another story.

If I missed something, perhaps you can update the changelog to explain how exactly it fixes drop_fpu? Otherwise, imo this patch should not change it. As we already discussed, we can probably cleanup this disable_lazy_fpu logic, but this needs another change/discussion.

Oleg.

#50 lore raw

Re: [PATCH 4/6] x86,fpu: use disable_task_lazy_fpu_restore helper

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 54 lines · Oleg Nesterov
Quoted 27 lines · Rik van Riel

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1

Quoted 20 lines · Oleg Nesterov

I'll try to read this patch tomorrow. Too late for me.

I think it is fine, but

Quoted 11 lines · On 02/02, [email protected] wrote:

This also fixes the lazy FPU restore disabling in drop_fpu, which only really works when !use_eager_fpu(). ...

--- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -396,7 +396,7 @@ static inline void drop_fpu(struct task_struct *tsk) * Forget coprocessor state.. */ preempt_disable(); - tsk->thread.fpu_counter = 0; + task_disable_lazy_fpu_restore(tsk); __drop_fpu(tsk); clear_used_math();

perhaps this makes sense anyway, but I am not sure if the changelog is right.

Quoted 2 lines

Note that we clear PF_USED_MATH, last_fpu/has_fpu have no effect after this.

Quoted 6 lines

There are several code paths, including signal handler stack setup and teardown, where we first clear PF_USED_MATH, but later on set it again, after setting up a new math state for the task.

We need to ensure we always use that new math state, and never lazily re-use what is still in the FPU registers.

Still can't understand....

I can only see only on example of re-setting PF_USED_MATH if eager_fpu, __restore_xstate_sig() does drop_fpu() + math_state_restore(). And this case looks fine in this sense...

Although let me repeat that imho math_state_restore() and all current users (including flush_thread() added by "don't abuse FPU in kernel threads") need cleanups in any case. I was going to (try to) do this if/when that series is applied. In particular, in this case math_state_restore() will wrongly return with irqs disabled or I am totally confused.

And set_used_math() if copy_from_user() fails doesn't look right, but this is another story.

Quoted 5 lines

If I missed something, perhaps you can update the changelog to explain how exactly it fixes drop_fpu? Otherwise, imo this patch should not change it. As we already discussed, we can probably cleanup this disable_lazy_fpu logic, but this needs another change/discussion.

I don't think this changes the behaviour of any code path as the kernel currently stands.

However, having drop_fpu() disable lazy restore in a more explicit way may help us going forward, with the "delay FPU state restore to kernel -> user space switch" series.

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJU0UUxAAoJEM553pKExN6DzSMIAIuPNXZ8P5zHAPMLePQhfaZK QaatOplJ5F8GNN3bT2sJHLIPfDJVokMbGFv7ff8/jPsZ03uBm6onFPp/4Qn7dGZ4 FQyFX7OkmR7D4NJ0KZ9J1ghWhfRhmxfAqr/qwrdovUJ/Hfz73FdqGPYpP90qvY/2 0psSaW6ubJen6l9QYBear5juhQE3+akfwc/D1ItpZtZRUHOJTewBiww/9I/kUrDZ mp1j4szVEjaQ9jB5Et4KO4EFaaEFzdj2JXwSV10neBgLrZ5dixYII1kUFQQFxvTd bse2Rjsh0+6ESkUOoXLy1y0IYbjrQqEc+YdrGbnf64XJLIjj1a8U8F3dU5xPdCM= =0+mw
-----END PGP SIGNATURE-----

#51 lore raw

Re: [PATCH 4/6] x86,fpu: use disable_task_lazy_fpu_restore helper

In reply to Oleg Nesterov

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 20 lines · Oleg Nesterov

I'll try to read this patch tomorrow. Too late for me.

I think it is fine, but

Quoted 11 lines · On 02/02, [email protected] wrote:

This also fixes the lazy FPU restore disabling in drop_fpu, which only really works when !use_eager_fpu(). ...

--- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -396,7 +396,7 @@ static inline void drop_fpu(struct task_struct *tsk) * Forget coprocessor state.. */ preempt_disable(); - tsk->thread.fpu_counter = 0; + task_disable_lazy_fpu_restore(tsk); __drop_fpu(tsk); clear_used_math();

perhaps this makes sense anyway, but I am not sure if the changelog is right.

Quoted 2 lines

Note that we clear PF_USED_MATH, last_fpu/has_fpu have no effect after this.

After a few days on the RCU code, I'm back to this :)

You are right, I should drop the change above from the patch, and disable lazy fpu restore explicitly in places where we need it.

I will send a v2 of these patches, without patch 6/6.

Ingo, would you like me to also re-send Oleg's FPU patches that are not in -tip yet?

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJU1O71AAoJEM553pKExN6DUtEH/R8X02MHD7GUxO4hyiLECL9f SQDdF1l+1rqcQo7e+5nRJ5/rFvAIaNA5oBMOZJ9MlJRd6HOKS+VqLLpb8idvApeK zRiYUdeyoui3e0po2nNCx/GBfXqMYca+qH4JMMq6gzv0c9Nm9Zq9pbKDbO2znns8 10YQexvZsHUiJgt63YoZSwxFKD1iAhnTOGBhZOJu/s27Qtu+7gyuyIcuMMDFj2eu ACGqZPcjG2u7TlC+D4uivSferMrduNnWsxGq3AY32/nNhjKGmXaFJxRHDdCsYAGJ +S+SFuUWq6JoD7MuC02NQyAs/bQzqhVfn8v7gm2gromqIIQGzBABtI+Em0LGFP4= =3R+T
-----END PGP SIGNATURE-----

#52 lore raw

PATCH 5/6 x86,fpu: also check fpu_lazy_restore when use_eager_fpu

In reply to [email protected]

From: Rik van Riel <[email protected]>

With Oleg's patch "x86, fpu: don't abuse FPU in kernel threads if use_eager_fpu()", kernel threads no longer have an FPU state even on systems with use_eager_fpu()

That in turn means that a task may still have its FPU state loaded in the FPU registers, if the task only got interrupted by kernel threads from when it went to sleep, to when it woke up again.

In that case, there is no need to restore the FPU state for this task, since it is still in the registers.

The kernel can simply use the same logic to determine this as is used for !use_eager_fpu() systems.

---
 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 e2832f9dfed5..085903415cbd 100644
@@ -457,7 +457,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 		task_disable_lazy_fpu_restore(old);
 		if (fpu.preload) {
 			new->thread.fpu_counter++;
-			if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
+			if (fpu_lazy_restore(new, cpu))
 				fpu.preload = 0;
 			else
 				prefetch(new->thread.fpu.state);
Signature · 1 line
1.9.3
#53 lore raw

Re: [PATCH 5/6] x86,fpu: also check fpu_lazy_restore when use_eager_fpu

Quoted 12 lines · On 02/02, [email protected] wrote:

From: Rik van Riel <[email protected]>

With Oleg's patch "x86, fpu: don't abuse FPU in kernel threads if use_eager_fpu()", kernel threads no longer have an FPU state even on systems with use_eager_fpu()

That in turn means that a task may still have its FPU state loaded in the FPU registers, if the task only got interrupted by kernel threads from when it went to sleep, to when it woke up again.

Quoted 5 lines

In that case, there is no need to restore the FPU state for this task, since it is still in the registers.

The kernel can simply use the same logic to determine this as is used for !use_eager_fpu() systems.

Yes, agreed, I was going to do this too.

And in fact this change make sense even without "don't abuse FPU in kernel threads", I think.

But in theory it depends on another change, "__kernel_fpu_begin() should clear fpu_owner_task even if use_eager_fpu()".

And that series was ignored ;)

I think this patch is fine.

Quoted 14 lines
arch/x86/include/asm/fpu-internal.h +1 -2
@@ -457,7 +457,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 		task_disable_lazy_fpu_restore(old);
 		if (fpu.preload) {
 			new->thread.fpu_counter++;
-			if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
+			if (fpu_lazy_restore(new, cpu))
 				fpu.preload = 0;
 			else
 				prefetch(new->thread.fpu.state);
--

1.9.3

#54 lore raw

Re: [PATCH 5/6] x86,fpu: also check fpu_lazy_restore when use_eager_fpu

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 24 lines · Oleg Nesterov
Quoted 12 lines · On 02/02, [email protected] wrote:

From: Rik van Riel <[email protected]>

With Oleg's patch "x86, fpu: don't abuse FPU in kernel threads if use_eager_fpu()", kernel threads no longer have an FPU state even on systems with use_eager_fpu()

That in turn means that a task may still have its FPU state loaded in the FPU registers, if the task only got interrupted by kernel threads from when it went to sleep, to when it woke up again.

Quoted 5 lines

In that case, there is no need to restore the FPU state for this task, since it is still in the registers.

The kernel can simply use the same logic to determine this as is used for !use_eager_fpu() systems.

Yes, agreed, I was going to do this too.

And in fact this change make sense even without "don't abuse FPU in kernel threads", I think.

Quoted 6 lines

But in theory it depends on another change, "__kernel_fpu_begin() should clear fpu_owner_task even if use_eager_fpu()".

And that series was ignored ;)

I think this patch is fine.

Ingo,

does the FPU code have a sub-maintainer, or should all the FPU patches go straight through you?

Would it be better for you if FPU patches came through a git tree you could just pull?

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUz83HAAoJEM553pKExN6DqrQH/iP5cfUUtIqguM4oS19WO33Y 5H/wdjVIGOJw4Rt7U+550Y9m5VMXsuQrO17PagjZGsxbSm9QQhA6esVMDvXfOFH1 taWW1tFog4VTMueNYbOC5asqsicTrhNqfiLQFM9CmJFGOPO4lDQ9n+OPS64CkQ/d onylevtR4UWjggpEdkoOlmvbQH8RhnaC4JWKSXxP06YBakfP41gIMMfAjFNMP9O4 b/r1nU/WBQsTSX7pzQMnEx/Igp9LkT+X0Y93NerF/0O7gic9Wv7tKTEaUa3DzS7p U7xgT8xX88AJ6QQGQfB3IQSkjcb3N9UCY1CYkkWqigm9MhhlLxPyRDAy7vkrUlk= =j/eO
-----END PGP SIGNATURE-----

#55 lore raw

PATCH 6/6 x86,fpu: remove redundant increments of fpu_counter

In reply to [email protected]

From: Rik van Riel <[email protected]>

fpu.preload only gets set if new->thread.fpu_counter is already larger than 5. Incrementing it further does absolutely nothing. Remove those lines.

---
 arch/x86/include/asm/fpu-internal.h | 2 --
 1 file changed, 2 deletions(-)
arch/x86/include/asm/fpu-internal.h +0 -2
index 085903415cbd..88df5808a2db 100644
@@ -447,7 +447,6 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 
 		/* Don't change CR0.TS if we just switch! */
 		if (fpu.preload) {
-			new->thread.fpu_counter++;
 			__thread_set_has_fpu(new);
 			prefetch(new->thread.fpu.state);
 		} else if (!use_eager_fpu())
@@ -456,7 +455,6 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 		old->thread.fpu_counter = 0;
 		task_disable_lazy_fpu_restore(old);
 		if (fpu.preload) {
-			new->thread.fpu_counter++;
 			if (fpu_lazy_restore(new, cpu))
 				fpu.preload = 0;
 			else
Signature · 1 line
1.9.3
#56 lore raw

Re: [PATCH 6/6] x86,fpu: remove redundant increments of fpu_counter

Quoted 6 lines · On 02/02, [email protected] wrote:

From: Rik van Riel <[email protected]>

fpu.preload only gets set if new->thread.fpu_counter is already larger than 5. Incrementing it further does absolutely nothing. Remove those lines.

I _think_ that we increment it further on purpose. Note that fpu_counter is "char", so it seems that we want no more than 256 automatic preloads.

So I am not sure about this change. At least the changelog doesn't look right.

Oleg.

Quoted 21 lines
arch/x86/include/asm/fpu-internal.h +0 -2
@@ -447,7 +447,6 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 
 		/* Don't change CR0.TS if we just switch! */
 		if (fpu.preload) {
-			new->thread.fpu_counter++;
 			__thread_set_has_fpu(new);
 			prefetch(new->thread.fpu.state);
 		} else if (!use_eager_fpu())
@@ -456,7 +455,6 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
 		old->thread.fpu_counter = 0;
 		task_disable_lazy_fpu_restore(old);
 		if (fpu.preload) {
-			new->thread.fpu_counter++;
 			if (fpu_lazy_restore(new, cpu))
 				fpu.preload = 0;
 			else
Signature · 1 line
1.9.3
#57 lore raw

Re: [PATCH 6/6] x86,fpu: remove redundant increments of fpu_counter

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 8 lines · Oleg Nesterov
Quoted 6 lines · On 02/02, [email protected] wrote:

From: Rik van Riel <[email protected]>

fpu.preload only gets set if new->thread.fpu_counter is already larger than 5. Incrementing it further does absolutely nothing. Remove those lines.

Quoted 6 lines

I _think_ that we increment it further on purpose. Note that fpu_counter is "char", so it seems that we want no more than 256 automatic preloads.

So I am not sure about this change. At least the changelog doesn't look right.

You are right, lets drop this patch 6/6.

Do the other five look right?

- --
All rights reversed
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJUz8SFAAoJEM553pKExN6DQOcH/1+BrG+jIItcfZG3KwnN3Dfv nXtmlNRiopMTJQ3HxzYEBT40zuqnKDSsf2cvMkcVJjt3oUukbD8D22iyJQzQxKnZ g1MSJmZzSFZ1D0hoI/Qv3OLjyYJtcI4BaTHvs8f/YSmovTLY9D3e4zD37RbQp2d4 S0PdX/xxJBHpdJtFNaQni1VE9isIPh5x0YK8T55t5WhwRM+JwH+8C3mlL28ZEyQl +BclNypHDiFKct+TL9NK+2RBRC2qwjuZzLi0BVrF49yK8G+Zw+8026vGrUOnx6Gg XICJbyZbkBtn2J7Mc8i2xT2U4fYUy6pjcNuh0OiDSCV1f47iznBN0MjRwzc8ugo= =mOwp
-----END PGP SIGNATURE-----

#58 lore raw

Re: [PATCH 6/6] x86,fpu: remove redundant increments of fpu_counter

Quoted 6 lines · Rik van Riel
Quoted 2 lines

So I am not sure about this change. At least the
changelog doesn't look right.

You are right, lets drop this patch 6/6.

Do the other five look right?

Is there consensus on the first 5 patches?

Thanks,

Ingo

maintainer
#59 lore raw

Re: [PATCH 6/6] x86,fpu: remove redundant increments of fpu_counter

Quoted 1 line · Ingo Molnar

Is there consensus on the first 5 patches?

I've picked up that series here:

https://lkml.kernel.org/r/[email protected]

Maybe I should reply when picking up stuff so that we don't overlap.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#60 lore raw

Re: [PATCH 6/6] x86,fpu: remove redundant increments of fpu_counter

In reply to Ingo Molnar

Borislav, Ingo,

Quoted 2 lines · Ingo Molnar

Is there consensus on the first 5 patches?

Yes, but perhaps you can also look at another series

	[PATCH 1/3] x86, fpu: __kernel_fpu_begin() should clear fpu_owner_task even if use_eager_fpu()
	http://marc.info/?l=linux-kernel&m=142169357231860&w=2

	[PATCH 2/3] x86, fpu: always allow FPU in interrupt if use_eager_fpu()
	http://marc.info/?l=linux-kernel&m=142169359331866&w=2

	[PATCH 3/3] x86, fpu: don't abuse FPU in kernel threads if use_eager_fpu()
	http://marc.info/?l=linux-kernel&m=142169360931869&w=2

? (off course I will be happy to resend)

It was sent before the recently applied changes. And in fact in theory 728e53fef429a0f "x86/fpu: Also check fpu_lazy_restore() when use_eager_fpu()" depends on 1/3 above.

Oleg.