From: Oleg Nesterov <oleg@redhat.com>
To: Suresh Siddha <sbsiddha@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
Al Viro <viro@zeniv.linux.org.uk>,
Andrew Morton <akpm@linux-foundation.org>,
Fenghua Yu <fenghua.yu@intel.com>,
Bean Anderson <bean@azulsystems.com>,
"H. Peter Anvin" <hpa@zytor.com>, Ingo Molnar <mingo@redhat.com>,
Thomas Gleixner <tglx@linutronix.de>,
the arch/x86 maintainers <x86@kernel.org>,
Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH 4/4] x86, fpu: irq_fpu_usable: kill all checks except !in_kernel_fpu
Date: Tue, 2 Sep 2014 14:58:10 +0200 [thread overview]
Message-ID: <20140902125810.GB18534@redhat.com> (raw)
In-Reply-To: <CALmL7E8mTeALSjSXkgVQs=KW9AX5K4r5k63foiP0Vy5ue8Vfgg@mail.gmail.com>
On 09/02, Suresh Siddha wrote:
>
> On Fri, Aug 29, 2014 at 11:17 AM, Oleg Nesterov <oleg@redhat.com> wrote:
> > ONCE AGAIN, THIS IS MORE THE QUESTION THAN THE PATCH.
>
> this patch I think needs more thought for sure. please see below.
Of course.
> > interrupted_kernel_fpu_idle() does:
> >
> > if (use_eager_fpu())
> > return true;
> >
> > return !__thread_has_fpu(current) &&
> > (read_cr0() & X86_CR0_TS);
> >
> > and it is absolutely not clear why these 2 cases differ so much.
> >
> > To remind, the use_eager_fpu() case is buggy; __save_init_fpu() in
> > __kernel_fpu_begin() can race with math_state_restore() which does
> > __thread_fpu_begin() + restore_fpu_checking(). So we should fix this
> > race anyway and we can't require __thread_has_fpu() == F likes the
> > !use_eager_fpu() case does, in this case kernel_fpu_begin() will not
> > work if it interrupts the idle thread (this will reintroduce the
> > performance regression fixed by 5187b28f).
> >
> > Probably math_state_restore() can use kernel_fpu_disable/end() which
> > sets/clears in_kernel_fpu, or it can disable irqs. Doesn't matter, we
> > should fix this bug anyway.
> >
> > And if we fix this bug, why else !use_eager_fpu() case needs the much
> > more strict check? Why we can't handle the __thread_has_fpu(current)
> > case the same way?
> >
> > The comment deleted by this change says:
> >
> > and TS must be set so that the clts/stts pair does nothing
> >
> > and can explain the difference, but I can not understand this (again,
> > assuming that we fix the race(s) mentoined above).
> >
> > Say, user_fpu_begin(). Yes, kernel_fpu_begin/end() can restore X86_CR0_TS.
> > But this should be fine?
>
> No. The reason is that has_fpu state and cr0.TS can get out of sync.
>
> Let's say you get an interrupt after clts() in __thread_fpu_begin()
> called as part of user_fpu_begin().
>
> And because of this proposed change, irq_fpu_usable() returns true and
> an interrupt can end-up using fpu and after the return from interrupt
> we can have a state where cr0.TS is set but we end up resuming the
> execution from __thread_set_has_fpu(). Now after this point has_fpu is
> set but cr0.TS is set. And now any schedule() with this state (let's
> say immd after preemption_enable() at the end of user_fpu_begin()) is
> dangerous. We can get a dna fault in the middle of __switch_to() which
> can lead to subtle bugs.
Thanks. Yes, I thought about this race, but I didn't realize that a DNA
inside __switch_to() is dangerous.
Thanks a lot. OK, this is trivially fixable. I had this v2 in mind from
the very beginning because I was not really sure that unconditional stts()
in kernel_fpu_end() is safe (but yes, I didn't realize why). Just we need
to save X86_CR0_TS in the same per-cpu in_kernel_fpu,
static DEFINE_PER_CPU(int, in_kernel_fpu);
void __kernel_fpu_begin(void)
{
struct task_struct *me = current;
this_cpu_write(in_kernel_fpu, 1);
if (__thread_has_fpu(me)) {
__save_init_fpu(me);
} else if (!use_eager_fpu()) {
this_cpu_write(fpu_owner_task, NULL);
if ((read_cr0() & X86_CR0_TS))
this_cpu_write(in_kernel_fpu, 2);
clts();
}
}
}
void __kernel_fpu_end(void)
{
struct task_struct *me = current;
if (__thread_has_fpu(me)) {
if (WARN_ON(restore_fpu_checking(me)))
drop_init_fpu(me);
} else if (!use_eager_fpu()) {
if (this_cpu_read(in_kernel_fpu) == 2)
stts();
}
this_cpu_write(in_kernel_fpu, 0);
}
Or, perhaps better, we can turn user_fpu_begin()->preempt_disable()
into kernel_fpu_disable().
Do you think this can work?
> other than this patch, rest of the changes look ok to me. Can you
> please resend this patchset with the math_state_restore() race
> addressed aswell?
OK, will do, but probably next week.
Will you agree if I add kernel_fpu_disable/enable to fix this race?
It can probably have more users (see above).
Thanks!
Oleg.
next prev parent reply other threads:[~2014-09-02 13:00 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-27 18:51 [PATCH 0/4] x86, fpu: copy_process's FPU paths cleanups Oleg Nesterov
2014-08-27 18:51 ` [PATCH 1/4] x86, fpu: change __thread_fpu_begin() to use use_eager_fpu() Oleg Nesterov
2014-08-27 18:51 ` [PATCH 2/4] x86, fpu: copy_process: avoid fpu_alloc/copy if !used_math() Oleg Nesterov
2014-08-27 18:52 ` [PATCH 3/4] x86, fpu: copy_process: sanitize fpu->last_cpu initialization Oleg Nesterov
2014-08-27 18:52 ` [PATCH 4/4] x86, fpu: shift "fpu_counter = 0" from copy_thread() to arch_dup_task_struct() Oleg Nesterov
2014-08-27 20:43 ` [PATCH 0/4] x86, fpu: copy_process's FPU paths cleanups H. Peter Anvin
2014-08-28 6:50 ` Ingo Molnar
2014-08-28 12:25 ` Oleg Nesterov
2014-08-28 10:38 ` Oleg Nesterov
2014-08-28 1:17 ` Linus Torvalds
2014-08-28 11:16 ` Oleg Nesterov
2014-08-29 18:15 ` [PATCH 0/4] x86, fpu: kernel_fpu_begin/end cleanups Oleg Nesterov
2014-08-29 18:16 ` [PATCH 1/4] x86, fpu: introduce per-cpu "bool in_kernel_fpu" Oleg Nesterov
2014-09-02 6:43 ` Suresh Siddha
2014-08-29 18:16 ` [PATCH 2/4] x86, fpu: don't abuse ->has_fpu in __kernel_fpu_begin/end Oleg Nesterov
2014-08-29 18:17 ` [PATCH 3/4] x86, fpu: irq_fpu_usable: always return true if use_eager_fpu() Oleg Nesterov
2014-08-29 18:17 ` [PATCH 4/4] x86, fpu: irq_fpu_usable: kill all checks except !in_kernel_fpu Oleg Nesterov
2014-09-02 7:04 ` Suresh Siddha
2014-09-02 12:58 ` Oleg Nesterov [this message]
2014-09-02 14:13 ` Oleg Nesterov
2014-09-02 5:04 ` [PATCH 0/4] x86, fpu: copy_process's FPU paths cleanups Suresh Siddha
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140902125810.GB18534@redhat.com \
--to=oleg@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=bean@azulsystems.com \
--cc=fenghua.yu@intel.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=sbsiddha@gmail.com \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=viro@zeniv.linux.org.uk \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.