Re: [PATCH 08/28] hazptrtorture: Add slowpath and lockdep scenarios
From: Paul E. McKenney
Date: Tue Nov 10 2026 - 16:43:31 EST
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.
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
>