From owner-freebsd-hackers@FreeBSD.ORG Thu Mar 27 12:07:31 2014 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id AE31C322 for ; Thu, 27 Mar 2014 12:07:31 +0000 (UTC) Received: from kib.kiev.ua (kib.kiev.ua [IPv6:2001:470:d5e7:1::1]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 319F1895 for ; Thu, 27 Mar 2014 12:07:31 +0000 (UTC) Received: from tom.home (kostik@localhost [127.0.0.1]) by kib.kiev.ua (8.14.8/8.14.8) with ESMTP id s2RC7Lq6051073; Thu, 27 Mar 2014 14:07:21 +0200 (EET) (envelope-from kostikbel@gmail.com) DKIM-Filter: OpenDKIM Filter v2.8.3 kib.kiev.ua s2RC7Lq6051073 Received: (from kostik@localhost) by tom.home (8.14.8/8.14.8/Submit) id s2RC7KYX051072; Thu, 27 Mar 2014 14:07:20 +0200 (EET) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: tom.home: kostik set sender to kostikbel@gmail.com using -f Date: Thu, 27 Mar 2014 14:07:20 +0200 From: Konstantin Belousov To: Chris Torek Subject: Re: slight problem with r254457 (kthread_add fix) Message-ID: <20140327120720.GN21331@kib.kiev.ua> References: <201403270902.s2R92nPo064876@elf.torek.net> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="dngyMJhgXGAL5Gb8" Content-Disposition: inline In-Reply-To: <201403270902.s2R92nPo064876@elf.torek.net> User-Agent: Mutt/1.5.23 (2014-03-12) X-Spam-Status: No, score=-2.0 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FROM,NML_ADSP_CUSTOM_MED autolearn=no autolearn_force=no version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on tom.home Cc: freebsd-hackers@freebsd.org X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Mar 2014 12:07:31 -0000 --dngyMJhgXGAL5Gb8 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Mar 27, 2014 at 03:02:49AM -0600, Chris Torek wrote: > This fix: >=20 > http://lists.freebsd.org/pipermail/svn-src-head/2013-August/050550.html >=20 > has introduced a bit of a problem with kernel threads that enable > the FPU, on amd64. >=20 > Before the fix, a new thread added to proc0 (when kthread_add() is > called with p =3D=3D NULL) was essentially "forked from" thread0: >=20 > if (p =3D=3D NULL) { > p =3D &proc0; > oldtd =3D &thread0; > } >=20 > Now, each such new thread "forks from" the *newest* thread in proc0: >=20 > if (p =3D=3D NULL) > p =3D &proc0; > ... > PROC_LOCK(p); > oldtd =3D FIRST_THREAD_IN_PROC(p); >=20 > The problem is that "first thread in proc" is really the *last* > (i.e., most recent) thread in the proc, as thread_link() does a > TAILQ_INSERT_HEAD() on p->p_threads, and FIRST_THREAD_IN_PROC > takes the TAILQ_FIRST element. >=20 > What this means is that if something enables the FPU (e.g., a > device creates a taskq thread and enables the FPU in that thread, > so that the device can use XMM registers), every subsequent taskq > also has the FPU enabled. (We found this by unconditionally > enabling the extensions in various threads, assuming that new ones > did not have FPU enabled for kernel use yet. That worked until > we picked up this particular change.) >=20 > The fix itself is fine but "forking from" the most-recent kernel > thread, rather than thread0, for this case seems wrong. I see > three obvious ways to fix *that*: >=20 > - Restore the old behavior: >=20 > if (p =3D=3D NULL) { > p =3D &proc0; > oldtd =3D &thread0; > } else > oldtd =3D NULL; > ... > PROC_LOCK(p); > if (oldtd =3D=3D NULL) > oldtd =3D FIRST_THREAD_IN_PROC(p); >=20 > Conservative, will definitely work, but still seems a bit odd > behavior-wise: a new "not in a proc" kthread clones from thread0, > but a new "is in a proc" kthread clones from most-recent-thread > in that kernel proc. (But that's what this did before the fix, > modulo the bug where it cloned from a dead thread...) >=20 > - Pick the *last* (i.e., earliest still-alive) thread in the proc: >=20 > PROC_LOCK(p); > oldtd =3D LAST_THREAD_IN_PROC(p); >=20 > where LAST_THREAD_IN_PROC uses the tail entry on the tailq > (pretty straightforward). >=20 > - Get rid of FIRST_THREAD_IN_PROC entirely, as it's not clear > what "first" means (at least it was not to me: I assumed at > first that it meant the *oldest*, i.e., first-created, one): > add new macro accessors NEWEST_THREAD_IN_PROC, > OLDEST_THREAD_IN_PROC, and (for when you don't care about > order) SOME_THREAD_IN_PROC [%], and start using those where > appropriate. The thread_link() routine then puts "newest" and > "oldest" at whichever end of the tailq is best for kernel code > space/speed, and only it and the macros need to agree. >=20 > [% Needs better name. Perhaps just THREAD_IN_PROC?] >=20 > I actually like the last option best, but it is the largest > overall change and it messes with all kinds of other kernel code > (there are 62 occurrences of FIRST_THREAD_IN_PROC in a count I > just ran). However, it becomes clearer which thread is really > wanted. >=20 > (I'm going to do the first fix, for now at least, in our kernel.) I agree with the problem statement, but disagree with the proposed 'fix'. I.e., I agree that on the creation of a new kernel thread, the current thread FPU grab state must not leak into the created thread. In fact, cpu_set_upcall() already almost handles this correctly, by resetting the pcb_save pointer back to the user save area. What is not done is the clearing of PCB_KERNFPU flag, which seems to be the issue you met. Am I right ? If yes, then the following patch should handle the problem, hopefully. diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index 335a9c9..bc7b311 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -446,7 +446,8 @@ cpu_set_upcall(struct thread *td, struct thread *td0) * values here. */ bcopy(td0->td_pcb, pcb2, sizeof(*pcb2)); - clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE); + clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE | + PCB_KERNFPU); pcb2->pcb_save =3D get_pcb_user_save_pcb(pcb2); bcopy(get_pcb_user_save_td(td0), pcb2->pcb_save, cpu_max_ext_state_size); diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index ba61bdf..3562954 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -457,7 +457,8 @@ cpu_set_upcall(struct thread *td, struct thread *td0) * values here. */ bcopy(td0->td_pcb, pcb2, sizeof(*pcb2)); - pcb2->pcb_flags &=3D ~(PCB_NPXINITDONE | PCB_NPXUSERINITDONE); + pcb2->pcb_flags &=3D ~(PCB_NPXINITDONE | PCB_NPXUSERINITDONE | + PCB_KERNNPX); pcb2->pcb_save =3D &pcb2->pcb_user_save; =20 /* --dngyMJhgXGAL5Gb8 Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (FreeBSD) iQIcBAEBAgAGBQJTNBR3AAoJEJDCuSvBvK1BpwUP/3W4HV8fedrekWaaMPH8wHQ/ D++VO5csIj6tPlYV5VcmTO89zapDgUq9I5YHM4qIHbA/fgidqafu9JN/ugkl6EBh 7uaRKPzUL9mk/jTKRlGmzuKcKQwHt/hqJZyFbOxF8I9NlwEv3PRgXnnXNi+/0XRu k6cIj5c5gjQdinHhM74HFrC7MJkJciwz6s3dG+GEq9qebvFD9OJHPBdNLsvgws/q F6KyWUhinuGbvMMS87w4NPKXB9/5AGqvpHo5lSJWKXSUSurXQxpF4A8tuGk7srk8 xqo/2eWZiwVFRcHm9Ol2C7q/5HPHz2TPuTAHbrN2hHD0byWPAsbgNKaYlWTIq2ks y4Rgfb50LYhGajPFLZ3/mM46rxw7ujWPPuCDr4mAn5ztpUC5Phzn3Lbqf49Jpokz n/cFJBc6tOWMsqsm7y3aakdphIAWpT30KCFSHvhLGgYuetosbAR9tsnzJN+nmHSI +udvWWQ82GPbbxL9BU7ULWpMR4SrAG9Na+KccOLMukT80wpL1aUj6JtfhkcnftK4 DftDhNx1ysm7FGRQDPqvsn0AqlqOwoH5awoMXaWajArjYd+ecVVOgzxLQ2hzJcPJ 0LwvwI/sToZjXALm7eZWDCDjvxy/4g9YOwbG+NJaIqEXswndxNVFdyTnpgA5mjmt 1ESeauS1zDHZj//FDN5K =gUZi -----END PGP SIGNATURE----- --dngyMJhgXGAL5Gb8--