[PATCH v1 RESEND 3/4] rust: add ordered workqueue wrapper
From: Onur Özkan
Date: Fri Mar 13 2026 - 05:25:53 EST
Add an owned OrderedQueue wrapper for alloc_ordered_workqueue() and
destroy_workqueue().
This gives Rust drivers a simple way to create and own an ordered
workqueue with automatic cleanup in Drop.
Tested-by: Deborah Brouwer <deborah.brouwer@xxxxxxxxxxxxx>
Signed-off-by: Onur Özkan <work@xxxxxxxxxxxxx>
---
rust/helpers/workqueue.c | 6 +++++
rust/kernel/workqueue.rs | 47 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/rust/helpers/workqueue.c b/rust/helpers/workqueue.c
index ce1c3a5b2150..7cd3b000a5b6 100644
--- a/rust/helpers/workqueue.c
+++ b/rust/helpers/workqueue.c
@@ -14,3 +14,9 @@ __rust_helper void rust_helper_init_work_with_key(struct work_struct *work,
INIT_LIST_HEAD(&work->entry);
work->func = func;
}
+
+__rust_helper struct workqueue_struct *
+rust_helper_alloc_ordered_workqueue(const char *name, unsigned int flags)
+{
+ return alloc_ordered_workqueue("%s", flags, name);
+}
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index 6acc7b5ba31c..d5aa61a5ef93 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -195,6 +195,7 @@
types::Opaque,
};
use core::marker::PhantomData;
+use core::ptr::NonNull;
/// Creates a [`Work`] initialiser with the given name and a newly-created lock class.
#[macro_export]
@@ -346,6 +347,52 @@ pub fn try_spawn<T: 'static + Send + FnOnce()>(
}
}
+/// A kernel work queue that allocates and owns an ordered `workqueue_struct`.
+///
+/// Unlike [`Queue`], [`OrderedQueue`] takes ownership of the underlying C
+/// workqueue and automatically destroys it when dropped.
+pub struct OrderedQueue(NonNull<bindings::workqueue_struct>);
+
+// SAFETY: Workqueue objects are thread-safe to share and use concurrently.
+unsafe impl Send for OrderedQueue {}
+// SAFETY: Workqueue objects are thread-safe to share and use concurrently.
+unsafe impl Sync for OrderedQueue {}
+
+impl OrderedQueue {
+ /// Allocates an ordered workqueue.
+ ///
+ /// It is equivalent to C's `alloc_ordered_workqueue()`.
+ pub fn new(name: &'static CStr, flags: u32) -> Result<Self> {
+ // SAFETY: `name` is a `&'static CStr`, guaranteeing a valid, null-terminated C
+ // string pointer for the duration of this call.
+ let ptr = unsafe { bindings::alloc_ordered_workqueue(name.as_char_ptr(), flags) };
+ let ptr = NonNull::new(ptr).ok_or(ENOMEM)?;
+ Ok(Self(ptr))
+ }
+
+ /// Enqueues a work item.
+ ///
+ /// This may fail if the work item is already enqueued in a workqueue.
+ ///
+ /// The work item will be submitted using `WORK_CPU_UNBOUND`.
+ pub fn enqueue<W, const ID: u64>(&self, w: W) -> W::EnqueueOutput
+ where
+ W: RawWorkItem<ID> + Send + 'static,
+ {
+ // SAFETY: `self.0` is valid while `self` is alive.
+ unsafe { Queue::from_raw(self.0.as_ptr()) }.enqueue(w)
+ }
+}
+
+impl Drop for OrderedQueue {
+ fn drop(&mut self) {
+ // SAFETY:
+ // - Pointer comes from `alloc_ordered_workqueue()` and is owned by `self`.
+ // - `OrderedQueue` does not expose delayed scheduling API.
+ unsafe { bindings::destroy_workqueue(self.0.as_ptr()) };
+ }
+}
+
/// A helper type used in [`try_spawn`].
///
/// [`try_spawn`]: Queue::try_spawn
--
2.51.2