On Sun, Jul 09, 2023 at 12:52:20PM -0500, Scott Cheloha wrote:
> This patch fixes resume/unhibernate on GPROF kernels where kgmon(8)
> has activated kernel profiling.
>
> I think the problem is that code called from cpu_hatch() does not play
> nicely with _mcount(), so GPROF kernels crash during resume. I can't
> point you to which code in particular, but keeping all CPUs out of
> _mcount() until the primary CPU has completed resume/unhibernate fixes
> the crash.
>
> ok?
To be honest, I'm not sure we need something like this. GPROF is already a
special case and poeple running a GPROF kernel should probably stop the
collection of profile data before suspend/hibernate.
Unless someone wants to gprof suspend/hibernate but then doing this will
result in bad data.
Another option is to abort zzz/ZZZ if kernel profiling is running.
In your diff I would remove these asserts:
KASSERT(CPU_IS_PRIMARY(curcpu()));
The code does not require the primary cpu there and KASSERT are not for free.
> Index: sys/lib/libkern/mcount.c
> ===================================================================
> RCS file: /cvs/src/sys/lib/libkern/mcount.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 mcount.c
> --- sys/lib/libkern/mcount.c 11 Jan 2022 09:21:34 -0000 1.14
> +++ sys/lib/libkern/mcount.c 9 Jul 2023 17:49:55 -0000
> @@ -33,6 +33,32 @@
> #include <sys/param.h>
> #include <sys/gmon.h>
>
> +#ifdef _KERNEL
> +#ifdef SUSPEND
> +#include <sys/atomic.h>
> +
> +#include <lib/libkern/libkern.h> /* KASSERT */
> +
> +volatile int mcount_disabled;
> +
> +void
> +mcount_disable(void)
> +{
> + KASSERT(CPU_IS_PRIMARY(curcpu()));
> + mcount_disabled = 1;
> + membar_producer();
> +}
> +
> +void
> +mcount_enable(void)
> +{
> + KASSERT(CPU_IS_PRIMARY(curcpu()));
> + mcount_disabled = 0;
> + membar_producer();
> +}
> +#endif /* SUSPEND */
> +#endif /* _KERNEL */
> +
> /*
> * mcount is called on entry to each function compiled with the profiling
> * switch set. _mcount(), which is declared in a machine-dependent way
> @@ -63,7 +89,10 @@ _MCOUNT_DECL(u_long frompc, u_long selfp
> */
> if (gmoninit == 0)
> return;
> -
> +#ifdef SUSPEND
> + if (mcount_disabled)
> + return;
> +#endif
> if ((p = curcpu()->ci_gmon) == NULL)
> return;
> #else
> Index: sys/kern/subr_suspend.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/subr_suspend.c,v
> retrieving revision 1.15
> diff -u -p -r1.15 subr_suspend.c
> --- sys/kern/subr_suspend.c 2 Jul 2023 19:02:27 -0000 1.15
> +++ sys/kern/subr_suspend.c 9 Jul 2023 17:49:55 -0000
> @@ -26,6 +26,9 @@
> #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
> @@ -63,6 +66,9 @@ top:
>
> if (sleep_showstate(v, sleepmode))
> return EOPNOTSUPP;
> +#ifdef GPROF
> + mcount_disable();
> +#endif
> #if NWSDISPLAY > 0
> wsdisplay_suspend();
> #endif
> @@ -192,6 +198,9 @@ fail_hiballoc:
> start_periodic_resettodr();
> #if NWSDISPLAY > 0
> wsdisplay_resume();
> +#endif
> +#ifdef GPROF
> + mcount_enable();
> #endif
> sys_sync(curproc, NULL, NULL);
> if (cpu_setperf != NULL)
> Index: sys/sys/gmon.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/gmon.h,v
> retrieving revision 1.9
> diff -u -p -r1.9 gmon.h
> --- sys/sys/gmon.h 11 Jan 2022 23:59:55 -0000 1.9
> +++ sys/sys/gmon.h 9 Jul 2023 17:49:55 -0000
> @@ -158,6 +158,10 @@ struct gmonparam {
> #ifdef _KERNEL
> extern int gmoninit; /* Is the kernel ready for being profiled? */
>
> +#ifdef SUSPEND
> +void mcount_disable(void);
> +void mcount_enable(void);
> +#endif
> #else /* !_KERNEL */
>
> #include <sys/cdefs.h>
> Index: lib/libc/gmon/mcount.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/gmon/mcount.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 mcount.c
> --- lib/libc/gmon/mcount.c 11 Jan 2022 09:21:34 -0000 1.16
> +++ lib/libc/gmon/mcount.c 9 Jul 2023 17:49:55 -0000
> @@ -31,6 +31,32 @@
> #include <sys/types.h>
> #include <sys/gmon.h>
>
> +#ifdef _KERNEL
> +#ifdef SUSPEND
> +#include <sys/atomic.h>
> +
> +#include <lib/libkern/libkern.h> /* KASSERT */
> +
> +volatile int mcount_disabled;
> +
> +void
> +mcount_disable(void)
> +{
> + KASSERT(CPU_IS_PRIMARY(curcpu()));
> + mcount_disabled = 1;
> + membar_producer();
> +}
> +
> +void
> +mcount_enable(void)
> +{
> + KASSERT(CPU_IS_PRIMARY(curcpu()));
> + mcount_disabled = 0;
> + membar_producer();
> +}
> +#endif /* SUSPEND */
> +#endif /* _KERNEL */
> +
> /*
> * mcount is called on entry to each function compiled with the profiling
> * switch set. _mcount(), which is declared in a machine-dependent way
> @@ -61,7 +87,10 @@ _MCOUNT_DECL(u_long frompc, u_long selfp
> */
> if (gmoninit == 0)
> return;
> -
> +#ifdef SUSPEND
> + if (mcount_disabled)
> + return;
> +#endif
> if ((p = curcpu()->ci_gmon) == NULL)
> return;
> #else
>
--
:wq Claudio