All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Onur Özkan" <work@onurozkan.dev>
To: Philipp Stanner <phasta@kernel.org>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Sumit Semwal" <sumit.semwal@linaro.org>,
	"Christian König" <christian.koenig@amd.com>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Asahi Lina" <lina+kernel@asahilina.net>,
	"Burak Emir" <bqe@google.com>, "Lorenzo Stoakes" <ljs@kernel.org>,
	"Joel Fernandes" <joelagnelf@nvidia.com>,
	"Alexandre Courbot" <acourbot@nvidia.com>,
	"Krishna Ketan Rai" <prafulrai522@gmail.com>,
	"Tamir Duberstein" <tamird@kernel.org>,
	"Mirko Adzic" <adzicmirko97@gmail.com>,
	"Alistair Francis" <alistair.francis@wdc.com>,
	"Shankari Anand" <shankari.ak0208@gmail.com>,
	linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linaro-mm-sig@lists.linaro.org
Subject: Re: [PATCH v5 4/5] rust: Add dma_fence abstractions
Date: Wed, 15 Jul 2026 23:00:34 +0300	[thread overview]
Message-ID: <20260715200036.46182-1-work@onurozkan.dev> (raw)
In-Reply-To: <20260703073141.3962604-6-phasta@kernel.org>

On Fri, 03 Jul 2026 09:31:40 +0200
Philipp Stanner <phasta@kernel.org> wrote:

