@@ -400,12 +400,34 @@ static inline void wc_linuxkm_fpu_state_release(
400400
401401WARN_UNUSED_RESULT int can_save_vector_registers_x86 (void )
402402{
403+ /* First, check if we're already saved, per wc_linuxkm_fpu_states.
404+ *
405+ * On kernel >= 6.15, irq_fpu_usable() dumps a backtrace to the kernel log
406+ * if called while already saved, so it's crucial to preempt that call by
407+ * checking wc_linuxkm_fpu_states.
408+ */
409+
410+ struct wc_thread_fpu_count_ent * pstate = wc_linuxkm_fpu_state_assoc (0 );
411+
412+ if ((pstate != NULL ) && (pstate -> fpu_state != 0U )) {
413+ if (unlikely ((pstate -> fpu_state & WC_FPU_COUNT_MASK )
414+ == WC_FPU_COUNT_MASK ))
415+ {
416+ /* would overflow */
417+ return 0 ;
418+ } else {
419+ return 1 ;
420+ }
421+ }
422+
403423 if (irq_fpu_usable ())
404424 return 1 ;
405425 else if (in_nmi () || (hardirq_count () > 0 ) || (softirq_count () > 0 ))
406426 return 0 ;
427+ #ifdef TIF_NEED_FPU_LOAD
407428 else if (test_thread_flag (TIF_NEED_FPU_LOAD ))
408429 return 1 ;
430+ #endif
409431 return 0 ;
410432}
411433
@@ -441,7 +463,7 @@ WARN_UNUSED_RESULT int save_vector_registers_x86(void)
441463 }
442464
443465 if (irq_fpu_usable ()
444- #if (LINUX_VERSION_CODE < KERNEL_VERSION (5 , 17 , 0 ))
466+ #if (LINUX_VERSION_CODE < KERNEL_VERSION (5 , 17 , 0 )) && defined ( TIF_NEED_FPU_LOAD )
445467 /* work around a kernel bug -- see linux commit 59f5ede3bc0f0.
446468 * what we really want here is this_cpu_read(in_kernel_fpu), but
447469 * in_kernel_fpu is an unexported static array.
@@ -489,6 +511,7 @@ WARN_UNUSED_RESULT int save_vector_registers_x86(void)
489511 wc_linuxkm_fpu_state_release (pstate );
490512#endif
491513 return BAD_STATE_E ;
514+ #ifdef TIF_NEED_FPU_LOAD
492515 } else if (!test_thread_flag (TIF_NEED_FPU_LOAD )) {
493516 static int warned_fpu_forbidden = 0 ;
494517 if (! warned_fpu_forbidden )
@@ -498,6 +521,7 @@ WARN_UNUSED_RESULT int save_vector_registers_x86(void)
498521 wc_linuxkm_fpu_state_release (pstate );
499522#endif
500523 return BAD_STATE_E ;
524+ #endif
501525 } else {
502526 /* assume already safely in_kernel_fpu from caller, but recursively
503527 * preempt_disable() to be extra-safe.
0 commit comments