lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260203215555.832171-1-hamzamahfooz@linux.microsoft.com>
Date: Tue,  3 Feb 2026 13:55:55 -0800
From: Hamza Mahfooz <hamzamahfooz@...ux.microsoft.com>
To: rust-for-linux@...r.kernel.org
Cc: Miguel Ojeda <ojeda@...nel.org>,
	Boqun Feng <boqun.feng@...il.com>,
	Gary Guo <gary@...yguo.net>,
	Björn Roy Baron <bjorn3_gh@...tonmail.com>,
	Benno Lossin <lossin@...nel.org>,
	Andreas Hindborg <a.hindborg@...nel.org>,
	Alice Ryhl <aliceryhl@...gle.com>,
	Trevor Gross <tmgross@...ch.edu>,
	Danilo Krummrich <dakr@...nel.org>,
	Tejun Heo <tj@...nel.org>,
	Tamir Duberstein <tamird@...il.com>,
	Alban Kurti <kurti@...icto.ai>,
	linux-kernel@...r.kernel.org,
	Hamza Mahfooz <hamzamahfooz@...ux.microsoft.com>
Subject: [PATCH] workqueue: rust: add work item runtime modification support

This feature is required for our Hyper-V VMBus reimplementation effort.
As it provides the ability to modify the running state of work items at
runtime.

The design revolves around having
Queue::enqueue()/Queue::enqueue_delayed() return implementations of
WorkHandle which can then be used to enable/disable/cancel
the relevant work item.

Please see the example introduced at the top of the file for example
usage of work handles.

Signed-off-by: Hamza Mahfooz <hamzamahfooz@...ux.microsoft.com>
---
 rust/kernel/workqueue.rs | 239 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 233 insertions(+), 6 deletions(-)

diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index 706e833e9702..cbbd487ce8cb 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -135,7 +135,7 @@
 //!
 //! ```
 //! use kernel::sync::Arc;
-//! use kernel::workqueue::{self, impl_has_delayed_work, new_delayed_work, DelayedWork, WorkItem};
+//! use kernel::workqueue::{self, impl_has_delayed_work, new_delayed_work, DelayedWork, WorkItem, WorkHandle};
 //!
 //! #[pin_data]
 //! struct MyStruct {
@@ -179,8 +179,22 @@
 //! fn print_now(val: Arc<MyStruct>) {
 //!     let _ = workqueue::system().enqueue(val);
 //! }
+//!
+//! /// The returned WorkHandle can be used to cancel the work item before it gets executed.
+//! fn print_never(val: Arc<MyStruct>) {
+//!     let result = workqueue::system_bh().enqueue_delayed(val, 1000);
+//!
+//!     match result {
+//!         Ok(handle) => {
+//!             handle.cancel(true);
+//!         },
+//!         Err(_) => (),
+//!     }
+//! }
+//!
 //! # print_later(MyStruct::new(42).unwrap());
 //! # print_now(MyStruct::new(42).unwrap());
+//! # print_never(MyStruct::new(42).unwrap());
 //! ```
 //!
 //! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h)
@@ -297,7 +311,7 @@ pub fn enqueue<W, const ID: u64>(&self, w: W) -> W::EnqueueOutput
     /// 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_delayed<W, const ID: u64>(&self, w: W, delay: Jiffies) -> W::EnqueueOutput