> C's dma_fence's are synchronisation primitives that will be needed by all
> Rust GPU drivers.
> 
> The dma_fence framework sets a number of rules, notably:
>   - fences must only be signalled once
>   - all fences must be signalled at some point
>   - fence error codes must only be set before signalling
>   - every pointer to a fence must be backed by a reference
> 
> All those rules are being addressed by these abstractions.
> 
> To cleanly decouple fence issuers and consumers, two types are provided:
>   - DriverFence: the only fence type that can be signalled and that
>     carries driver-specific data.
>   - Fence: the fence type to be shared with other drivers and / or
>     userspace. The only type callbacks can be registered on.
>     Cannot be signalled.
> 
> Hereby, a Fence lives in the same chunk of memory as a DriverFence. Both
> share the refcount of the underlying C dma_fence. Since this
> implementation does not provide a custom dma_fence_backend_ops.release()
> function, the memory is freed by the dma_fence backend once the refcount
> drops to 0.
> 
> To create a DriverFence, the user must first allocate a
> DriverFenceAllocation, so that the creation of the DriverFence later on
> can always succeed. Otherwise, deadlocks could occur if fences need to
> be created in a GPU job submission path.
> 
> Synchronization is ensured by the dma_fence backend.
> 
> All DriverFence's created through this abstraction must be signalled by
> the creator with an error code. In case a DriverFence drops without
> being signalled beforehand, it is signalled with -ECANCELLED as its
> error and a warning is printed. This allows the Rust abstraction to very
> cleanly decouple fence issuer and consumer by relying on the decoupling
> mechanisms in the C backend, which ensures through RCU and the
> 'signalled' fence-flag that dma_fence_backend_ops functions cannot
> access the potentially unloaded driver code anymore.
> 
> Signalling fences on drop thus grants many advantages. Not signalling
> fences on drop would risk deadlock and does not grant real advantages:
> By definition only the drivers can ensure that a fence always represents
> the hardware's state correctly.
> 
> This implementation models a DmaFenceCtx (fence context) object on which
> fences are to be created, thereby ensuring correct sequence numbering
> according to the timeline.
> 
> dma_fence supports a variety of callbacks. The mandatory callbacks
> (get_timeline_name() and get_driver_name()) are implemented in this
> patch. For convenience, they store those name parameters in the fence
> context, saving the driver from implementing these two callbacks.
> 
> Support for other callbacks (like for hardware signalling) is prepared
> for through the fact that both DriverFence and Fence live in the same
> allocation, allowing for usage of container_of from the callback to
> access the driver-specific data.
> 
> Synchronization for backend_ops callbacks is ensured by only running the
> Rust deconstructor delayed with call_rcu(), which prevents UAF-bugs
> should a DriverFence drop while a Fence callback is currently operating
> on the associated driver data.
> 
> Add abstractions for dma_fence in Rust.
> 
> Signed-off-by: Philipp Stanner <phasta@kernel.org>
> ---
>  rust/bindings/bindings_helper.h  |   1 +
>  rust/helpers/dma_fence.c         |  48 ++
>  rust/helpers/helpers.c           |   1 +
>  rust/kernel/dma_buf/dma_fence.rs | 894 +++++++++++++++++++++++++++++++
>  rust/kernel/dma_buf/mod.rs       |  14 +
>  rust/kernel/lib.rs               |   1 +
>  6 files changed, 959 insertions(+)
>  create mode 100644 rust/helpers/dma_fence.c
>  create mode 100644 rust/kernel/dma_buf/dma_fence.rs
>  create mode 100644 rust/kernel/dma_buf/mod.rs
> 
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 1124785e210b..54b62d952e01 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -53,6 +53,7 @@
>  #include <linux/debugfs.h>
>  #include <linux/device/faux.h>
>  #include <linux/dma-direction.h>
> +#include <linux/dma-fence.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/dma-resv.h>
>  #include <linux/errname.h>
> diff --git a/rust/helpers/dma_fence.c b/rust/helpers/dma_fence.c
> new file mode 100644
> index 000000000000..0e08411098fa
> --- /dev/null
> +++ b/rust/helpers/dma_fence.c
> @@ -0,0 +1,48 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/dma-fence.h>
> +
> +__rust_helper void rust_helper_dma_fence_get(struct dma_fence *f)
> +{
> +	dma_fence_get(f);
> +}
> +
> +__rust_helper void rust_helper_dma_fence_put(struct dma_fence *f)
> +{
> +	dma_fence_put(f);
> +}
> +
> +__rust_helper bool rust_helper_dma_fence_begin_signalling(void)
> +{
> +	return dma_fence_begin_signalling();
> +}
> +
> +__rust_helper void rust_helper_dma_fence_end_signalling(bool cookie)
> +{
> +	dma_fence_end_signalling(cookie);
> +}
> +
> +__rust_helper bool rust_helper_dma_fence_is_signaled(struct dma_fence *f)
> +{
> +	return dma_fence_is_signaled(f);
> +}
> +
> +__rust_helper bool rust_helper_dma_fence_test_signaled_flag(struct dma_fence *f)
> +{
> +	return dma_fence_test_signaled_flag(f);
> +}
> +
> +__rust_helper void rust_helper_dma_fence_lock_irqsave(struct dma_fence *f, unsigned long *flags)
> +{
> +	dma_fence_lock_irqsave(f, *flags);
> +}
> +
> +__rust_helper void rust_helper_dma_fence_unlock_irqrestore(struct dma_fence *f, unsigned long *flags)
> +{
> +	dma_fence_unlock_irqrestore(f, *flags);
> +}
> +
> +__rust_helper void rust_helper_dma_fence_set_error(struct dma_fence *f, int error)
> +{
> +	dma_fence_set_error(f, error);
> +}
> diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
> index 998e31052e66..4ab8aa9da7e7 100644
> --- a/rust/helpers/helpers.c
> +++ b/rust/helpers/helpers.c
> @@ -58,6 +58,7 @@
>  #include "cred.c"
>  #include "device.c"
>  #include "dma.c"
> +#include "dma_fence.c"
>  #include "dma-resv.c"
>  #include "drm.c"
>  #include "drm_gpuvm.c"
> diff --git a/rust/kernel/dma_buf/dma_fence.rs b/rust/kernel/dma_buf/dma_fence.rs
> new file mode 100644
> index 000000000000..cbe8f447a603
> --- /dev/null
> +++ b/rust/kernel/dma_buf/dma_fence.rs
> @@ -0,0 +1,894 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (T) 2025, 2026 Red Hat Inc.:
> +//   - Philipp Stanner <pstanner@redhat.com>
> +
> +//! DriverFence support.
> +//!
> +//! Reference: <https://docs.kernel.org/driver-api/dma-buf.html#c.dma_fence>
> +//!
> +//! T 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,
> +    warn_on, //
> +};
> +
> +use core::{
> +    marker::PhantomData,
> +    mem::ManuallyDrop,
> +    ops::Deref,
> +    ptr,
> +    ptr::{
> +        drop_in_place,
> +        NonNull, //
> +    },
> +    sync::atomic::{
> +        AtomicU64,
> +        Ordering, //
> +    }, //
> +};
> +
> +use kernel::{
> +    str::CString,
> +    sync::{
> +        aref::{
> +            ARef,
> +            AlwaysRefCounted, //
> +        },
> +        rcu::rcu_barrier, //
> +    }, //
> +};
> +
> +/// VTable for dma_fence backend_ops callbacks.
> +//
> +// Mandatory dma_fence backend_ops are implemented implicitly through
> +// [`FenceCtx`]. Additional ones shall get implemented on this trait, which then
> +// shall be demanded for the fence context data.
> +pub trait FenceCtxOps {
> +    /// 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 FenceCtx<T: Send + Sync> {
> +    /// The fence context number.
> +    nr: u64,
> +    /// The sequence number for the next fence created.
> +    seqno: AtomicU64,
> +    // 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 FenceCtx's fences belong to.
> +    driver_name: CString,
> +    /// The name of the timeline this FenceCtx's fences belong to.
> +    timeline_name: CString,
> +    /// The user's data.
> +    #[pin]
> +    data: T,
> +}
> +
> +#[allow(unused_unsafe)]

