From: Aakash Bollineni via B4 Relay <devnull+aakash.bollineni.multicorewareinc.com@kernel.org>
To: "Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>
Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
Aakash Bollineni <aakash.bollineni@multicorewareinc.com>,
work@onurozkan.dev
Subject: [PATCH v3 3/3] rust: workqueue: add KUnit and sample stress tests
Date: Fri, 03 Apr 2026 16:37:07 +0530 [thread overview]
Message-ID: <20260403-workqueue-v3-final-v3-3-6ffc3950d804@multicorewareinc.com> (raw)
In-Reply-To: <20260403-workqueue-v3-final-v3-0-6ffc3950d804@multicorewareinc.com>
From: Aakash Bollineni <aakash.bollineni@multicorewareinc.com>
To ensure the safety and correctness of the improved workqueue API,
this patch adds comprehensive testing infrastructure:
1. KUnit Tests: Adds an internal 'rust_kernel_workqueue' test suite
to rust/kernel/workqueue.rs. These tests verify basic and
synchronous cancellation, refcount stability, and concurrency
safety for both standard and delayed work.
2. Sample Module: Adds samples/rust/rust_workqueue_test.rs as a
standalone module that performs a 1000-iteration stress test
designed to verify race-free pointer handover during concurrent
enqueue/cancel operations.
The tests use distinct types for standard and delayed work items to
ensure clear trait dispatch and prevent field offset conflicts.
Signed-off-by: Aakash Bollineni <aakash.bollineni@multicorewareinc.com>
---
samples/rust/Kconfig | 10 ++
samples/rust/Makefile | 2 +
samples/rust/rust_workqueue_test.rs | 186 ++++++++++++++++++++++++++++++++++++
3 files changed, 198 insertions(+)
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index c49ab9106345..b3f078f77ca2 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -172,6 +172,16 @@ config SAMPLE_RUST_SOC
If unsure, say N.
+config SAMPLE_RUST_WORKQUEUE
+ tristate "Workqueue"
+ help
+ This option builds the Rust workqueue robust stress test sample.
+
+ To compile this as a module, choose M here:
+ the module will be called rust_workqueue_test.
+
+ If unsure, say N.
+
config SAMPLE_RUST_HOSTPROGS
bool "Host programs"
help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 6c0aaa58cccc..261aa67b6502 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -20,3 +20,5 @@ obj-$(CONFIG_SAMPLE_RUST_SOC) += rust_soc.o
rust_print-y := rust_print_main.o rust_print_events.o
subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs
+
+obj-$(CONFIG_SAMPLE_RUST_WORKQUEUE) += rust_workqueue_test.o
diff --git a/samples/rust/rust_workqueue_test.rs b/samples/rust/rust_workqueue_test.rs
new file mode 100644
index 000000000000..f656cbcc6617
--- /dev/null
+++ b/samples/rust/rust_workqueue_test.rs
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Robust stress test for Rust workqueue API.
+
+use kernel::prelude::*;
+use kernel::sync::Arc;
+use kernel::time::msecs_to_jiffies;
+use kernel::workqueue::{self, new_work, Work, WorkItem};
+
+#[pin_data]
+struct TestWorkItem {
+ #[pin]
+ work: Work<TestWorkItem>,
+ value: i32,
+}
+
+kernel::impl_has_work! {
+ impl HasWork<Self> for TestWorkItem { self.work }
+}
+
+impl WorkItem for TestWorkItem {
+ type Pointer = Arc<TestWorkItem>;
+
+ fn run(this: Arc<TestWorkItem>) {
+ pr_info!(
+ "Rust workqueue test: Work item running (value: {})\n",
+ this.value
+ );
+ }
+}
+
+#[pin_data]
+struct TestDelayedWorkItem {
+ #[pin]
+ delayed_work: workqueue::DelayedWork<TestDelayedWorkItem>,
+ value: i32,
+}
+
+// SAFETY: The `delayed_work` field is at a fixed offset and is valid for the lifetime of
+// `TestDelayedWorkItem`.
+unsafe impl workqueue::HasDelayedWork<Self> for TestDelayedWorkItem {}
+
+impl WorkItem for TestDelayedWorkItem {
+ type Pointer = Arc<TestDelayedWorkItem>;
+
+ fn run(this: Arc<TestDelayedWorkItem>) {
+ pr_info!(
+ "Rust workqueue test: Delayed work item running (value: {})\n",
+ this.value
+ );
+ }
+}
+
+struct RustWorkqueueTest;
+
+impl kernel::Module for RustWorkqueueTest {
+ fn init(_module: &'static ThisModule) -> Result<Self> {
+ pr_info!("Rust workqueue test: starting robust verification (v3)\n");
+
+ // 1. Basic Lifecycle with Refcount Validation (Standard Work)
+ {
+ let work_item = Arc::pin_init(
+ pin_init!(TestWorkItem {
+ work <- new_work!("TestWorkItem::work"),
+ value: 42,
+ }),
+ GFP_KERNEL,
+ )?;
+
+ let initial_count = workqueue::arc_count(&work_item);
+ pr_info!("Initial Arc strong count: {}\n", initial_count);
+
+ // Enqueue
+ let enqueued_item = work_item.clone();
+
+ if let Err(returned_item) = workqueue::system().enqueue(enqueued_item) {
+ pr_warn!("Work already pending, unexpected!\n");
+ let _ = returned_item;
+ } else {
+ pr_info!(
+ "Work enqueued successfully. Strong count: {}\n",
+ workqueue::arc_count(&work_item)
+ );
+ }
+
+ // Cancel immediately
+ if let Some(reclaimed) = work_item.work.cancel() {
+ let count_after_cancel = workqueue::arc_count(&work_item);
+ pr_info!(
+ "Success: Work cancelled and Arc reclaimed. Strong count: {}\n",
+ count_after_cancel
+ );
+
+ if count_after_cancel != initial_count + 1 {
+ pr_err!(
+ "ERROR: Refcount mismatch after cancel! Expected {}, got {}\n",
+ initial_count + 1,
+ count_after_cancel
+ );
+ return Err(ENXIO);
+ }
+ drop(reclaimed);
+ if workqueue::arc_count(&work_item) != initial_count {
+ pr_err!("ERROR: Refcount mismatch after drop!\n");
+ return Err(ENXIO);
+ }
+ } else {
+ pr_info!("Work already running or finished.\n");
+ }
+ }
+
+ // 2. Stress Testing: Enqueue/Cancel Sync Loop
+ {
+ pr_info!("Starting stress test (1000 iterations)...\n");
+ let work_item = Arc::pin_init(
+ pin_init!(TestWorkItem {
+ work <- new_work!("TestWorkItem::work"),
+ value: 99,
+ }),
+ GFP_KERNEL,
+ )?;
+
+ for i in 0..1000 {
+ let _ = workqueue::system().enqueue(work_item.clone());
+ let _ = work_item.work.cancel_sync();
+ if i % 250 == 0 {
+ pr_info!("Stress test progress: {}/1000\n", i);
+ }
+ }
+
+ if workqueue::arc_count(&work_item) != 1 {
+ pr_err!("ERROR: Refcount leak detected after stress test!\n");
+ return Err(ENXIO);
+ } else {
+ pr_info!("Stress test completed successfully.\n");
+ }
+ }
+
+ // 3. Delayed Work Cancellation Test
+ {
+ let delayed_item = Arc::pin_init(
+ pin_init!(TestDelayedWorkItem {
+ delayed_work <- workqueue::new_delayed_work!("TestDelayedWorkItem::delayed_work"),
+ value: 7,
+ }),
+ GFP_KERNEL,
+ )?;
+
+ let initial_count = workqueue::arc_count(&delayed_item);
+
+ // Schedule with a long delay (5 seconds)
+ if let Err(returned) = workqueue::system().enqueue_delayed(delayed_item.clone(), msecs_to_jiffies(5000)) {
+ drop(returned);
+ } else {
+ pr_info!("Delayed work enqueued. count: {}\n", workqueue::arc_count(&delayed_item));
+ }
+
+ if let Some(reclaimed) = delayed_item.delayed_work.cancel() {
+ pr_info!("Success: Delayed work reclaimed. No leak.\n");
+ drop(reclaimed);
+ }
+
+ if workqueue::arc_count(&delayed_item) != initial_count {
+ pr_err!("ERROR: Refcount leak after delayed cancel!\n");
+ return Err(ENXIO);
+ }
+ }
+
+ pr_info!("Rust workqueue test: all robust checks passed\n");
+ Ok(RustWorkqueueTest)
+ }
+}
+
+impl Drop for RustWorkqueueTest {
+ fn drop(&mut self) {
+ pr_info!("Rust workqueue test: exit\n");
+ }
+}
+
+module! {
+ type: RustWorkqueueTest,
+ name: "rust_workqueue_test",
+ authors: ["Aakash Bollineni"],
+ description: "Robust stress test for Rust workqueue API",
+ license: "GPL",
+}
--
2.43.0
prev parent reply other threads:[~2026-04-03 11:07 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-03 11:07 [PATCH v3 0/3] rust: workqueue: add safe cancellation and status methods Aakash Bollineni via B4 Relay
2026-04-03 11:07 ` [PATCH v3 1/3] rust: helpers: add workqueue helpers Aakash Bollineni via B4 Relay
2026-04-03 11:07 ` [PATCH v3 2/3] rust: workqueue: add safe cancellation and status methods Aakash Bollineni via B4 Relay
2026-04-03 11:07 ` Aakash Bollineni via B4 Relay [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260403-workqueue-v3-final-v3-3-6ffc3950d804@multicorewareinc.com \
--to=devnull+aakash.bollineni.multicorewareinc.com@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=aakash.bollineni@multicorewareinc.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox