Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: workqueue: add support for ARef<T>

Add support for the ARef<T> smart pointer. This allows an instance of
ARef<T> to handle deferred work directly, which can be convenient or even
necessary at times, depending on the specifics of the driver or subsystem.

The implementation is similar to that of Arc<T>, and a subsequent patch
will implement support for drm::Device as the first user. This is notably
important for work items that need access to the drm device, as it was not
possible to enqueue work on a ARef<drm::Device<T>> previously without
failing the orphan rule.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
Link: https://lore.kernel.org/r/20260323-aref-workitem-v3-1-f59729b812aa@collabora.com
Signed-off-by: Alice Ryhl <aliceryhl@google.com>

authored by

Daniel Almeida and committed by
Alice Ryhl
f5e841e4 1998e6be

+79 -6
+79 -6
rust/kernel/workqueue.rs
··· 192 192 sync::Arc, 193 193 sync::LockClassKey, 194 194 time::Jiffies, 195 - types::Opaque, 195 + types::{ARef, AlwaysRefCounted, Opaque}, 196 196 }; 197 - use core::marker::PhantomData; 197 + use core::{marker::PhantomData, ptr::NonNull}; 198 198 199 199 /// Creates a [`Work`] initialiser with the given name and a newly-created lock class. 200 200 #[macro_export] ··· 425 425 426 426 /// Defines the method that should be called directly when a work item is executed. 427 427 /// 428 - /// This trait is implemented by `Pin<KBox<T>>` and [`Arc<T>`], and is mainly intended to be 429 - /// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`] 430 - /// instead. The [`run`] method on this trait will usually just perform the appropriate 431 - /// `container_of` translation and then call into the [`run`][WorkItem::run] method from the 428 + /// This trait is implemented by `Pin<KBox<T>>`, [`Arc<T>`] and [`ARef<T>`], and 429 + /// is mainly intended to be implemented for smart pointer types. For your own 430 + /// structs, you would implement [`WorkItem`] instead. The [`run`] method on 431 + /// this trait will usually just perform the appropriate `container_of` 432 + /// translation and then call into the [`run`][WorkItem::run] method from the 432 433 /// [`WorkItem`] trait. 433 434 /// 434 435 /// This trait is used when the `work_struct` field is defined using the [`Work`] helper. ··· 933 932 T: WorkItem<ID, Pointer = Self>, 934 933 T: HasDelayedWork<T, ID>, 935 934 { 935 + } 936 + 937 + // SAFETY: Like the `Arc<T>` implementation, the `__enqueue` implementation for 938 + // `ARef<T>` obtains a `work_struct` from the `Work` field using 939 + // `T::raw_get_work`, so the same safety reasoning applies: 940 + // 941 + // - `__enqueue` gets the `work_struct` from the `Work` field, using `T::raw_get_work`. 942 + // - The only safe way to create a `Work` object is through `Work::new`. 943 + // - `Work::new` makes sure that `T::Pointer::run` is passed to `init_work_with_key`. 944 + // - Finally `Work` and `RawWorkItem` guarantee that the correct `Work` field 945 + // will be used because of the ID const generic bound. This makes sure that `T::raw_get_work` 946 + // uses the correct offset for the `Work` field, and `Work::new` picks the correct 947 + // implementation of `WorkItemPointer` for `ARef<T>`. 948 + unsafe impl<T, const ID: u64> WorkItemPointer<ID> for ARef<T> 949 + where 950 + T: AlwaysRefCounted, 951 + T: WorkItem<ID, Pointer = Self>, 952 + T: HasWork<T, ID>, 953 + { 954 + unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { 955 + // The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`. 956 + let ptr = ptr.cast::<Work<T, ID>>(); 957 + 958 + // SAFETY: This computes the pointer that `__enqueue` got from 959 + // `ARef::into_raw`. 960 + let ptr = unsafe { T::work_container_of(ptr) }; 961 + 962 + // SAFETY: The safety contract of `work_container_of` ensures that it 963 + // returns a valid non-null pointer. 964 + let ptr = unsafe { NonNull::new_unchecked(ptr) }; 965 + 966 + // SAFETY: This pointer comes from `ARef::into_raw` and we've been given 967 + // back ownership. 968 + let aref = unsafe { ARef::from_raw(ptr) }; 969 + 970 + T::run(aref) 971 + } 972 + } 973 + 974 + // SAFETY: The `work_struct` raw pointer is guaranteed to be valid for the duration of the call to 975 + // the closure because we get it from an `ARef`, which means that the ref count will be at least 1, 976 + // and we don't drop the `ARef` ourselves. If `queue_work_on` returns true, it is further guaranteed 977 + // to be valid until a call to the function pointer in `work_struct` because we leak the memory it 978 + // points to, and only reclaim it if the closure returns false, or in `WorkItemPointer::run`, which 979 + // is what the function pointer in the `work_struct` must be pointing to, according to the safety 980 + // requirements of `WorkItemPointer`. 981 + unsafe impl<T, const ID: u64> RawWorkItem<ID> for ARef<T> 982 + where 983 + T: AlwaysRefCounted, 984 + T: WorkItem<ID, Pointer = Self>, 985 + T: HasWork<T, ID>, 986 + { 987 + type EnqueueOutput = Result<(), Self>; 988 + 989 + unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput 990 + where 991 + F: FnOnce(*mut bindings::work_struct) -> bool, 992 + { 993 + let ptr = ARef::into_raw(self); 994 + 995 + // SAFETY: Pointers from ARef::into_raw are valid and non-null. 996 + let work_ptr = unsafe { T::raw_get_work(ptr.as_ptr()) }; 997 + // SAFETY: `raw_get_work` returns a pointer to a valid value. 998 + let work_ptr = unsafe { Work::raw_get(work_ptr) }; 999 + 1000 + if queue_work_on(work_ptr) { 1001 + Ok(()) 1002 + } else { 1003 + // SAFETY: The work queue has not taken ownership of the pointer. 1004 + Err(unsafe { ARef::from_raw(ptr) }) 1005 + } 1006 + } 936 1007 } 937 1008 938 1009 /// Returns the system work queue (`system_wq`).