NVIDIA GPU driver infrastructure
 help / color / mirror / Atom feed
From: "Gary Guo" <gary@garyguo.net>
To: "Danilo Krummrich" <dakr@kernel.org>, <abdiel.janulgue@gmail.com>,
	<daniel.almeida@collabora.com>, <robin.murphy@arm.com>,
	<a.hindborg@kernel.org>, <gregkh@linuxfoundation.org>,
	<rafael@kernel.org>, <aliceryhl@google.com>,
	<acourbot@nvidia.com>, <ojeda@kernel.org>, <boqun@kernel.org>,
	<gary@garyguo.net>, <bjorn3_gh@protonmail.com>,
	<lossin@kernel.org>, <tmgross@umich.edu>, <tamird@kernel.org>,
	<work@onurozkan.dev>, <mmaurer@google.com>
Cc: <driver-core@lists.linux.dev>, <nova-gpu@lists.linux.dev>,
	<dri-devel@lists.freedesktop.org>, <linux-kernel@vger.kernel.org>,
	<rust-for-linux@vger.kernel.org>
Subject: Re: [PATCH 1/4] rust: debugfs: drop 'static bound from ScopedDir file creation methods
Date: Thu, 03 Sep 2026 14:12:23 +0100	[thread overview]
Message-ID: <DL5PH2S8AP7E.25CW1PZIQ8BM3@garyguo.net> (raw)
In-Reply-To: <20260830193824.471089-2-dakr@kernel.org>

