Re: [PATCH 08/28] hazptrtorture: Add slowpath and lockdep scenarios
From: KunWu Chan
Date: Thu Nov 12 2026 - 11:17:22 EST
On Wed, Nov 11, 2026 at 5:41 AM Paul E. McKenney <paulmck@xxxxxxxxxx> wrote:
>
> On Thu, Nov 05, 2026 at 12:54:26AM +0800, Kunwu Chan wrote:
> > Add SLOWPATH and LOCKDEP configs: SLOWPATH enables
> > CONFIG_HAZPTR_ACQUIRE_FORCE_SLOWPATH for slow-path stress; LOCKDEP
> > combines PROVE_LOCKING with wq_churn=1 so each alloc_workqueue/
> > destroy_workqueue pair exercises the lockdep hazptr paths.
> >
> > Suggested-by: Boqun Feng <boqun@xxxxxxxxxx>
>
> Could the --kconfigs and --bootargs kvm.sh parameters be used here
> as well? My concern is the proliferation of almost-identical scenario
> files.
Hi Paul,
Agreed. I added the configs to keep the forced-slowpath and
lockdep-churn cases explicit and repeatable. I'll drop the
separate scenario files and retain both as scripted PREEMPT runs
using --kconfig and --bootargs.
The wq_churn workload itself will remain in this patch.
Thanks,
Kunwu
>
> Thanx, Paul
>
> > Signed-off-by: Kunwu Chan <kunwu.chan@xxxxxxxxx>
> > ---
> > kernel/rcu/hazptrtorture.c | 48 ++++++++++++++++++-
> > .../rcutorture/configs/hazptr/LOCKDEP | 16 +++++++
> > .../rcutorture/configs/hazptr/LOCKDEP.boot | 1 +
> > .../rcutorture/configs/hazptr/SLOWPATH | 16 +++++++
> > 4 files changed, 79 insertions(+), 2 deletions(-)
> > create mode 100644 tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP
> > create mode 100644 tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP.boot
> > create mode 100644 tools/testing/selftests/rcutorture/configs/hazptr/SLOWPATH
> >
> > diff --git a/kernel/rcu/hazptrtorture.c b/kernel/rcu/hazptrtorture.c
> > index c8b7c208775b..fe09280d063c 100644
> > --- a/kernel/rcu/hazptrtorture.c
> > +++ b/kernel/rcu/hazptrtorture.c
> > @@ -23,6 +23,7 @@
> > #include <linux/torture.h>
> > #include <linux/hazptr.h>
> > #include <linux/rcupdate.h>
> > +#include <linux/workqueue.h>
> >
> > #include "rcu.h"
> >
> > @@ -51,6 +52,8 @@ torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
> > torture_param(int, stat_interval, 60, "Number of seconds between stats printk()s");
> > torture_param(int, stutter, 5, "Number of seconds to run/halt test");
> > torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
> > +torture_param(bool, wq_churn, false,
> > + "Churn workqueues to exercise lockdep dynamic keys");
> >
> > static char *torture_type = "hazptr";
> > module_param(torture_type, charp, 0444);
> > @@ -62,6 +65,7 @@ static struct task_struct *preempt_task;
> > static struct task_struct **reader_tasks;
> > static struct task_struct *do_pending_task;
> > static struct task_struct *stats_task;
> > +static struct task_struct *wq_churn_task;
> >
> > #define HAZPTR_TORTURE_PIPE_LEN 10
> >
> > @@ -83,6 +87,7 @@ static atomic_t n_hazptr_torture_alloc;
> > static atomic_t n_hazptr_torture_alloc_fail;
> > static atomic_t n_hazptr_torture_free;
> > static atomic_t n_hazptr_torture_error;
> > +static atomic_t n_hazptr_torture_wq_churn;
> > static DEFINE_PER_CPU(atomic_long_t, hazptr_torture_acquires);
> > static DEFINE_PER_CPU(atomic_long_t, hazptr_torture_releases);
> > static DEFINE_PER_CPU(atomic_long_t, hazptr_torture_acquires_irq);
> > @@ -668,13 +673,14 @@ hazptr_torture_stats_print(void)
> > atomic_read(&n_hazptr_torture_alloc_fail),
> > atomic_read(&n_hazptr_torture_free));
> > torture_onoff_stats();
> > - pr_cont("acq: %lld rel: %lld acqirq: %lld relirq: %lld reldefer: %lld relundefer %lld\n",
> > + pr_cont("acq: %lld rel: %lld acqirq: %lld relirq: %lld reldefer: %lld relundefer %lld wqchurn: %d\n",
> > torture_sum_pcpu_atomic_long(&hazptr_torture_acquires),
> > torture_sum_pcpu_atomic_long(&hazptr_torture_releases),
> > torture_sum_pcpu_atomic_long(&hazptr_torture_acquires_irq),
> > torture_sum_pcpu_atomic_long(&hazptr_torture_releases_irq),
> > torture_sum_pcpu_atomic_long(&hazptr_torture_releases_defer),
> > - torture_sum_pcpu_atomic_long(&hazptr_torture_releases_undefer));
> > + torture_sum_pcpu_atomic_long(&hazptr_torture_releases_undefer),
> > + atomic_read(&n_hazptr_torture_wq_churn));
> >
> > pr_alert("%s%s ", torture_type, TORTURE_FLAG);
> > if (i > 1) {
> > @@ -788,6 +794,38 @@ static int hazptr_torture_preempt(void *unused)
> > return 0;
> > }
> >
> > +static void hazptr_torture_wq_churn_fn(struct work_struct *work)
> > +{
> > +}
> > +
> > +/*
> > + * Repeatedly create and destroy workqueues. Each workqueue creation
> > + * registers a lockdep dynamic key and each destruction unregisters it,
> > + * which exercises both is_dynamic_key() and lockdep_unregister_key().
> > + */
> > +static int hazptr_torture_wq_churn(void *unused)
> > +{
> > + VERBOSE_TOROUT_STRING("hazptr_torture_wq_churn task started");
> > + do {
> > + struct workqueue_struct *wq;
> > + struct work_struct churn_work;
> > +
> > + wq = alloc_workqueue("hazptr-torture-churn", WQ_PERCPU, 1);
> > + if (!wq) {
> > + torture_hrtimeout_ms(10, 10, NULL);
> > + continue;
> > + }
> > + INIT_WORK(&churn_work, hazptr_torture_wq_churn_fn);
> > + queue_work(wq, &churn_work);
> > + flush_work(&churn_work);
> > + destroy_workqueue(wq);
> > + atomic_inc(&n_hazptr_torture_wq_churn);
> > + stutter_wait("hazptr_torture_wq_churn");
> > + } while (!torture_must_stop());
> > + torture_kthread_stopping("hazptr_torture_wq_churn");
> > + return 0;
> > +}
> > +
> > static void
> > hazptr_torture_cleanup(void)
> > {
> > @@ -880,6 +918,7 @@ static int __init hazptr_torture_init(void)
> > atomic_set(&n_hazptr_torture_alloc_fail, 0);
> > atomic_set(&n_hazptr_torture_free, 0);
> > atomic_set(&n_hazptr_torture_error, 0);
> > + atomic_set(&n_hazptr_torture_wq_churn, 0);
> > for (i = 0; i < HAZPTR_TORTURE_PIPE_LEN + 1; i++)
> > atomic_set(&hazptr_torture_wcount[i], 0);
> > for_each_possible_cpu(cpu) {
> > @@ -960,6 +999,11 @@ static int __init hazptr_torture_init(void)
> > if (torture_init_error(firsterr))
> > goto unwind;
> > }
> > + if (wq_churn) {
> > + firsterr = torture_create_kthread(hazptr_torture_wq_churn, NULL, wq_churn_task);
> > + if (torture_init_error(firsterr))
> > + goto unwind;
> > + }
> >
> > torture_init_end();
> > return 0;
> > diff --git a/tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP b/tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP
> > new file mode 100644
> > index 000000000000..f0ff29925a54
> > --- /dev/null
> > +++ b/tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP
> > @@ -0,0 +1,16 @@
> > +CONFIG_SMP=y
> > +CONFIG_NR_CPUS=16
> > +CONFIG_PREEMPT_NONE=n
> > +CONFIG_PREEMPT_VOLUNTARY=n
> > +CONFIG_PREEMPT=y
> > +CONFIG_HZ_PERIODIC=n
> > +CONFIG_NO_HZ_IDLE=y
> > +CONFIG_NO_HZ_FULL=n
> > +CONFIG_HOTPLUG_CPU=y
> > +CONFIG_SUSPEND=n
> > +CONFIG_HIBERNATION=n
> > +CONFIG_DEBUG_LOCK_ALLOC=y
> > +CONFIG_PROVE_LOCKING=y
> > +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
> > +CONFIG_DEBUG_KERNEL=y
> > +CONFIG_HAZPTR_DEBUG=y
> > diff --git a/tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP.boot b/tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP.boot
> > new file mode 100644
> > index 000000000000..7b16720214bd
> > --- /dev/null
> > +++ b/tools/testing/selftests/rcutorture/configs/hazptr/LOCKDEP.boot
> > @@ -0,0 +1 @@
> > +hazptrtorture.wq_churn=1
> > diff --git a/tools/testing/selftests/rcutorture/configs/hazptr/SLOWPATH b/tools/testing/selftests/rcutorture/configs/hazptr/SLOWPATH
> > new file mode 100644
> > index 000000000000..4d13028ca84c
> > --- /dev/null
> > +++ b/tools/testing/selftests/rcutorture/configs/hazptr/SLOWPATH
> > @@ -0,0 +1,16 @@
> > +CONFIG_SMP=y
> > +CONFIG_NR_CPUS=16
> > +CONFIG_PREEMPT_NONE=n
> > +CONFIG_PREEMPT_VOLUNTARY=n
> > +CONFIG_PREEMPT=y
> > +CONFIG_HZ_PERIODIC=n
> > +CONFIG_NO_HZ_IDLE=y
> > +CONFIG_NO_HZ_FULL=n
> > +CONFIG_HOTPLUG_CPU=y
> > +CONFIG_SUSPEND=n
> > +CONFIG_HIBERNATION=n
> > +CONFIG_PROVE_LOCKING=n
> > +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
> > +CONFIG_DEBUG_KERNEL=y
> > +CONFIG_HAZPTR_DEBUG=y
> > +CONFIG_HAZPTR_ACQUIRE_FORCE_SLOWPATH=y
> > --
> > 2.43.0
> >