Re: [PATCH v3 5/5] arm64: Enable perf events based hard lockup detector

Lecopzer Chen
2022-04-26T16:39:09Z

> > The call path for hardlockup_detector_perf_init() is really complicated,
> >
> > I have some approach about this:
> > 1. abstract second variable with Kconfig.
> > a. Add a ARCH_SUPPORTS_HARDLOCKUP_DETECTOR_DLAYED_INIT
> > (the naming is a little bit long, may have better naming)
> > in "lib/Kconfig.debug" if ARCH knew they do need delayed init for
> > lockup detector.
> >
> > + select ARCH_SUPPORTS_HARDLOCKUP_DETECTOR_DLAYED_INIT if HAVE_HARDLOCKUP_DETECTOR_PERF
> >
> > b. and the watchdog_nmi_probe would look like.
> >
> > +int __init watchdog_nmi_probe(void)
> > +{
> > + int ret;
> > +
> > + /* comment here... */
> > + if (!arm_pmu_irq_is_nmi())
> > + return -ENODEV;
> > +
> > + ret = hardlockup_detector_perf_init();
> > + if (ret &&
> > + IS_ENABLED(ARCH_SUPPORTS_HARDLOCKUP_DETECTOR_DLAYED_INIT))
> > + return -EBUSY;
> > +
> > + return ret;
> > +}
> >
> > and than we can have only one variable (allow_lockup_detector_init_retry)
> > in 4th patch.
> >
> >
> > 2. base on ARCH_SUPPORTS_HARDLOCKUP_DETECTOR_DLAYED_INIT, change
> > inside hardlockup_detector_perf_init().
> >
> > int __init hardlockup_detector_perf_init(void)
> > {
> > int ret = hardlockup_detector_event_create();
> >
> > if (ret) {
> > pr_info("Perf NMI watchdog permanently disabled\n");
> > +
> > + /* comment here... */
> > + if (IS_ENABLED(ARCH_SUPPORTS_HARDLOCKUP_DETECTOR_DLAYED_INIT))
> > + ret = -EBUSY;
> > } else {
> > perf_event_release_kernel(this_cpu_read(watchdog_ev));
> > this_cpu_write(watchdog_ev, NULL);
> > }
> > return ret;
> > }
> >
> > 3. Don't add any other config, try to find a proper location
> > to return -EBUSY in hardlockup_detector_event_create().
> > IMHO, this may involve the PMU subsys and should be
> > the hardest approach.
>
> Honestly, everything looks a bit ugly and complicated to me.
>
> OKAY, is the return value actually important?
>
> What about just introducing the API that will allow to try to
> initialize the hardlockup detector later:
>
> /*
> * Retry hardlockup detector init. It is useful when it requires some
> * functionality that has to be initialized later on a particular
> * platform.
> */
> void __init retry_lockup_detector_init(void)
> {
> /* Must be called before late init calls. */
> if (!allow_lockup_detector_init_retry)
> return 0;
>
> queue_work_on(__smp_processor_id(), system_wq, &detector_work);
> }
>
> /*
> * Ensure that optional delayed hardlockup init is proceed before
> * the init code and memory is freed.
> */
> static int __init lockup_detector_check(void)
> {
> /* Prevent any later retry. */
> allow_lockup_detector_init_retry = false;
>
> /* Make sure no work is pending. */
> flush_work(&detector_work);
> }
> late_initcall_sync(lockup_detector_check);
>
> You could leave lockup_detector_init() as it is. It does not really
> matter what was the exact error value returned by watchdog_nmi_probe().
>
> Then you could call retry_lockup_detector_init() in
> armv8_pmu_driver_init() and be done with it.
>
> It will be universal API that might be used on any architecture
> for any reason. If nobody calls retry_lockup_detector_init()
> then nohing will happen and the code will work as before.
>
> It might make sense to provide the API only on architectures that
> really need it. We could hide it under
>
> ARCH_NEED_DELAYED_HARDLOCKUP_DETECTOR_INIT
>
> , similar to ARCH_NEEDS_CPU_IDLE_COUPLE.
>

During implementation, if I add ARCH_NEED_DELAYED_..., there will contain
many enclosed ifdef-endif and is a little bit ugly.
Also, I didn't find a must-have reason to this Kconfig after I rebase from
your suggestion.

The one calls retry_lockup_detector_init() must fail at lockup_detector_init,
so I think anyone who has aleady failed at lockup_detector_init() has right
to retry no matter HW, SW or Arch reason.
Thus I might not introduce a new Kconfig in v4, and I would be glad to see
if any further commet on this.