Something in the amd64 resume path doesn't agree with _mcount(), so
suspend/resume always fails if gmoninit is non-zero. It would be nice
if GPROF kernels didn't crash during resume.
In sleep_state(), (1) clear gmoninit after sched_stop_secondary_cpus()
so the primary CPU isn't racing sysctl(2) on another CPU, and (2)
restore gmoninit just after resume_mp() so the secondary CPUs are out
of cpu_hatch() and away from whatever is causing the crash before
_mcount() is reenabled.
Lots of input from claudio@, deraadt@, and kettenis@.
Thread 1: https://marc.info/?l=openbsd-tech&m=
168721453821801&w=2
Thread 2: https://marc.info/?l=openbsd-tech&m=
168892518722935&w=2
ok kettenis@ deraadt@
-/* $OpenBSD: subr_suspend.c,v 1.15 2023/07/02 19:02:27 cheloha Exp $ */
+/* $OpenBSD: subr_suspend.c,v 1.16 2023/07/12 18:40:06 cheloha Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <dev/wscons/wsdisplayvar.h>
+#ifdef GPROF
+#include <sys/gmon.h>
+#endif
#ifdef HIBERNATE
#include <sys/hibernate.h>
#endif
extern int perflevel;
size_t rndbuflen;
char *rndbuf;
+#ifdef GPROF
+ int gmon_state;
+#endif
#if NSOFTRAID > 0
extern void sr_quiesce(void);
#endif
#ifdef MULTIPROCESSOR
sched_stop_secondary_cpus();
KASSERT(CPU_IS_PRIMARY(curcpu()));
+#endif
+#ifdef GPROF
+ gmon_state = gmoninit;
+ gmoninit = 0;
+#endif
+#ifdef MULTIPROCESSOR
sleep_mp();
#endif
resume_randomness(rndbuf, rndbuflen);
#ifdef MULTIPROCESSOR
resume_mp();
+#endif
+#ifdef GPROF
+ gmoninit = gmon_state;
+#endif
+#ifdef MULTIPROCESSOR
sched_start_secondary_cpus();
#endif
vfs_stall(curproc, 0);