// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2025-2026 Red Hat Inc. * Author: Philipp Stanner */ //! DMA Fence support. //! //! Reference: //! //! header: [`include/linux/dma-fence.h`](srctree/include/linux/dma-fence.h) use crate::{ alloc::AllocError, bindings, container_of, error::to_result, prelude::*, types::ForeignOwnable, types::Opaque, // }; use core::{ marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr, ptr::{ drop_in_place, NonNull, // }, // }; use kernel::{ str::CString, sync::{ aref::{ ARef, AlwaysRefCounted, // }, atomic::{ Atomic, Relaxed, // }, rcu::rcu_barrier, // }, // }; /// VTable for dma_fence backend_ops callbacks. // // Mandatory dma_fence backend_ops are implemented implicitly through // [`FenceContext`]. Additional ones shall get implemented on this trait. pub trait FenceContextOps { /// The generic payload data for [`DriverFence`]s created on this fctx. type FenceDataType: Send + Sync; } /// A dma-fence context. A fence context takes care of associating related fences /// with each other, providing each with raising sequence numbers and a common /// identifier. #[pin_data(PinnedDrop)] pub struct FenceContext { /// The fence context number. nr: u64, /// The sequence number for the next fence created. seqno: Atomic, // The name parameters can be accessed by the dma_fence backend_ops. UAF // errors are prevented by the `call_rcu()` in `drop_driver_fence_data()`. /// The name of the driver this FenceContext's fences belong to. driver_name: CString, /// The name of the timeline this FenceContext's fences belong to. timeline_name: CString, /// The number of all unsignaled fences on this context. // Used to prevent bugs due to forgotten fences. // // The lifetime on `DriverFence`s should typically prevent this from // happening. // // However, we cannot fully guarantee in Rust that `DriverFence`s will not // be forgotten, e.g., through `core::mem::forget()`. This could circumvent // the lifetime which intends to enforce that all fences disappear before // their context. nr_of_unsignaled_fences: Atomic, /// The user's data. #[pin] data: T, } impl<'a, T: Send + Sync + FenceContextOps> FenceContext { // This can later be extended as a vtable in case other parties need support // for the more "exotic" callbacks. const OPS: bindings::dma_fence_ops = bindings::dma_fence_ops { get_driver_name: Some(Self::get_driver_name), get_timeline_name: Some(Self::get_timeline_name), enable_signaling: None, signaled: None, // Deprecated. wait: None, // Must never be implemented for these abstractions. release: None, set_deadline: None, }; /// Create a new `FenceContext`. pub fn new( initial_seqno: u64, driver_name: &CStr, timeline_name: &CStr, data: impl PinInit, ) -> impl PinInit where Error: From, { let driver_name = CString::try_from(driver_name); let timeline_name = CString::try_from(timeline_name); try_pin_init!(Self { // SAFETY: `dma_fence_context_alloc()` merely works on a global // atomic. Parameter `1` is the number of contexts we want to // allocate. nr: unsafe { bindings::dma_fence_context_alloc(1) }, seqno: Atomic::new(initial_seqno), driver_name: driver_name?, timeline_name: timeline_name?, nr_of_unsignaled_fences: Atomic::new(0), data <- data, }) } fn next_seqno(&self) -> u64 { self.seqno.fetch_add(1, Relaxed) } /// Allocate the memory for a [`DriverFence`] and already store `data` inside. /// /// This is needed because many times, creation of a [`DriverFence`] must not /// fail, and allocating might deadlock in some situations. /// /// The `data` you pass here must not perform any operations that are illegal /// in atomic context in its [`Drop`] implementation. pub fn new_fence_allocation( &self, data: T::FenceDataType, ) -> Result> { let fence_data = DriverFenceData { rcu_head: Default::default(), // `inner` remains uninitialized until a `DriverFence` takes over. inner: Fence { inner: Opaque::uninit(), }, fctx: self, data, }; // In order to support the C dma_fence callbacks, it is necessary for // a `Fence` and a `DriverFence` to live in the same allocation, // because the C backend passes a dma_fence, from which the driver most // likely wants to be able to access its `data` in `DriverFence`. // // Hence, we need the manage the memory manually. It will be freed by the // C backend automatically once the refcount within `Fence` drops to 0. let data = KBox::new(fence_data, GFP_KERNEL | __GFP_ZERO)?; Ok(DriverFenceAllocation { data, ops: &Self::OPS, }) } extern "C" fn get_driver_name(ptr: *mut bindings::dma_fence) -> *const c_char { // SAFETY: The C backend only invokes this callback with `ptr` pointing // to a valid, unsignaled `bindings::dma_fence`. All fences created in // this module always reside within `Fence` which always resides in a // `DriverFenceData`, thus satisfying the function's safety // requirements. let fctx = unsafe { Self::from_raw_fence(ptr) }; fctx.driver_name.as_char_ptr() } extern "C" fn get_timeline_name(ptr: *mut bindings::dma_fence) -> *const c_char { // SAFETY: The C backend only invokes this callback with `ptr` pointing // to a valid, unsignaled `bindings::dma_fence`. All fences created in // this module always reside within `Fence` which always resides in a // `DriverFenceData`, thus satisfying the function's safety // requirements. let fctx = unsafe { Self::from_raw_fence(ptr) }; fctx.timeline_name.as_char_ptr() } /// Create a [`FenceContext`] from an associated [`bindings::dma_fence`]. /// /// # Safety /// /// `ptr` must be a valid pointer to a [`bindings::dma_fence`] which resides /// within a [`Fence`], which in turn resides in a [`DriverFenceData`]. unsafe fn from_raw_fence(ptr: *mut bindings::dma_fence) -> &'a Self { let opaque_fence = Opaque::cast_from(ptr); // SAFETY: Safe due to the function's overall safety requirements. let fence_ptr = unsafe { container_of!(opaque_fence, Fence, inner) }; // CAST: `DriverFenceData` is `repr(C)` and a `Fence` is its first member. let fence_data_ptr: *const DriverFenceData<'a, T> = fence_ptr.cast(); // SAFETY: Safe because of the comments directly above. let fence_data = unsafe { &*fence_data_ptr }; fence_data.fctx } } #[pinned_drop] impl PinnedDrop for FenceContext { fn drop(self: Pin<&mut Self>) { // Fence ops callbacks can be called on unsignaled fences. Since these // callbacks can access the fence context and its data, it needs to be // guaranteed that a context only drops after all associated // `DriverFence`s have been dropped. This is unlikely to occur, but // would result in silent UAF. Throw a panic to prevent that. // // TODO: // It would be better if the fence context signals all forgotten fences // itself. To do so, it would keep a list of unsignaled fences. That // list's members would have to be pre-allocated (see // `FenceCallback::new_fence_allocation()`). if self.nr_of_unsignaled_fences.load(Relaxed) != 0 { panic!("Forgotten fences in FenceContext."); } // Ensure that the driver cannot unload while there are still dma_fence // callbacks running. At the same time, the RCU barrier addresses the // problem inherited by the C backend, in which backend ops callbacks // might be accessing the fence while it is being signaled (or shortly // after). This could cause UAF access on the fence context's // `fctx.driver_name` and `fctx.timeline_name`. // // Wait for the RCU callbacks in `DriverFence::drop`. rcu_barrier(); } } /// Error type for fence callback registration. /// /// Generic over `T` so that `AlreadySignaled` can return the callback to the /// caller, allowing it to reclaim any resources owned by the callback (e.g., /// a fence handle that needs to be signaled). #[derive(Debug)] pub enum CallbackError { /// The fence was already signaled. The callback is returned so the caller /// can extract owned resources without losing them. AlreadySignaled(T), /// Some other error occurred during registration. Other(Error), } impl From> for Error { #[inline] fn from(err: CallbackError) -> Self { match err { CallbackError::AlreadySignaled(_) => ENOENT, CallbackError::Other(e) => e, } } } impl From for CallbackError { #[inline] fn from(e: AllocError) -> Self { CallbackError::Other(Error::from(e)) } } /// Trait for callbacks that can be registered on fences. /// /// When the fence signals, the callback will be invoked. /// /// # Example /// /// ```rust /// use kernel::dma_buf::FenceCallback; /// /// struct MyCallback { /// // Your callback state here /// } /// /// impl FenceCallback for MyCallback { /// fn on_signal(&mut self) { /// pr_info!("Fence signaled!\n"); /// // Handle fence completion /// } /// } /// ``` pub trait FenceCallback: Send + 'static { /// Called when the fence is signaled. /// /// This is called from the fence signaling path, which may be in interrupt /// context or with locks held, which is why `self` is only borrowed, so that /// it cannot drop. Implementations must not sleep or perform /// long-running operations. /// /// An implementation likely wants to inform itself (e.g., through a work item) /// within this callback that the associated [`FenceCallbackRegistration`] /// can now be dropped. fn on_signal(&mut self); } /// A callback registration on a fence. /// /// When this object is dropped, the callback is automatically removed if it /// hasn't been called yet. #[pin_data(PinnedDrop)] pub struct FenceCallbackRegistration { #[pin] callback_foreign: Opaque, callback: ManuallyDrop, fence: ARef, } impl FenceCallbackRegistration { /// Create a [`PinInit`] closure for registering a callback on a fence. /// /// The actual attempt at registering the callback will take place once you /// call an allocator's `pin_init()` function. /// /// On success the callback is pinned in place and will fire when the fence /// signals. On `AlreadySignaled` the callback is returned to the caller so /// that owned resources can be reclaimed. pub fn new<'a>(fence: &'a Fence, callback: T) -> impl PinInit> + 'a where T: 'a, { try_pin_init!(Self { // We need to fully initialize the fence because after // `dma_fence_add_callback()` ran, the callback might immediately // get invoked. callback: ManuallyDrop::new(callback), fence: ARef::from(fence), callback_foreign <- Opaque::try_ffi_init(|ptr| { // SAFETY: `fence.inner.get()` is a valid, initialized `struct // dma_fence`. `ptr` points to the `struct dma_fence_cb` field // within the pinned allocation, so it remains valid until // `dma_fence_remove_callback()` in `PinnedDrop` or until the // callback fires. let ret = unsafe { to_result(bindings::dma_fence_add_callback( fence.inner.get(), ptr, Some(Self::dma_fence_callback), )) }; match ret { Ok(()) => Ok(()), Err(e) => { // SAFETY: We could not register the callback. Thus, // C will not use it. So we can just take it back // and pass it to the user again. let cb_back = unsafe { ManuallyDrop::take(callback) }; if e == ENOENT { Err(CallbackError::AlreadySignaled(cb_back)) } else { Err(CallbackError::Other(e)) } }, } }), }? CallbackError) } /// Raw dma fence callback that is called by the C code. /// /// # Safety /// /// This is only called by the dma_fence subsystem with valid pointers. unsafe extern "C" fn dma_fence_callback( _fence: *mut bindings::dma_fence, callback_foreign: *mut bindings::dma_fence_cb, ) { let ptr = Opaque::cast_from(callback_foreign).cast_mut(); // SAFETY: All callbacks we can receive here have been created in such a way that they are // embedded into a `FenceCallbackRegistration`. let reg: *mut Self = unsafe { container_of!(ptr, Self, callback_foreign) }; // SAFETY: `reg` is a valid `Self` pointer. // // The backend ensures synchronisation so whoever holds the registration object cannot drop // it while this code is running. See `FenceCallbackRegistration::drop`. unsafe { (*reg).callback.on_signal() }; } /// Returns a reference to the fence this callback is registered on. #[inline] pub fn fence(&self) -> &Fence { &self.fence } } #[pinned_drop] impl PinnedDrop for FenceCallbackRegistration { fn drop(self: Pin<&mut Self>) { // Always call `dma_fence_remove_callback()`, even if the callback // already ran. This is necessary for synchronization: // `dma_fence_remove_callback()` acquires `fence->lock`, which ensures // that any in-flight `dma_fence_signal()` (which calls our callback // while holding the same lock) has completed before we free the struct. // // Without this, Drop can race with a concurrent signal: // CPU0 (signal, lock held): take() -> on_signal(fence_ref) (in progress) // CPU1 (drop): skips lock -> frees struct // CPU0: accesses fence_ref -> use-after-free // // When the callback has already fired, the signal path detached the // list node via `INIT_LIST_HEAD()`, so dma_fence_remove_callback just // sees an empty node and returns false — the lock acquisition is the // only thing that matters. // // SAFETY: The fence pointer is valid and the cb was initialized by // `dma_fence_add_callback()` during construction. unsafe { bindings::dma_fence_remove_callback(self.fence.as_raw(), self.callback_foreign.get()) }; // SAFETY: This is literally the drop implementation, so no one has // dropped this so far; so we can do it now. unsafe { ManuallyDrop::::drop(self.project().callback) }; } } // SAFETY: FenceCallbackRegistration can be sent between threads. unsafe impl Send for FenceCallbackRegistration {} // SAFETY: &FenceCallbackRegistration can be shared between threads if &T can. unsafe impl Sync for FenceCallbackRegistration where T: Sync {} /// The receiving counterpart of a [`DriverFence`]. /// /// The Rust DMA fence implementation has a dualistic design: [`DriverFence`]s /// are the producer-side, intended to be always owned by only one party. That /// party has the monopoly on signaling the fence. /// /// A [`Fence`] is the counterpart for consumers. Thus, [`Fence`]s are always /// refcounted and can shared with an arbitrary number of parties, including /// userspace. A [`Fence`] can only be used for actions such as checking the /// fence's status or for registering callbacks on it. /// /// Once the associated [`DriverFence`] signals, all /// [`FenceCallbackRegistration`]s registered on the [`Fence`] will be executed. /// /// A [`Fence`] can arbitrarily outlive its [`DriverFence`] and the /// [`FenceContext`]. Signaling a [`DriverFence`] decouples it from its /// [`Fence`]s. #[repr(transparent)] pub struct Fence { /// The actual dma_fence passed to C. inner: Opaque, } /// Guard helper for locking within this module. /// /// Its only purpose for now is to avoid a number of unsafe lock-unlock cycles. /// It is never used outside of this module. // TODO: This should be made more canonical, probably by basing it on a // SpinLockIrqGuard once available. struct FenceGuard<'a> { inner: &'a Fence, flags: usize, } impl<'a> Deref for FenceGuard<'a> { type Target = &'a Fence; fn deref(&self) -> &Self::Target { &self.inner } } impl Drop for FenceGuard<'_> { fn drop(&mut self) { // SAFETY: `fence` is valid because `self` is valid. `flag_ptr` is // merely a pointer to an integer, which lives as long as this function. // When a `FenceGuard` exists, the lock has been taken by definition. unsafe { bindings::dma_fence_unlock_irqrestore(self.as_raw(), &raw mut self.flags) }; } } // SAFETY: Fences are literally designed to be shared between threads. unsafe impl Send for Fence {} // SAFETY: Fences are literally designed to be shared between threads. unsafe impl Sync for Fence {} impl Fence { /// Check whether the fence was signaled at the moment of the function call. /// /// Note that this can return `true` for a [`Fence`] whose [`DriverFence`] /// has not yet been dropped. The reason is that the fence ops callbacks can /// cause the fence to get signaled by the C backend. #[inline] pub fn is_signaled(&self) -> bool { // We should not use `dma_fence_is_signaled_locked()` here, because // according to the C backend's recommendations, that function is // problematic and we should avoid calling that function with a lock // held. // SAFETY: Inner `fence` is valid because `self` is valid. let ret = unsafe { bindings::dma_fence_is_signaled(self.as_raw()) }; // To be as robust as possible for the future we guarantee that an API // caller can 100% rely on the signaling being completed (i.e., all // fence callbacks ran), so we have to take the lock. // // The reason is that the C dma_fence backend currently does not // carefully synchronize the `dma_fence_is_signaled()` function with the // proper spinlock. This can lead to the function returning `true` while // fence callbacks are still being executed. This can be mitigated by // guarding the entire function with the spinlock. // // The fundamental reason is that the C backend currently does guard // setting of the fence's signaled-bit with the fence's spinlock, but // reading is done locklessly. // // See commit c8a5d5ea3ba6a. let _ = self.lock(); ret } /// Lock the fence. A helper only to be used internally in this module. fn lock(&self) -> FenceGuard<'_> { let mut guard = FenceGuard { inner: self, flags: 0, }; // SAFETY: `fence` is valid because `self` is valid. `flag_ptr` is // merely a pointer to an integer, whose lifetime is tied to the guard // object. unsafe { bindings::dma_fence_lock_irqsave(self.as_raw(), &raw mut guard.flags) }; guard } /// Get the fence's sequence number. #[inline] pub fn seqno(&self) -> u64 { // SAFETY: Valid because `self` is valid. unsafe { (*self.as_raw()).seqno } } fn as_raw(&self) -> *mut bindings::dma_fence { self.inner.get() } /// Create a [`Fence`] from a raw C [`bindings::dma_fence`]. /// /// # Safety /// /// `ptr` must point to an initialized fence that is embedded into a [`Fence`]. #[inline] pub unsafe fn from_raw<'a>(ptr: *mut bindings::dma_fence) -> &'a Self { // SAFETY: Safe as per the function's overall safety requirements. unsafe { &*ptr.cast() } } } // SAFETY: These implement the C backends refcounting methods which are proven // to work correctly. unsafe impl AlwaysRefCounted for Fence { fn inc_ref(&self) { // SAFETY: `self.as_raw()` is a pointer to a valid `struct dma_fence`. unsafe { bindings::dma_fence_get(self.as_raw()) } } unsafe fn dec_ref(ptr: NonNull) { // SAFETY: `ptr` is never a NULL pointer; and when `dec_ref()` is called // the fence is by definition still valid. let fence = unsafe { (*ptr.as_ptr()).inner.get() }; // SAFETY: `fence` was created validly above. When `dec_ref()` is called, // there is by definition still a reference alive that can be put. unsafe { bindings::dma_fence_put(fence) } } } // Necessary to guarantee that `inner` always comes first and can be freed by C. // Also useful for using casts instead of container_of(). #[repr(C)] #[pin_data] struct DriverFenceData<'a, T: Send + Sync + FenceContextOps> { #[pin] /// The inner fence. // Must always be the first member so that unsafe casting works; but also // necessary so that the C backend can free the allocation (coming from our // Rust code) with kfree_rcu(). inner: Fence, /// Callback head for dropping this in a deferred manner through RCU. rcu_head: bindings::callback_head, /// Reference to access the FenceContext. fctx: &'a FenceContext, /// The API user's data. It is essential that the data only performs /// operations legal in atomic context in its [`Drop`] implementation. #[pin] data: T::FenceDataType, } /// A synchronization primitive mainly for GPU drivers. /// /// The Rust DMA fence implementation has a dualistic design: [`DriverFence`]s /// are the producer-side, intended to be always owned by only one party. That /// party has the monopoly on signaling the fence. /// /// A [`Fence`] is the counterpart for consumers. Thus, [`Fence`]s are always /// refcounted and can be shared with an arbitrary number of parties, including /// userspace. A [`Fence`] can only be used for actions such as checking the /// fence's status or for registering callbacks on it. /// /// Once the associated [`DriverFence`] signals, all /// [`FenceCallbackRegistration`]s registered on a [`Fence`] will be executed. /// /// A [`Fence`] can arbitrarily outlive its [`DriverFence`] and the /// [`FenceContext`]. Signaling a [`DriverFence`] decouples it from its /// [`Fence`]s. /// /// It is crucial that a [`DriverFence`] always correctly represents the state /// of the associated job on the hardware. Especially, it is strictly necessary /// that the owner ensures that all [`DriverFence`]s eventually get signaled. /// As a last resort, a [`DriverFence`] will signal itself if it drops /// unsignaled and print a warning. /// /// This design intends to implement the [`bindings::dma_fence_ops`] in such a /// way that the driver-data necessary to implement the callback's functionality /// resides in the [`FenceContext`]. Thus, a [`DriverFence`] contains a /// reference to the context, which can be accessed in the callbacks. The /// implementation, therefore, ensures that a [`DriverFence`] cannot outlive its /// [`FenceContext`]. Unfortunately, this can be circumvented under certain /// circumstances in Rust (e.g., usage of [`core::mem::forget`]). /// /// In the unlikely case of such violations, a panic is thrown. /// /// # Examples /// /// ``` /// use kernel::{ /// dma_buf::{ /// DriverFence, /// FenceContext, /// FenceContextOps, /// FenceCallback, /// FenceCallbackRegistration, /// }, /// str::CString, /// sync::aref::ARef, // /// }; /// use core::fmt::Display; /// /// struct CallbackData { } /// /// impl FenceCallback for CallbackData { /// fn on_signal(&mut self) { /// pr_info!("DmaFence callback executed.\n"); /// } /// } /// /// #[pin_data] /// struct FenceContextData {} /// /// impl FenceContextData { /// fn new() -> impl PinInit { /// pin_init!(Self {}) /// } /// } /// /// impl FenceContextOps for FenceContextData { /// type FenceDataType = FenceData; /// } /// /// let fctx_data = FenceContextData::new(); /// /// /// let mut fctx = KBox::pin_init( /// FenceContext::new(0, c"dummy_driver", c"dummy_timeline", fctx_data), /// GFP_KERNEL /// )?; /// /// struct FenceData { /// data: CString, /// } /// /// let fence_data = FenceData { data: c"dummy_data".try_into()? }; /// /// let fence_alloc = fctx.new_fence_allocation(fence_data)?; /// let mut fence = fence_alloc.new_fence(); /// /// let cb_data = CallbackData { }; /// let waiting_fence = ARef::from(fence.as_fence()); /// let cb_reg = FenceCallbackRegistration::new(&waiting_fence, cb_data); /// let cb_reg = KBox::pin_init(cb_reg, GFP_KERNEL)?; /// /// // TODO signalling guards /// assert_eq!(waiting_fence.is_signaled(), false); /// fence.signal(Ok(())); /// assert_eq!(waiting_fence.is_signaled(), true); /// /// Ok::<(), Error>(()) /// ``` pub struct DriverFence<'a, T: Send + Sync + FenceContextOps> { /// The actual content of the fence. Lives in a [`NonNull`] so that its /// memory can be managed independently. Valid until both the [`DriverFence`] /// and all associated [`Fence`]s have disappeared. data: NonNull>, } /// A pre-prepared DMA fence, carrying the user's data and the memory it and the /// fence reside in. Only useful for creating a [`DriverFence`]. Splitting /// allocation and full initialization is necessary because fences cannot be /// allocated dynamically in some circumstances (deadlock). pub struct DriverFenceAllocation<'a, T: Send + Sync + FenceContextOps> { /// The memory for the actual content of the fence. /// Handed over to a [`DriverFence`], or deallocated once the /// [`DriverFenceAllocation`] drops. data: KBox>, /// Reference for the ops for the associated [`FenceContext`] ops: &'static bindings::dma_fence_ops, } impl<'a, T: Send + Sync + FenceContextOps> DriverFenceAllocation<'a, T> { /// Create a new [`DriverFence`], the signalable counterpart of a [`Fence`]. /// /// This increments the sequence number in the associated [`FenceContext`]. pub fn new_fence(self) -> DriverFence<'a, T> { // We feed the C dma_fence backend a NULL for the spinlock so that it // uses per-fence locks automatically. let null_ptr: *mut bindings::spinlock = ptr::null_mut(); let seqno = self.data.fctx.next_seqno(); let fence_ptr = self.as_raw(); // SAFETY: `fence_ptr` has been created directly above. It will live // at least as long as `Self`. The same applies to `&Self::OPS`. unsafe { bindings::dma_fence_init(fence_ptr, self.ops, null_ptr, self.data.fctx.nr, seqno) }; self.data.fctx.nr_of_unsignaled_fences.fetch_add(1, Relaxed); // A `DriverFenceAllocation`'s purpose is to carry allocated memory, so // that `DriverFence`s can always be created without allocating. In this // method, ownership over that memory is transferred to the new // `DriverFence` and managed through refcounting. The C dma_fence // backend will ultimately free the memory once the refcount reaches 0. let ptr = KBox::into_raw(self.data); // SAFETY: `ptr` was just created validly directly above. let ptr = unsafe { NonNull::new_unchecked(ptr) }; DriverFence { data: ptr } } fn as_raw(&self) -> *mut bindings::dma_fence { self.data.inner.inner.get() } } impl<'a, T: Send + Sync + FenceContextOps> DriverFence<'a, T> { fn as_raw(&self) -> *mut bindings::dma_fence { // SAFETY: Valid because `self` is valid. let fence_data = unsafe { &*self.data.as_ptr() }; fence_data.inner.inner.get() } /// Create a [`DriverFence`] from a raw pointer to a [`bindings::dma_fence`]. /// /// # Safety /// /// `ptr` must be a valid pointer to a `dma_fence` that was obtained through /// a [`DriverFence`] with matching generic data for both fence and associated /// [`FenceContext`]. unsafe fn from_raw(ptr: *mut bindings::dma_fence) -> Self { let opaque_fence = Opaque::cast_from(ptr); // SAFETY: Safe due to the function's overall safety requirements. let fence_ptr = unsafe { container_of!(opaque_fence, Fence, inner) }; // DriverFenceData is `repr(C)` and a Fence is its first member. let fence_data_ptr = fence_ptr as *mut DriverFenceData<'a, T>; // SAFETY: `fence_data_ptr` was created validly above. let data = unsafe { NonNull::new_unchecked(fence_data_ptr) }; Self { data } } /// Return the underlying [`Fence`]. #[inline] pub fn as_fence(&self) -> &Fence { // SAFETY: `self` is by definition still valid, and it cannot drop until // this new reference is gone. unsafe { Fence::from_raw(self.as_raw()) } } /// Signal the fence. This will invoke all registered callbacks. pub fn signal(self, res: Result) { let fence = self.as_fence().lock(); // SAFETY: `fence` is valid because `self` is valid. The lock must be // held, which we acquired directly above. if !unsafe { bindings::dma_fence_test_signaled_flag(fence.as_raw()) } { if let Err(err) = res { // SAFETY: `fence` is valid because `self` is valid. The fence // must not have been signaled yet, which we check directly above. unsafe { bindings::dma_fence_set_error(fence.as_raw(), err.to_errno()) }; } // SAFETY: `fence` is valid because `self` is valid. The lock must // be held, which we acquired above. unsafe { bindings::dma_fence_signal_locked(fence.as_raw()) }; } // SAFETY: `self.data` is valid because `self` is valid. let fctx = unsafe { self.data.as_ref().fctx }; let _ = fctx.nr_of_unsignaled_fences.fetch_sub(1, Relaxed); } } // SAFETY: Fences are literally designed to be shared between threads. unsafe impl<'a, T: Send + Sync + FenceContextOps> Send for DriverFence<'a, T> {} // SAFETY: Fences are literally designed to be shared between threads. unsafe impl<'a, T: Send + Sync + FenceContextOps> Sync for DriverFence<'a, T> {} impl<'a, T: Send + Sync + FenceContextOps> Deref for DriverFence<'a, T> { type Target = T::FenceDataType; fn deref(&self) -> &Self::Target { // SAFETY: Thanks to refcounting, `data` is always valid as long as `self` is. let data = unsafe { &*self.data.as_ptr() }; &data.data } } /// A borrow wrapper for [`DriverFence`]. Implements [`Deref`]. pub struct DriverFenceBorrow<'a, T: Send + Sync + FenceContextOps> { driver_fence: ManuallyDrop>, _lifetime: PhantomData<&'a T>, } impl<'a, T: Send + Sync + FenceContextOps> Deref for DriverFenceBorrow<'a, T> { type Target = DriverFence<'a, T>; fn deref(&self) -> &Self::Target { self.driver_fence.deref() } } // SAFETY: The Rust dma_fence abstractions are already designed around the inner // C `dma_fence`, which can serve safely as the identification point when being // owned by C. Moreover, safety is ensured by not dropping `DriverFence` and by // only allowing operations without side effects on the Borrowed type. unsafe impl ForeignOwnable for DriverFence<'_, T> { type Borrowed<'a> = DriverFenceBorrow<'a, T> where Self: 'a; type BorrowedMut<'a> = DriverFenceBorrow<'a, T> where Self: 'a; const FOREIGN_ALIGN: usize = core::mem::align_of::(); fn into_foreign(self) -> *mut c_void { let fence = self; let ptr = fence.as_raw(); // DriverFence must not drop. let _ = ManuallyDrop::new(fence); ptr.cast() } unsafe fn from_foreign(ptr: *mut c_void) -> Self { // SAFETY: Safe because the trait implementation only invokes this with // a valid `ptr`, associated to a `DriverFence` with matching generic data. unsafe { Self::from_raw(ptr.cast()) } } unsafe fn borrow<'a>(ptr: *mut c_void) -> Self::Borrowed<'a> where Self: 'a, { // SAFETY: The trait implementation ensures that `ptr` always resides // within a [`Fence`] within a [`DriverFenceData`]. let driver_fence = unsafe { Self::from_raw(ptr.cast()) }; let driver_fence = ManuallyDrop::new(driver_fence); DriverFenceBorrow { driver_fence, _lifetime: PhantomData, } } unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Self::BorrowedMut<'a> // FIXME: The bound below and the one above in `borrow` should actually be // unnecessary since the compiler should be able to completely derive all // necessary information automatically. There is currently a compiler bug // preventing that, though: // // https://github.com/rust-lang/rust/issues/155430. // // (Help to) fix the compiler bug and remove the bounds afterwards. where Self: 'a, { // SAFETY: The trait implementation ensures that `ptr` always resides // within a [`Fence`] within a [`DriverFenceData`]. let driver_fence = unsafe { Self::from_raw(ptr.cast()) }; let driver_fence = ManuallyDrop::new(driver_fence); DriverFenceBorrow { driver_fence, _lifetime: PhantomData, } } } impl<'a, T: Send + Sync + FenceContextOps> Drop for DriverFence<'a, T> { fn drop(&mut self) { let guard = self.as_fence().lock(); // Use dma_fence_test_signaled_flag() instead of // dma_fence_is_signaled_locked() because the C backend wants to get rid // of the latter. // SAFETY: `guard` is valid until the `call_rcu()` below. let signaled: bool = unsafe { bindings::dma_fence_test_signaled_flag(guard.as_raw()) }; if !signaled { pr_err!("DriverFence drops unsignaled. Danger of memory corruption!\n"); // SAFETY: `guard` is valid until the `call_rcu()` below. The fence // must not have been signaled yet, which we check directly above. unsafe { bindings::dma_fence_set_error(guard.as_raw(), ECANCELED.to_errno()) }; // SAFETY: `guard` is valid until the `call_rcu()` below. The lock // must be held, which we acquired above. unsafe { bindings::dma_fence_signal_locked(guard.as_raw()) }; // SAFETY: `self.data` is valid because `self` is valid. let fctx = unsafe { self.data.as_ref().fctx }; let _ = fctx.nr_of_unsignaled_fences.fetch_sub(1, Relaxed); } drop(guard); // `DriverFenceData` could be accessed through some dma_fence // callbacks right now. Access is being revoked in principle above by // signaling the fence, but since the C backend does not guarantee // perfect full synchronization, we have to wait for one grace period to // ensure that all accessors of `DriverFenceData` (through the // dma_fence_ops accessible through a `Fence`) are gone. if !core::mem::needs_drop::() { // SAFETY: Once a `DriverFence` is initialized, the inner `fence` is // valid and initialized. It is valid until the refcount drops to 0, // which can earliest happen once we drop the `DriverFence`'s // reference here. unsafe { bindings::dma_fence_put(self.as_raw()) }; return; } // SAFETY: Valid because `self` is valid. let rcu_head_ptr = unsafe { &raw mut (*self.data.as_ptr()).rcu_head }; // SAFETY: `call_rcu()` is always safe to be called. `rcu_head_ptr` was // created validly above. The module must perform a `synchronize_rcu()` // or `rcu_barrier()` call to guard against module unload. unsafe { bindings::call_rcu(rcu_head_ptr, Some(drop_driver_fence_data::)) }; } } // TODO: // The entire call_rcu() mechanism in the drop above and the code below would be // unnecessary if C's dma_fence_signal() could be reworked in a way that after it // ran, the caller knows that no fence_ops callbacks can be running anymore. // In other words, if the dma_fence backend would use its spinlock for full // synchronization. // // Then we could move the drop_in_place() and dma_fence_put() upwards into the // drop() implementation and call it a day. /// Finally really drop this `DriverFence` /// /// # Safety /// /// `head` references the `rcu_head` field of an `DriverFenceData`. All /// accessors to that `DriverFenceData` must be gone by now. This must be /// ensured by signalling the associated `DriverFence` and then waiting /// for a grace period until calling this function here. unsafe extern "C" fn drop_driver_fence_data( head: *mut bindings::callback_head, ) { // SAFETY: Caller provides a pointer to the `rcu_head` field of a `DriverFenceData`. let fence_data = unsafe { container_of!(head, DriverFenceData<'_, T>, rcu_head) }; // SAFETY: `fence_data` was created validly above. All the fence's data will // only drop below, but the raw pointer to the raw C `dma_fence` remains // valid because the reference count is only decremented at the end of the // function. let fence = unsafe { (*fence_data).inner.inner.get() }; // SAFETY: `fence_data` was created validly above. The user has already // dropped the only conventional accessor to the user data, the `DriverFence`, // one grace period ago. All accessors are gone now. unsafe { drop_in_place(&raw mut (*fence_data).data) }; // The inner `Fence` explicitly does not get dropped because there may be // many more users / consumers, each holding their own reference. // SAFETY: Once a `DriverFence` is initialized, the inner `fence` is valid // and initialized. It is valid until the refcount drops to 0, which can // earliest happen once we drop the `DriverFence`'s reference here. unsafe { bindings::dma_fence_put(fence) }; // The actual memory the data associated with a `DriverFence` lives in // gets freed by the C dma_fence backend once the fence's refcount reaches 0. }