Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern PR port-arm/52603:



details:   https://anonhg.NetBSD.org/src/rev/29ef663c03d3
branches:  trunk
changeset: 827141:29ef663c03d3
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Mon Oct 16 15:03:57 2017 +0000

description:
PR port-arm/52603:
There is a race here, as seen on arm with FPU:
LWP L is running but not on CPU, has its FPU state on CPU2 which
has not been released yet, so fpexc still has VFP_FPEXC_EN set in the PCB copy.

LWP L is scheduled on CPU1, CPU1 calls cpu_switchto() for L in mi_switch().
cpu_switchto() will set VFP_FPEXC_EN in the FPU's fpexc register per the
PCB fpexc copy.

Before CPU1 calls pcu_switchpoint() for L, CPU2 calls
pcu_do_op(PCU_CMD_SAVE | PCU_CMD_RELEASE) for L because it still holds its
FPU state and wants to load another lwp. This cause VFP_FPEXC_EN to
be cleared in the PCB copy, but not in CPU1's register. L's l_pcu_cpu is
set to NULL.

When CPU1 calls pcu_switchpoint() for L it see l_pcu_cpu is NULL, and doesn't
call the release callback.

Now CPU1 has its FPU enabled but with the wrong FPU state.

Fix by releasing the PCU even if l_pcu_cpu is NULL.

diffstat:

 sys/kern/subr_pcu.c |  7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

diffs (28 lines):

diff -r 772217f3ba3e -r 29ef663c03d3 sys/kern/subr_pcu.c
--- a/sys/kern/subr_pcu.c       Mon Oct 16 12:50:43 2017 +0000
+++ b/sys/kern/subr_pcu.c       Mon Oct 16 15:03:57 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_pcu.c,v 1.20 2017/03/16 16:13:21 chs Exp $        */
+/*     $NetBSD: subr_pcu.c,v 1.21 2017/10/16 15:03:57 bouyer Exp $     */
 
 /*-
  * Copyright (c) 2011, 2014 The NetBSD Foundation, Inc.
@@ -52,7 +52,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_pcu.c,v 1.20 2017/03/16 16:13:21 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_pcu.c,v 1.21 2017/10/16 15:03:57 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/cpu.h>
@@ -110,7 +110,8 @@
                        continue;
                }
                struct cpu_info * const pcu_ci = l->l_pcu_cpu[id];
-               if (pcu_ci == NULL || pcu_ci == l->l_cpu) {
+               if (pcu_ci == l->l_cpu) {
+                       KASSERT(pcu_ci->ci_pcu_curlwp[id] == l);
                        continue;
                }
                const pcu_ops_t * const pcu = pcu_ops_md_defs[id];



Home | Main Index | Thread Index | Old Index