+    pub fn enqueue_delayed<W, const ID: u64>(&self, w: W, delay: Jiffies) -> W::EnqueueDelayedOutput
     where
         W: RawDelayedWorkItem<ID> + Send + 'static,
     {
@@ -317,7 +331,7 @@ pub fn enqueue_delayed<W, const ID: u64>(&self, w: W, delay: Jiffies) -> W::Enqu
         // promises that the raw pointer will stay valid until we call the function pointer in the
         // `work_struct`, so the access is ok.
         unsafe {
-            w.__enqueue(move |work_ptr| {
+            w.__enqueue_delayed(move |work_ptr| {
                 bindings::queue_delayed_work_on(
                     bindings::wq_misc_consts_WORK_CPU_UNBOUND as ffi::c_int,
                     queue_ptr,
@@ -421,7 +435,15 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
 /// provided pointer must point at the `work` field of a valid `delayed_work`, and the guarantees
 /// that `__enqueue` provides about accessing the `work_struct` must also apply to the rest of the
 /// `delayed_work` struct.
-pub unsafe trait RawDelayedWorkItem<const ID: u64>: RawWorkItem<ID> {}
+pub unsafe trait RawDelayedWorkItem<const ID: u64>: RawWorkItem<ID> {
+    /// The return type of [`Queue::enqueue_delayed`].
+    type EnqueueDelayedOutput;
+
+    /// See [`RawWorkItem::__enqueue`], this method only differs in return type.
+    unsafe fn __enqueue_delayed<F>(self, queue_work_on: F) -> Self::EnqueueDelayedOutput
+    where
+        F: FnOnce(*mut bindings::work_struct) -> bool;
+}
 
 /// Defines the method that should be called directly when a work item is executed.
 ///
@@ -530,6 +552,66 @@ pub unsafe fn raw_get(ptr: *const Self) -> *mut bindings::work_struct {
         // the compiler does not complain that the `work` field is unused.
         unsafe { Opaque::cast_into(core::ptr::addr_of!((*ptr).work)) }
     }
+
+    /// Enable the current work item
+    #[inline]
+    pub unsafe fn raw_enable(this: *const Self) -> bool {
+        unsafe { bindings::enable_work(Self::raw_get(this)) }
+    }
+
+    /// Disable and cancel the current work item
+    #[inline]
+    pub unsafe fn raw_disable(this: *const Self) -> bool {
+        unsafe { bindings::disable_work(Self::raw_get(this)) }
+    }
+
+    #[inline]
+    unsafe fn raw_get_delayed(this: *const Self) -> *mut bindings::delayed_work {
+        let work_ptr = unsafe { Self::raw_get(this) };
+        unsafe { container_of!(work_ptr, bindings::delayed_work, work) }
+    }
+
+    /// Disable and cancel the current delayed work item
+    #[inline]
+    pub unsafe fn raw_disable_delayed(this: *const Self) -> bool {
+        unsafe { bindings::disable_delayed_work(Self::raw_get_delayed(this)) }
+    }
+
+    /// Disable and cancel the current work item and block until it's done
+    #[inline]
+    pub unsafe fn raw_disable_sync(this: *const Self) -> bool {
+        unsafe { bindings::disable_work_sync(Self::raw_get(this)) }
+    }
+
+    /// Disable and cancel the current delayed work item and block until it's done
+    #[inline]
+    pub unsafe fn raw_disable_delayed_sync(this: *const Self) -> bool {
+        unsafe { bindings::disable_delayed_work_sync(Self::raw_get_delayed(this)) }
+    }
+
+    /// Kill off the current work item
+    #[inline]
+    pub unsafe fn raw_cancel(this: *const Self) -> bool {
+        unsafe { bindings::cancel_work(Self::raw_get(this)) }
+    }
+
+    /// Kill off the current delayed work item
+    #[inline]
+    pub unsafe fn raw_cancel_delayed(this: *const Self) -> bool {
+        unsafe { bindings::cancel_delayed_work(Self::raw_get_delayed(this)) }
+    }
+
+    /// Kill off the current work item and block until it's done
+    #[inline]
+    pub unsafe fn raw_cancel_sync(this: *const Self) -> bool {
+        unsafe { bindings::cancel_work_sync(Self::raw_get(this)) }
+    }
+
+    /// Kill off the current delayed work item and block until it's done
+    #[inline]
+    pub unsafe fn raw_cancel_delayed_sync(this: *const Self) -> bool {
+        unsafe { bindings::cancel_delayed_work_sync(Self::raw_get_delayed(this)) }
+    }
 }
 
 /// Declares that a type contains a [`Work<T, ID>`].
@@ -578,6 +660,122 @@ pub unsafe trait HasWork<T, const ID: u64 = 0> {
     unsafe fn work_container_of(ptr: *mut Work<T, ID>) -> *mut Self;
 }
 
+/// A handle representing a potentially running work item.
+pub unsafe trait WorkHandle {
+    /// Enable a work item
+    ///
+    /// SAFETY: can be called from any context.
+    ///
+    /// Returns `true` only if the disable count reached 0.
+    fn enable(self) -> bool;
+
+    /// Disable and cancel a work item
+    ///
+    /// SAFETY: Can be called from any context if `sync` is set to `false`.
+    ///
+    /// If `sync` is set to true this method will block until the work item
+    /// has been cancelled.
+    ///
+    /// Returns `true` if the work item was pending.
+    fn disable(self, sync: bool) -> bool;
+
+    /// Cancel a work item
+    ///
+    /// SAFETY: Can be called from any context if `sync` is set to `false`.
+    ///
+    /// If `sync` is set to true this method will block until the work item
+    /// has been cancelled.
+    ///
+    /// Returns `true` if the work item was pending.
+    fn cancel(self, sync: bool) -> bool;
+}
+
+/// A handle for an `Arc<HasWork<T>>` returned by a call to
+/// [`RawWorkItem::__enqueue`]
+pub struct ArcWorkHandle<T, const ID: u64 = 0>
+where
+    T: HasWork<T, ID>,
+{
+    inner: Arc<T>,
+}
+
+unsafe impl<T, const ID: u64> WorkHandle for ArcWorkHandle<T, ID>
+where
+    T: HasWork<T, ID>,
+{
+    fn enable(self) -> bool {
+        let self_ptr = Arc::as_ptr(&self.inner) as *mut T;
+        let work_ptr = unsafe { <T as HasWork<T, ID>>::raw_get_work(self_ptr) };
+
+        unsafe { Work::<T, ID>::raw_enable(work_ptr) }
+    }
+
+    fn disable(self, sync: bool) -> bool {
+        let self_ptr = Arc::as_ptr(&self.inner) as *mut T;
+        let work_ptr = unsafe { <T as HasWork<T, ID>>::raw_get_work(self_ptr) };
+
+        if sync {
+            unsafe { Work::<T, ID>::raw_disable_sync(work_ptr) }
+        } else {
+            unsafe { Work::<T, ID>::raw_disable(work_ptr) }
+        }
+    }
+
+    fn cancel(self, sync: bool) -> bool {
+        let self_ptr = Arc::as_ptr(&self.inner) as *mut T;
+        let work_ptr = unsafe { <T as HasWork<T, ID>>::raw_get_work(self_ptr) };
+
+        if sync {
+            unsafe { Work::<T, ID>::raw_cancel_sync(work_ptr) }
+        } else {
+            unsafe { Work::<T, ID>::raw_cancel(work_ptr) }
+        }
+    }
+}
+
+/// A handle for an `Arc<HasDelayedWork<T>>` returned by a call to
+/// [`RawWorkItem::__enqueue_delayed`]
+pub struct ArcDelayedWorkHandle<T, const ID: u64 = 0>
+where
+    T: HasDelayedWork<T, ID>,
+{
+    inner: Arc<T>,
+}
+
+unsafe impl<T, const ID: u64> WorkHandle for ArcDelayedWorkHandle<T, ID>
+where
+    T: HasDelayedWork<T, ID>,
+{
+    fn enable(self) -> bool {
+        let self_ptr = Arc::as_ptr(&self.inner) as *mut T;
+        let work_ptr = unsafe { <T as HasWork<T, ID>>::raw_get_work(self_ptr) };
+
+        unsafe { Work::<T, ID>::raw_enable(work_ptr) }
+    }
+
+    fn disable(self, sync: bool) -> bool {
+        let self_ptr = Arc::as_ptr(&self.inner) as *mut T;
+        let work_ptr = unsafe { <T as HasWork<T, ID>>::raw_get_work(self_ptr) };
+
+        if sync {
+            unsafe { Work::<T, ID>::raw_disable_delayed_sync(work_ptr) }
+        } else {
+            unsafe { Work::<T, ID>::raw_disable_delayed(work_ptr) }
+        }
+    }
+
+    fn cancel(self, sync: bool) -> bool {
+        let self_ptr = Arc::as_ptr(&self.inner) as *mut T;
+        let work_ptr = unsafe { <T as HasWork<T, ID>>::raw_get_work(self_ptr) };
+
+        if sync {
+            unsafe { Work::<T, ID>::raw_cancel_delayed_sync(work_ptr) }
+        } else {
+            unsafe { Work::<T, ID>::raw_cancel_delayed(work_ptr) }
+        }
+    }
+}
+
 /// Used to safely implement the [`HasWork<T, ID>`] trait.
 ///
 /// # Examples
@@ -841,7 +1039,7 @@ unsafe impl<T, const ID: u64> RawWorkItem<ID> for Arc<T>
     T: WorkItem<ID, Pointer = Self>,
     T: HasWork<T, ID>,
 {
-    type EnqueueOutput = Result<(), Self>;
+    type EnqueueOutput = Result<ArcWorkHandle<T, ID>, Self>;
 
     unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
     where
@@ -856,7 +1054,7 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
         let work_ptr = unsafe { Work::raw_get(work_ptr) };
 
         if queue_work_on(work_ptr) {
-            Ok(())
+            Ok(ArcWorkHandle { inner: unsafe { Arc::from_raw(ptr) } })
         } else {
             // SAFETY: The work queue has not taken ownership of the pointer.
             Err(unsafe { Arc::from_raw(ptr) })
@@ -872,6 +1070,27 @@ unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Arc<T>
     T: WorkItem<ID, Pointer = Self>,
     T: HasDelayedWork<T, ID>,
 {
+    type EnqueueDelayedOutput = Result<ArcDelayedWorkHandle<T, ID>, Self>;
+
+    unsafe fn __enqueue_delayed<F>(self, queue_work_on: F) -> Self::EnqueueDelayedOutput
+    where
+        F: FnOnce(*mut bindings::work_struct) -> bool,
+    {
+        // Casting between const and mut is not a problem as long as the pointer is a raw pointer.
+        let ptr = Arc::into_raw(self).cast_mut();
+
+        // SAFETY: Pointers into an `Arc` point at a valid value.
+        let work_ptr = unsafe { T::raw_get_work(ptr) };
+        // SAFETY: `raw_get_work` returns a pointer to a valid value.
+        let work_ptr = unsafe { Work::raw_get(work_ptr) };
+
+        if queue_work_on(work_ptr) {
+            Ok(ArcDelayedWorkHandle { inner: unsafe { Arc::from_raw(ptr) } })
+        } else {
+            // SAFETY: The work queue has not taken ownership of the pointer.
+            Err(unsafe { Arc::from_raw(ptr) })
+        }
+    }
 }
 
 // SAFETY: TODO.
@@ -932,6 +1151,14 @@ unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Pin<KBox<T>>
     T: WorkItem<ID, Pointer = Self>,
     T: HasDelayedWork<T, ID>,
 {
+    type EnqueueDelayedOutput = ();
+
+    unsafe fn __enqueue_delayed<F>(self, queue_work_on: F) -> Self::EnqueueDelayedOutput
+    where
+        F: FnOnce(*mut bindings::work_struct) -> bool,
+    {
+        unsafe { self.__enqueue(queue_work_on) }
+    }
 }
 
 /// Returns the system work queue (`system_wq`).
-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