On Mon, Aug 17, 2026 at 6:03 AM Håkon Bugge <[email protected]> wrote:
> diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile
> index cee1901d4cff8..240084b4abbb7 100644
> --- a/kernel/locking/Makefile
> +++ b/kernel/locking/Makefile
> @@ -38,3 +38,4 @@ obj-$(CONFIG_QUEUED_RWLOCKS) += qrwlock.o
> obj-$(CONFIG_LOCK_TORTURE_TEST) += locktorture.o
> obj-$(CONFIG_WW_MUTEX_SELFTEST) += test-ww_mutex.o
> obj-$(CONFIG_LOCK_EVENT_COUNTS) += lock_events.o
> +obj-$(CONFIG_MX_TEST) += mx_test.o
Total bikeshed item, but both CONFIG_MX_TEST and mx_test are not very
obvious names for someone looking at this make file.
> diff --git a/kernel/locking/mx_test.c b/kernel/locking/mx_test.c
> new file mode 100644
> index 0000000000000..71d9ddc48a44b
> --- /dev/null
> +++ b/kernel/locking/mx_test.c
...
> +static int __init mx_test_init(void)
> +{
> + unsigned int threads = 4 * num_online_cpus();
> + enum mx_test test = MX_ILLEGAL;
> + char *mnemonic;
> + unsigned int i;
> + unsigned int p;
> + struct {
> + enum mx_test test;
> + char *mnemonic;
> + } mx_test_types[] = {
> + {
> + .test = MX_BUSTED,
> + .mnemonic = "busted",
> + },
> + {
> + .test = MX_SPIN_LOCK,
> + .mnemonic = "spin_lock",
> + },
> + {
> + .test = MX_SPIN_LOCK_IRQ,
> + .mnemonic = "spin_lock_irq",
> + },
> + {
> + .test = MX_SPIN_LOCK_IRQSAVE,
> + .mnemonic = "spin_lock_irqsave",
> + },
> + {
> + .test = MX_RW_LOCK_W,
> + .mnemonic = "write_lock",
> + },
> + {
> + .test = MX_RW_LOCK_W_BH,
> + .mnemonic = "write_lock_bh",
> + },
> + {
> + .test = MX_RW_LOCK_TRW,
> + .mnemonic = "read_trylock_write_lock",
> + },
> + {
> + .test = MX_RW_LOCK_TRW_BH,
> + .mnemonic = "read_trylock_write_lock_bh",
> + },
> + {
> + .test = MX_MUTEX,
> + .mnemonic = "mutex",
> + },
> + {
> + .test = MX_ATOMIC_ADD,
> + .mnemonic = "atomic_add",
> + },
> + {
> + .test = MX_CMPXCHG,
> + .mnemonic = "cmpxchg",
> + },
> + {
> + .test = MX_RDS_BUSTED,
> + .mnemonic = "rds_busted",
> + },
> + {
> + .test = MX_TEST_AND_SET_BIT_LOCK,
> + .mnemonic = "test_and_set_bit_lock",
> + },
> + {
> + .test = MX_TEST_AND_SET_BIT_INNOV,
> + .mnemonic = "test_and_set_bit_innov",
> + },
> + {
> + .test = MX_TEST_AND_SET_BIT_PLAIN,
> + .mnemonic = "test_and_set_bit_plain",
> + },
> + {
> + .test = MX_TEST_AND_CLEAR_BIT_INNOV,
> + .mnemonic = "test_and_clear_bit_innov",
> + },
> + {
> + .test = MX_TEST_AND_CLEAR_BIT_PLAIN,
> + .mnemonic = "test_and_clear_bit_plain",
> + },
> + {
> + .test = MX_SINGLE_WW_MUTEX_WW,
> + .mnemonic = "single_ww_mutex_wound_wait",
> + },
> + {
> + .test = MX_SINGLE_WW_MUTEX_WD,
> + .mnemonic = "single_ww_mutex_wait_die",
> + },
> + };
> +
> + /* Select the test type */
> + for (i = 0; i < ARRAY_SIZE(mx_test_types); ++i)
> + if (!strcmp(mx_test, mx_test_types[i].mnemonic)) {
> + test = mx_test_types[i].test;
> + mnemonic = mx_test_types[i].mnemonic;
> + break;
> + }
> +
> + if (test == MX_ILLEGAL) {
> + pr_err("mx_test: unknown test type %s\n", mx_test);
> + pr_notice("mx_test: legitimate test types:\n");
> + for (i = 0; i < ARRAY_SIZE(mx_test_types); ++i)
> + pr_notice("mx_test_types: %s\n",
> mx_test_types[i].mnemonic);
> + return -ENOPROTOOPT;
> + }
> +
> + if ((mx_min_padding % 8) || (mx_max_padding % 8)) {
> + pr_err("mx_test: padding must be a multiple of 8 bytes\n");
> + return -EINVAL;
> + }
> +
> + if (mx_min_padding > mx_max_padding) {
> + pr_err("mx_test: mx_min_padding must be less than equal to
> mx_max_padding\n");
> + return -EINVAL;
> + }
> +
> + if (mx_max_padding > L1_CACHE_BYTES) {
> + pr_err("mx_test: mx_max_padding must be less than equal to
> L1_CACHE_BYTES (%d)\n",
> + L1_CACHE_BYTES);
> + return -EINVAL;
> + }
> +
> + if (mx_nmbr_elems < 1) {
> + pr_err("Number of elements must be greater than equal to
> one\n");
> + return -EINVAL;
> + }
> +
> + if (mx_scnds_per_test > MAX_JIFFY_OFFSET / HZ) {
> + pr_err("mx_scnds_per_test too large\n");
> + return -EINVAL;
> + }
> +
> + for (p = mx_min_padding; p <= mx_max_padding; p += 8) {
> + int sts = run_test(test, mnemonic, threads, p);
> +
> + if (sts)
> + return sts;
> + }
> +
> + return 0;
> +}
Apologies, I've not had a chance to apply and try this yet.
So this looks like the test has to be run via module load? I almost
never use modules in my test environment, so its often nice to allow
it to be built in and be triggered/re-triggered without having to
unload/reload (assuming this is not something like locktorture which
never finishes - and if that is the case, it might be good to
integrate into the locktorture framework instead of adding a new one).
Maybe something to consider?
thanks
-john