On Sun Aug 30, 2026 at 8:37 PM BST, Danilo Krummrich wrote:
> Drop the T: 'static bound from ScopedDir's file creation methods
> (read_binary_file(), read_only_file(), etc.) to support registering
> debugfs files backed by types that contain non-'static references, such
> as dma::Coherent<'a, T>.
>
> The previous 'static bound existed because ScopedDir::create_file() took
> &'static FileOps<T>, and &'static requires T: 'static for well-
> formedness. However, this was overly conservative; FileOps instances are
> always associated consts residing in static storage, so the pointer
> passed to the C debugfs API is always valid for the file's lifetime.
>
> Formalize this as a type invariant on FileOps. All instances reside in
> static storage, enforced by requiring FileOps::new() to only be used in
> const/static items. Replace the Deref impl with an explicit fops()
> method that returns &'static bindings::file_operations, justified by the
> type invariant.
>
> With this, ScopedDir::create_file() takes &FileOps<T> (no 'static),
> preserving the generic type safety (T links the fops to the data type)
> while allowing non-'static T.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/debugfs.rs          | 26 +++++------------
>  rust/kernel/debugfs/entry.rs    |  4 +--
>  rust/kernel/debugfs/file_ops.rs | 52 +++++++++++++++++++--------------
>  3 files changed, 39 insertions(+), 43 deletions(-)
>
> diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
> index d7b8014a6474..2beb55d444ca 100644
> --- a/rust/kernel/debugfs.rs
> +++ b/rust/kernel/debugfs.rs
> @@ -538,7 +538,7 @@ pub fn dir<'dir2>(&'dir2 self, name: &CStr) -> ScopedDir<'data, 'dir2> {
>          }
>      }
>  
> -    fn create_file<T: Sync>(&self, name: &CStr, data: &'data T, vtable: &'static FileOps<T>) {
> +    fn create_file<T: Sync>(&self, name: &CStr, data: &'data T, vtable: &FileOps<T>) {
>          #[cfg(CONFIG_DEBUG_FS)]
>          core::mem::forget(Entry::file(name, &self.entry, data, vtable));

With the signature change you're relying on static promotion to happen -- which
would still happen without a lifetime bound, but I find it somewhat
uncomfortable relying on that fact without a lifetime check.

>      }
> @@ -550,7 +550,7 @@ fn create_file<T: Sync>(&self, name: &CStr, data: &'data T, vtable: &'static Fil
>      /// This function does not produce an owning handle to the file. The created
>      /// file is removed when the [`Scope`] that this directory belongs
>      /// to is dropped.
> -    pub fn read_only_file<T: Writer + Send + Sync + 'static>(&self, name: &CStr, data: &'data T) {
> +    pub fn read_only_file<T: Writer + Send + Sync>(&self, name: &CStr, data: &'data T) {
>          self.create_file(name, data, &T::FILE_OPS)
>      }
>  
> @@ -560,11 +560,7 @@ pub fn read_only_file<T: Writer + Send + Sync + 'static>(&self, name: &CStr, dat
>      ///
>      /// This function does not produce an owning handle to the file. The created file is removed
>      /// when the [`Scope`] that this directory belongs to is dropped.
> -    pub fn read_binary_file<T: BinaryWriter + Send + Sync + 'static>(
> -        &self,
> -        name: &CStr,
> -        data: &'data T,
> -    ) {
> +    pub fn read_binary_file<T: BinaryWriter + Send + Sync>(&self, name: &CStr, data: &'data T) {
>          self.create_file(name, data, &T::FILE_OPS)
>      }
>  
> @@ -596,11 +592,7 @@ pub fn read_callback_file<T, F>(&self, name: &CStr, data: &'data T, _f: &'static
>      /// This function does not produce an owning handle to the file. The created
>      /// file is removed when the [`Scope`] that this directory belongs
>      /// to is dropped.
> -    pub fn read_write_file<T: Writer + Reader + Send + Sync + 'static>(
> -        &self,
> -        name: &CStr,
> -        data: &'data T,
> -    ) {
> +    pub fn read_write_file<T: Writer + Reader + Send + Sync>(&self, name: &CStr, data: &'data T) {
>          let vtable = &<T as ReadWriteFile<_>>::FILE_OPS;
>          self.create_file(name, data, vtable)
>      }
> @@ -612,7 +604,7 @@ pub fn read_write_file<T: Writer + Reader + Send + Sync + 'static>(
>      ///
>      /// This function does not produce an owning handle to the file. The created file is removed
>      /// when the [`Scope`] that this directory belongs to is dropped.
> -    pub fn read_write_binary_file<T: BinaryWriter + BinaryReader + Send + Sync + 'static>(
> +    pub fn read_write_binary_file<T: BinaryWriter + BinaryReader + Send + Sync>(
>          &self,
>          name: &CStr,
>          data: &'data T,
> @@ -655,7 +647,7 @@ pub fn read_write_callback_file<T, F, W>(
>      /// This function does not produce an owning handle to the file. The created
>      /// file is removed when the [`Scope`] that this directory belongs
>      /// to is dropped.
> -    pub fn write_only_file<T: Reader + Send + Sync + 'static>(&self, name: &CStr, data: &'data T) {
> +    pub fn write_only_file<T: Reader + Send + Sync>(&self, name: &CStr, data: &'data T) {
>          let vtable = &<T as WriteFile<_>>::FILE_OPS;
>          self.create_file(name, data, vtable)
>      }
> @@ -666,11 +658,7 @@ pub fn write_only_file<T: Reader + Send + Sync + 'static>(&self, name: &CStr, da
>      ///
>      /// This function does not produce an owning handle to the file. The created file is removed
>      /// when the [`Scope`] that this directory belongs to is dropped.
> -    pub fn write_binary_file<T: BinaryReader + Send + Sync + 'static>(
> -        &self,
> -        name: &CStr,
> -        data: &'data T,
> -    ) {
> +    pub fn write_binary_file<T: BinaryReader + Send + Sync>(&self, name: &CStr, data: &'data T) {
>          self.create_file(name, data, &T::FILE_OPS)
>      }
>  
> diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs
> index 46aad64896ec..88a870d8c295 100644
> --- a/rust/kernel/debugfs/entry.rs
> +++ b/rust/kernel/debugfs/entry.rs
> @@ -74,7 +74,7 @@ pub(crate) unsafe fn dynamic_file<T>(
>                  parent.as_ptr(),
>                  core::ptr::from_ref(data) as *mut c_void,
>                  core::ptr::null(),
> -                &**file_ops,
> +                file_ops.fops(),
>              )
>          };
>  
> @@ -127,7 +127,7 @@ pub(crate) fn file<T>(
>                  parent.as_ptr(),
>                  core::ptr::from_ref(data) as *mut c_void,
>                  core::ptr::null(),
> -                &**file_ops,
> +                file_ops.fops(),
>              )
>          };
>  
> diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs
> index f15908f71c4a..7e1dd8c75ad9 100644
> --- a/rust/kernel/debugfs/file_ops.rs
> +++ b/rust/kernel/debugfs/file_ops.rs
> @@ -20,14 +20,12 @@
>  
>  use core::marker::PhantomData;
>  
> -#[cfg(CONFIG_DEBUG_FS)]
> -use core::ops::Deref;
> -
> -/// # Invariant
> +/// # Invariants
>  ///
> -/// `FileOps<T>` will always contain an `operations` which is safe to use for a file backed
> -/// off an inode which has a pointer to a `T` in its private data that is safe to convert
> -/// into a reference.
> +/// - `FileOps<T>` will always contain an `operations` which is safe to use for a file backed
> +///   off an inode which has a pointer to a `T` in its private data that is safe to convert
> +///   into a reference.
> +/// - Every instance of `FileOps<T>` resides in static storage.

This can be better done by storing `&'static bindings::file_operations` in
`FileOps<T>` instead of just by value. That is actually better than the current
impl, IMO, because `mode` for example doesn't have to be in static storage. (You
can also then make `FileOps<T>` `Copy`).

If you made the change, you'd still have `&'static` checked at compile time, and
the fops below can be safe.

Best,
Gary

>  pub(super) struct FileOps<T> {
>      #[cfg(CONFIG_DEBUG_FS)]
>      operations: bindings::file_operations,
> @@ -39,9 +37,13 @@ pub(super) struct FileOps<T> {
>  impl<T> FileOps<T> {
>      /// # Safety
>      ///
> -    /// The caller asserts that the provided `operations` is safe to use for a file whose
> -    /// inode has a pointer to `T` in its private data that is safe to convert into a reference.
> +    /// - The caller asserts that the provided `operations` is safe to use for a file whose
> +    ///   inode has a pointer to `T` in its private data that is safe to convert into a reference.
> +    /// - Must only be used to initialize a `const` or `static` item, to uphold the type invariant
> +    ///   that all `FileOps` instances reside in static storage.
>      const unsafe fn new(operations: bindings::file_operations, mode: u16) -> Self {
> +        // INVARIANT: The caller is required to only use this in a `const` or `static` item,
> +        // ensuring that all `FileOps` instances reside in static storage.
>          Self {
>              #[cfg(CONFIG_DEBUG_FS)]
>              operations,
> @@ -65,11 +67,11 @@ pub(super) const fn adapt(&self) -> &FileOps<T::Inner> {
>  }
>  
>  #[cfg(CONFIG_DEBUG_FS)]
> -impl<T> Deref for FileOps<T> {
> -    type Target = bindings::file_operations;
> -
> -    fn deref(&self) -> &Self::Target {
> -        &self.operations
> +impl<T> FileOps<T> {
> +    /// Returns a `'static` reference to the inner `file_operations`.
> +    pub(crate) fn fops(&self) -> &'static bindings::file_operations {
> +        // SAFETY: By the type invariant, `self` resides in static storage.
> +        unsafe { core::mem::transmute(&self.operations) }
>      }
>  }
>  


  reply	other threads:[~2026-09-03 13:12 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-30 19:37 [PATCH 0/4] rust: dma: tie DMA allocations to the device's bound lifetime Danilo Krummrich
2026-08-30 19:37 ` [PATCH 1/4] rust: debugfs: drop 'static bound from ScopedDir file creation methods Danilo Krummrich
2026-09-03 13:12   ` Gary Guo [this message]
2026-09-03 15:07     ` Danilo Krummrich
2026-09-03 15:16       ` Gary Guo
2026-08-30 19:37 ` [PATCH 2/4] rust: dma: tie CoherentHandle to the device's bound lifetime Danilo Krummrich
2026-09-03 13:12   ` Gary Guo
2026-08-30 19:37 ` [PATCH 3/4] samples: rust_dma: separate driver type from driver data Danilo Krummrich
2026-09-03 13:13   ` Gary Guo
2026-08-30 19:37 ` [PATCH 4/4] rust: dma: tie Coherent and CoherentBox to the device's bound lifetime Danilo Krummrich
2026-09-03 13:20   ` Gary Guo
2026-09-03 15:22     ` Danilo Krummrich
2026-09-03 15:42       ` Gary Guo

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=DL5PH2S8AP7E.25CW1PZIQ8BM3@garyguo.net \
    --to=gary@garyguo.net \
    --cc=a.hindborg@kernel.org \
    --cc=abdiel.janulgue@gmail.com \
    --cc=acourbot@nvidia.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=driver-core@lists.linux.dev \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=mmaurer@google.com \
    --cc=nova-gpu@lists.linux.dev \
    --cc=ojeda@kernel.org \
    --cc=rafael@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tamird@kernel.org \
    --cc=tmgross@umich.edu \
    --cc=work@onurozkan.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox