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.

Reply via email to