Why is this needed?

> +impl<'a, T: Send + Sync + FenceCtxOps> FenceCtx<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,
> +        wait: None,
> +        release: None,
> +        set_deadline: None,
> +    };
> +
> +    /// Create a new `FenceCtx`.
> +    pub fn new<E>(
> +        driver_name: CString,
> +        timeline_name: CString,
> +        data: impl PinInit<T, E>,
> +    ) -> impl PinInit<Self, Error>
> +    where

[...]

> +    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.
> +}
> diff --git a/rust/kernel/dma_buf/mod.rs b/rust/kernel/dma_buf/mod.rs
> new file mode 100644
> index 000000000000..fb353ce042ce
> --- /dev/null
> +++ b/rust/kernel/dma_buf/mod.rs
> @@ -0,0 +1,14 @@
> +// SPDX-License-Identifier: GPL-2.0 OR MIT
> +
> +//! DMA-buf subsystem abstractions.
> +
> +pub mod dma_fence;
> +
> +pub use self::dma_fence::{
> +    DriverFence,
> +    Fence,
> +    FenceCb,
> +    FenceCbRegistration,
> +    FenceCtx,
> +    FenceCtxOps, //
> +};
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 9512af7156df..dc54d8af471f 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -64,6 +64,7 @@
>  pub mod device_id;
>  pub mod devres;
>  pub mod dma;
> +pub mod dma_buf;
>  pub mod driver;
>  #[cfg(CONFIG_DRM = "y")]
>  pub mod drm;
> -- 
> 2.54.0
> 

  parent reply	other threads:[~2026-07-15 20:00 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-03  7:31 [PATCH v5 0/5] rust / dma_buf: Add abstractions for dma_fence Philipp Stanner
2026-07-03  7:31 ` [PATCH v5 1/5] rust: types: implement ForeignOwnable for ARef<T> Philipp Stanner
2026-07-03  7:42   ` sashiko-bot
2026-07-03  7:31 ` [PATCH v5 2/5] rust: error: Add ECANCELED error code Philipp Stanner
2026-07-15 20:03   ` Onur Özkan
2026-07-03  7:31 ` [PATCH v5 3/5] rust: sync: Add abstraction for rcu_barrier() Philipp Stanner
2026-07-03  7:40   ` sashiko-bot
2026-07-15 20:01   ` Onur Özkan
2026-07-03  7:31 ` [PATCH v5 4/5] rust: Add dma_fence abstractions Philipp Stanner
2026-07-03  7:45   ` sashiko-bot
2026-07-08 13:29   ` Philipp Stanner
2026-07-15 18:57   ` Daniel Almeida
2026-07-15 20:00   ` Onur Özkan [this message]
2026-07-03  7:31 ` [PATCH v5 5/5] MAINTAINERS: Add entry for Rust dma-buf Philipp Stanner
2026-07-06 13:07 ` [PATCH v5 0/5] rust / dma_buf: Add abstractions for dma_fence Daniel Almeida

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260715200036.46182-1-work@onurozkan.dev \
    --to=work@onurozkan.dev \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=adzicmirko97@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=alistair.francis@wdc.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=bqe@google.com \
    --cc=christian.koenig@amd.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=joelagnelf@nvidia.com \
    --cc=lina+kernel@asahilina.net \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=ljs@kernel.org \
    --cc=lossin@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=phasta@kernel.org \
    --cc=prafulrai522@gmail.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=shankari.ak0208@gmail.com \
    --cc=sumit.semwal@linaro.org \
    --cc=tamird@kernel.org \
    --cc=tmgross@umich.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.