On Fri, 2026-07-03 at 09:31 +0200, Philipp Stanner wrote:
>
> +// 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 + FenceCtxOps> {
> + #[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 FenceCtx. Useful for obtaining name
> parameters.
> + fctx: &'a FenceCtx<T>,
> + /// The API user's data. This must either not need drop, or must delay
> its
> + /// drop by a grace period. It is essential that the data only performs
> + /// operations legal in atomic context in its [`Drop`] implementation.
> + #[pin]
> + data: T::FenceDataType,
> +}
> +
> +pub struct DriverFence<'a, T: Send + Sync + FenceCtxOps> {
> + /// The actual content of the fence. Lives in a raw pointer 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 + FenceCtxOps> {
> + /// 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>>,
> +}
One issue that I'm only discovering just now is that the request of
deriving the DriverFence's generic through the FenceCtx's generic
causes issues like this:
struct DriverFoo {
f: DriverFence<()>, // error: must implement FenceCtxOps
}
IOW, all DriverFence::data now must implement the trait. Which is
obviously not what we want.
But I cannot get easily get rid of it. See DriverFenceData.
@Boris: Do you have a suggestion? Otherwise I'd want to default back to
PhantomData, which I still believe is cleaner.
P.