Print this page
13902 Fix for 13717 may break 8-disk raidz2
13915 installctx() blocking allocate causes problems
Portions contributed by: Jerry Jelinek <gjelinek@gmail.com>
Change-Id: I934d69946cec42630fc541fa8c7385b862b69ca2

@@ -18,11 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2020 Joyent, Inc.
+ * Copyright 2021 Joyent, Inc.
  * Copyright 2021 RackTop Systems, Inc.
  */
 
 /*      Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T   */

@@ -668,11 +668,11 @@
          * Mark that both the parent and child need to have the FPU cleaned up
          * before returning to user land.
          */
 
         installctx(ct, cfp, fpsave_ctxt, fprestore_ctxt, fp_new_lwp,
-            fp_new_lwp, NULL, fp_free);
+            fp_new_lwp, NULL, fp_free, NULL);
 }
 
 /*
  * Free any state associated with floating point context.
  * Fp_free can be called in three cases:

@@ -794,10 +794,11 @@
  */
 void
 fp_exec(void)
 {
         struct fpu_ctx *fp = &ttolwp(curthread)->lwp_pcb.pcb_fpu;
+        struct ctxop *ctx = installctx_preallocate();
 
         if (fp_save_mech == FP_XSAVE) {
                 fp->fpu_xsave_mask = XFEATURE_FP_ALL;
         }
 

@@ -805,11 +806,11 @@
          * Make sure that we're not preempted in the middle of initializing the
          * FPU on CPU.
          */
         kpreempt_disable();
         installctx(curthread, fp, fpsave_ctxt, fprestore_ctxt, fp_new_lwp,
-            fp_new_lwp, NULL, fp_free);
+            fp_new_lwp, NULL, fp_free, ctx);
         fpinit();
         fp->fpu_flags = FPU_EN;
         kpreempt_enable();
 }
 

@@ -834,11 +835,11 @@
         if (fp_save_mech == FP_XSAVE) {
                 fp->fpu_xsave_mask = XFEATURE_FP_ALL;
         }
 
         installctx(curthread, fp, fpsave_ctxt, fprestore_ctxt, fp_new_lwp,
-            fp_new_lwp, NULL, fp_free);
+            fp_new_lwp, NULL, fp_free, NULL);
         fpinit();
 
         /*
          * If FPU_VALID is set, it means someone has modified registers via
          * /proc.  In this case, restore the current lwp's state.

@@ -1316,10 +1317,11 @@
 
 void
 kernel_fpu_begin(kfpu_state_t *kfpu, uint_t flags)
 {
         klwp_t *pl = curthread->t_lwp;
+        struct ctxop *ctx;
 
         if ((curthread->t_flag & T_KFPU) != 0) {
                 panic("curthread attempting to nest kernel FPU states");
         }
 

@@ -1378,27 +1380,29 @@
          *
          * We might have already saved once (due to a prior use of the kernel
          * FPU or another code path) so FPU_VALID could be set. This is handled
          * by fp_save, as is the FPU_EN check.
          */
-        if (pl != NULL) {
+        ctx = installctx_preallocate();
                 kpreempt_disable();
+        if (pl != NULL) {
                 if ((flags & KFPU_USE_LWP) == 0)
                         fp_save(&pl->lwp_pcb.pcb_fpu);
                 pl->lwp_pcb.pcb_fpu.fpu_flags |= FPU_KERNEL;
-                kpreempt_enable();
         }
 
         /*
-         * Set the context operations for kernel FPU usage. Note that this
-         * cannot be done with pre-emption and interrupts disabled, since
-         * installctx does a sleeping allocation. We haven't finished
-         * initializing our kernel FPU state yet, but in the rare case that we
-         * happen to save/restore before that, no harm is done.
+         * Set the context operations for kernel FPU usage. Note that this is
+         * done with a preallocated buffer and under kpreempt_disable because
+         * without a preallocated buffer, installctx does a sleeping
+         * allocation. We haven't finished initializing our kernel FPU state
+         * yet, and in the rare case that we happen to save/restore just as
+         * installctx() exits its own kpreempt_enable() internal call, we
+         * guard against restoring an uninitialized buffer (0xbaddcafe).
          */
         installctx(curthread, kfpu, kernel_fpu_ctx_save, kernel_fpu_ctx_restore,
-            NULL, NULL, NULL, NULL);
+            NULL, NULL, NULL, NULL, ctx);
 
         curthread->t_flag |= T_KFPU;
 
         if ((flags & KFPU_USE_LWP) == KFPU_USE_LWP) {
                 /*

@@ -1418,10 +1422,11 @@
                 pf->fpu_flags = FPU_EN | FPU_KERNEL;
         } else {
                 /* initialize the kfpu state */
                 kernel_fpu_ctx_restore(kfpu);
         }
+        kpreempt_enable();
 }
 
 void
 kernel_fpu_end(kfpu_state_t *kfpu, uint_t flags)
 {