blob: 18a43e1bb442f6e00170296a267cb410c822d979 [file]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2025-2026 Red Hat Inc.
* Author: Philipp Stanner <pstanner@redhat.com>
*/
//! DMA Fence support.
//!
//! Reference: <https://docs.kernel.org/driver-api/dma-buf.html#c.dma_fence>
//!
//! 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<T: FenceContextOps + Send + Sync> {
/// The fence context number.
nr: u64,
/// The sequence number for the next fence created.
seqno: Atomic<u64>,
// 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<usize>,
/// The user's data.
#[pin]
data: T,
}
impl<'a, T: Send + Sync + FenceContextOps> FenceContext<T> {
// 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<E>(
initial_seqno: u64,
driver_name: &CStr,
timeline_name: &CStr,
data: impl PinInit<T, E>,
) -> impl PinInit<Self, Error>
where
Error: From<E>,
{
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<DriverFenceAllocation<'_, T>> {
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<T: FenceContextOps + Send + Sync> PinnedDrop for FenceContext<T> {
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<T> {
/// 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<T> From<CallbackError<T>> for Error {
#[inline]
fn from(err: CallbackError<T>) -> Self {
match err {
CallbackError::AlreadySignaled(_) => ENOENT,
CallbackError::Other(e) => e,
}
}
}
impl<T> From<AllocError> for CallbackError<T> {
#[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<T: FenceCallback + 'static> {
#[pin]
callback_foreign: Opaque<bindings::dma_fence_cb>,
callback: ManuallyDrop<T>,
fence: ARef<Fence>,
}
impl<T: FenceCallback> FenceCallbackRegistration<T> {
/// 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<Self, CallbackError<T>> + '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<T>)
}
/// 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<T: FenceCallback> PinnedDrop for FenceCallbackRegistration<T> {
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::<T>::drop(self.project().callback) };
}
}
// SAFETY: FenceCallbackRegistration can be sent between threads.
unsafe impl<T: FenceCallback> Send for FenceCallbackRegistration<T> {}
// SAFETY: &FenceCallbackRegistration can be shared between threads if &T can.
unsafe impl<T: FenceCallback> Sync for FenceCallbackRegistration<T> 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<bindings::dma_fence>,
}
/// 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<Self>) {
// 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<T>,
/// 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<Self> {
/// 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<DriverFenceData<'a, T>>,
}
/// 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<DriverFenceData<'a, T>>,
/// 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<DriverFence<'a, T>>,
_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<T: Send + Sync + FenceContextOps> 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::<bindings::dma_fence>();
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::<T::FenceDataType>() {
// 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::<T>)) };
}
}
// 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<T>`
///
/// # Safety
///
/// `head` references the `rcu_head` field of an `DriverFenceData<T>`. All
/// accessors to that `DriverFenceData<T>` must be gone by now. This must be
/// ensured by signalling the associated `DriverFence<T>` and then waiting
/// for a grace period until calling this function here.
unsafe extern "C" fn drop_driver_fence_data<T: Send + Sync + FenceContextOps>(
head: *mut bindings::callback_head,
) {
// SAFETY: Caller provides a pointer to the `rcu_head` field of a `DriverFenceData<C>`.
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.
}