All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] drm/tyr: add debugfs support
@ 2026-07-30 17:05 Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 1/9] rust: seq_file: add as_raw() method Alvin Sun
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add debugfs support for the Tyr DRM driver.

The series adds a SeqShow trait for seq_file-backed debugfs files with
lifecycle hooks, a DrmSeqShow adapter with DRM device lifecycle
management, and a gpuvas debugfs file in Tyr exposing GPU VA space
information.

Additionally, fix a use-after-free in the DRM debugfs open/release
paths where a device could be unregistered while a debugfs file remains
open.

This is based on drm-rust-next and depends on:

[PATCH v10 0/7] drm/tyr: firmware loading and MCU boot support
  https://lore.kernel.org/r/20260728-fw-boot-b4-v10-0-9187aefa3f2f@collabora.com

See the full dependency and commit history at [1].

Link: https://gitlab.freedesktop.org/panfrost/linux/-/issues/11
Link: https://gitlab.freedesktop.org/panfrost/linux/-/merge_requests/59 [1]
Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
Changes in v2:
- Reworked the debugfs implementation per feedback from Danilo on v1:
  dropped the hazptr/revocable-based approach in favor of the DRM
  debugfs_init callback and generic seq_file abstractions.
- Fixed a UAF in drm_debugfs where a device could be unregistered while
  a debugfs file remains open (drm_dev_get/put across file lifetime).
- Link to v1: https://lore.kernel.org/r/20260326-b4-tyr-debugfs-v1-0-074badd18716@linux.dev

---
Alvin Sun (9):
      rust: seq_file: add as_raw() method
      rust: debugfs: add SeqShow trait and seq_file file operations
      rust: debugfs: add Entry::from_raw and ScopedDir::from_dentry
      drm: move debugfs_init after dev->registered is set
      rust: drm: add debugfs_init callback to Driver trait
      rust: drm: add DrmSeqShow seq_file adapter
      rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm
      drm/tyr: add gpuvas debugfs file
      drm/debugfs: hold device reference for the lifetime of open files

 drivers/gpu/drm/drm_debugfs.c   | 45 ++++++++++++++++---
 drivers/gpu/drm/drm_drv.c       |  5 +++
 drivers/gpu/drm/tyr/debugfs.rs  | 65 +++++++++++++++++++++++++++
 drivers/gpu/drm/tyr/driver.rs   | 16 +++++++
 drivers/gpu/drm/tyr/fw.rs       |  8 ++++
 drivers/gpu/drm/tyr/tyr.rs      |  1 +
 drivers/gpu/drm/tyr/vm.rs       |  5 +++
 rust/bindings/bindings_helper.h |  1 +
 rust/kernel/debugfs.rs          | 35 ++++++++++++++-
 rust/kernel/debugfs/entry.rs    | 15 ++++++-
 rust/kernel/debugfs/file_ops.rs | 97 +++++++++++++++++++++++++++++++++++++++++
 rust/kernel/debugfs/traits.rs   | 30 ++++++++++++-
 rust/kernel/drm/debugfs.rs      | 49 +++++++++++++++++++++
 rust/kernel/drm/device.rs       | 36 ++++++++++++++-
 rust/kernel/drm/driver.rs       | 11 +++++
 rust/kernel/drm/gpuvm/mod.rs    |  8 ++++
 rust/kernel/drm/mod.rs          |  1 +
 rust/kernel/seq_file.rs         |  6 +++
 18 files changed, 422 insertions(+), 12 deletions(-)
---
base-commit: 0ffc014cb2abfc79d161662b125e085b3e7107e7
change-id: 20260730-tyr-debugfs-v2-608cef77d6e9

Best regards,
-- 
Alvin Sun <alvin.sun@linux.dev>



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/9] rust: seq_file: add as_raw() method
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 2/9] rust: debugfs: add SeqShow trait and seq_file file operations Alvin Sun
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add a method to obtain a raw pointer to the underlying struct
seq_file, needed for FFI calls into C (e.g. drm_debugfs_gpuva_info).

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/seq_file.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs
index 518265558d66f..fbc75e0e77634 100644
--- a/rust/kernel/seq_file.rs
+++ b/rust/kernel/seq_file.rs
@@ -29,6 +29,12 @@ pub unsafe fn from_raw<'a>(ptr: *mut bindings::seq_file) -> &'a SeqFile {
         unsafe { &*ptr.cast() }
     }
 
+    /// Returns a raw pointer to the underlying `struct seq_file`.
+    #[inline]
+    pub fn as_raw(&self) -> *mut bindings::seq_file {
+        self.inner.get()
+    }
+
     /// Used by the [`seq_print`] macro.
     #[inline]
     pub fn call_printf(&self, args: fmt::Arguments<'_>) {

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/9] rust: debugfs: add SeqShow trait and seq_file file operations
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 1/9] rust: seq_file: add as_raw() method Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 3/9] rust: debugfs: add Entry::from_raw and ScopedDir::from_dentry Alvin Sun
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add SeqShow trait for seq_file-backed debugfs files with optional
open/release lifecycle hooks. Needed by DRM and other subsystems to
expose readable debugfs state via seq_file.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/debugfs.rs          | 16 ++++++-
 rust/kernel/debugfs/file_ops.rs | 97 +++++++++++++++++++++++++++++++++++++++++
 rust/kernel/debugfs/traits.rs   | 30 ++++++++++++-
 3 files changed, 141 insertions(+), 2 deletions(-)

diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index d7b8014a64746..dea0e2c953039 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -24,7 +24,7 @@
         PhantomData,
         PhantomPinned, //
     },
-    ops::Deref,
+    ops::Deref, //
 };
 
 mod traits;
@@ -33,6 +33,7 @@
     BinaryReaderMut,
     BinaryWriter,
     Reader,
+    SeqShow,
     Writer, //
 };
 
@@ -51,6 +52,7 @@
     FileOps,
     ReadFile,
     ReadWriteFile,
+    SeqReadFile,
     WriteFile, //
 };
 
@@ -588,6 +590,18 @@ pub fn read_callback_file<T, F>(&self, name: &CStr, data: &'data T, _f: &'static
         self.create_file(name, data, vtable)
     }
 
+    /// Creates a seq_file debugfs file in this directory.
+    ///
+    /// The file's contents are produced by invoking [`SeqShow::show`] with
+    /// `data` on each read.
+    ///
+    /// 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 seq_file<S: SeqShow<U>, U: Sync + 'static>(&self, name: &CStr, data: &'data U) {
+        self.create_file(name, data, &<S as SeqReadFile<U>>::FILE_OPS)
+    }
+
     /// Creates a read-write file in this directory.
     ///
     /// Reading the file uses the [`Writer`] implementation on `data`. Writing to the file uses
diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs
index f15908f71c4a2..20a4362785a44 100644
--- a/rust/kernel/debugfs/file_ops.rs
+++ b/rust/kernel/debugfs/file_ops.rs
@@ -5,11 +5,13 @@
     BinaryReader,
     BinaryWriter,
     Reader,
+    SeqShow,
     Writer, //
 };
 
 use crate::{
     debugfs::callback_adapters::Adapter,
+    error::from_result,
     fmt,
     fs::file,
     prelude::*,
@@ -19,6 +21,7 @@
 };
 
 use core::marker::PhantomData;
+use core::ptr::NonNull;
 
 #[cfg(CONFIG_DEBUG_FS)]
 use core::ops::Deref;
@@ -123,6 +126,100 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     0
 }
 
+/// Show callback for `SeqShow` types.
+///
+/// # Safety
+///
+/// The seq_file core guarantees that `seq` points to a live `seq_file` and that
+/// `seq->private` is a valid pointer to a `T` with no outstanding mutable
+/// references.
+unsafe extern "C" fn seq_file_show<S: SeqShow<T>, T: Sync>(
+    seq: *mut bindings::seq_file,
+    _: *mut crate::ffi::c_void,
+) -> crate::ffi::c_int {
+    // SAFETY: `seq->private` is a valid `T` pointer with no outstanding
+    // mutable references.
+    let data = unsafe { &*((*seq).private.cast::<T>()) };
+    // SAFETY: `seq` points to a live `seq_file`.
+    let m = unsafe { SeqFile::from_raw(seq) };
+    from_result(|| S::show(data, m).map(|()| 0))
+}
+
+/// Open callback for `SeqShow` types.
+///
+/// # Safety
+///
+/// The VFS guarantees that `inode` is valid with `i_private` pointing to a
+/// valid `T` that remains valid for the duration of the call, and that `file`
+/// points to a live, uninitialized file object.
+unsafe extern "C" fn seq_file_open<S: SeqShow<T>, T: Sync>(
+    inode: *mut bindings::inode,
+    file: *mut bindings::file,
+) -> crate::ffi::c_int {
+    // SAFETY: `inode` is valid per VFS. `i_private` points to a valid `T`
+    // (guaranteed by the `FileOps<T>` invariants).
+    let data = unsafe { (*inode).i_private.cast::<T>() };
+    // SAFETY: `data` is a valid `T` pointer from `i_private` per the `FileOps` invariants.
+    let data_ref = unsafe { &*data };
+
+    if let Err(e) = S::open(data_ref) {
+        return e.to_errno();
+    }
+
+    // SAFETY: `file` is valid per VFS; `data` matches `seq_file_show`'s contract.
+    let ret = unsafe { bindings::single_open(file, Some(seq_file_show::<S, T>), data.cast()) };
+    if ret != 0 {
+        // SAFETY: Since `S::open` has already succeeded, `data` is valid. `data` came from
+        // `i_private` (a `&T` reference), so it is non-null.
+        unsafe { S::release(NonNull::new_unchecked(data)) };
+    }
+    ret
+}
+
+/// Release callback for `SeqShow` types.
+///
+/// # Safety
+///
+/// The VFS guarantees that `file` is valid, and that `private_data` points to
+/// a live `seq_file` whose `private` field is a valid pointer to `T`.
+unsafe extern "C" fn seq_file_release<S: SeqShow<T>, T: Sync>(
+    inode: *mut bindings::inode,
+    file: *mut bindings::file,
+) -> crate::ffi::c_int {
+    // SAFETY: `file->private_data` is the seq_file from `single_open`.
+    let seq = unsafe { (*file).private_data.cast::<bindings::seq_file>() };
+
+    // SAFETY: `seq->private` was set by `single_open` to the `i_private` value.
+    let data = unsafe { (*seq).private };
+
+    // SAFETY: `data` came from `i_private` (a `&T` reference), so it is
+    // non-null.
+    unsafe { S::release(NonNull::new_unchecked(data.cast::<T>())) };
+
+    // SAFETY: `inode` and `file` are valid per VFS.
+    unsafe { bindings::single_release(inode, file) }
+}
+
+pub(crate) trait SeqReadFile<T> {
+    const FILE_OPS: FileOps<T>;
+}
+
+impl<S: SeqShow<T>, T: Sync + 'static> SeqReadFile<T> for S {
+    const FILE_OPS: FileOps<T> = {
+        let operations = bindings::file_operations {
+            read: Some(bindings::seq_read),
+            llseek: Some(bindings::seq_lseek),
+            release: Some(seq_file_release::<Self, T>),
+            open: Some(seq_file_open::<Self, T>),
+            ..pin_init::zeroed()
+        };
+        // SAFETY: `read` and `llseek` are stock `seq_file` implementations.
+        // `seq_file_open` and `seq_file_release` treat `inode->i_private` as a
+        // valid `&T` reference, satisfying the `FileOps::new` contract.
+        unsafe { FileOps::new(operations, 0o400) }
+    };
+}
+
 // Work around lack of generic const items.
 pub(crate) trait ReadFile<T> {
     const FILE_OPS: FileOps<T>;
diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs
index 8c39524b6a990..4cbdfdf511a88 100644
--- a/rust/kernel/debugfs/traits.rs
+++ b/rust/kernel/debugfs/traits.rs
@@ -8,6 +8,7 @@
     fmt,
     fs::file,
     prelude::*,
+    seq_file::SeqFile,
     sync::{
         atomic::{
             Atomic,
@@ -33,7 +34,8 @@
         Deref,
         DerefMut, //
     },
-    str::FromStr,
+    ptr::NonNull,
+    str::FromStr, //
 };
 
 /// A trait for types that can be written into a string.
@@ -338,3 +340,29 @@ fn read_from_slice(
         self.deref().read_from_slice(reader, offset)
     }
 }
+
+/// Renders `data` into a seq_file.
+///
+/// `data` is the value stashed as the debugfs file's `i_private` at creation
+/// time. `show` is invoked on each read to produce the file's contents.
+///
+/// `open` and `release` are optional lifecycle hooks called during file open
+/// and release. They can be used to manage the lifetime of `data` (e.g.,
+/// reference counting). Default implementations are no-ops.
+pub trait SeqShow<T> {
+    /// Writes debugfs output for the file.
+    fn show(data: &T, m: &SeqFile) -> Result;
+
+    /// Called during file open, before `single_open`.
+    fn open(_data: &T) -> Result {
+        Ok(())
+    }
+
+    /// Called during file release, before `single_release`.
+    ///
+    /// # Safety
+    ///
+    /// `data` must point to valid memory, kept alive by actions taken in
+    /// [`Self::open`] (e.g., incrementing a reference count).
+    unsafe fn release(_data: NonNull<T>) {}
+}

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/9] rust: debugfs: add Entry::from_raw and ScopedDir::from_dentry
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 1/9] rust: seq_file: add as_raw() method Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 2/9] rust: debugfs: add SeqShow trait and seq_file file operations Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 4/9] drm: move debugfs_init after dev->registered is set Alvin Sun
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add methods to construct debugfs abstractions from raw C dentry
pointers. Needed by DRM debugfs_init callback to create ScopedDir
from the root dentry provided by C core.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/debugfs.rs       | 19 +++++++++++++++++++
 rust/kernel/debugfs/entry.rs | 15 ++++++++++++++-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index dea0e2c953039..0f521762352ad 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -735,4 +735,23 @@ fn new(name: &CStr) -> ScopedDir<'data, 'static> {
             _phantom: PhantomData,
         }
     }
+
+    /// Creates a [`ScopedDir`] wrapping an existing debugfs dentry.
+    ///
+    /// Files created under this directory are not automatically removed on drop;
+    /// their lifetime is tied to the dentry owner.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure the dentry remains valid for the lifetime of the
+    /// returned `ScopedDir`.
+    pub unsafe fn from_dentry(dentry: *mut bindings::dentry) -> Self {
+        let _ = dentry;
+        ScopedDir {
+            #[cfg(CONFIG_DEBUG_FS)]
+            // SAFETY: The caller guarantees the dentry is valid and outlives this `ScopedDir`.
+            entry: ManuallyDrop::new(unsafe { Entry::from_raw(dentry) }),
+            _phantom: PhantomData,
+        }
+    }
 }
diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs
index 46aad64896ecb..7643ff0fa6093 100644
--- a/rust/kernel/debugfs/entry.rs
+++ b/rust/kernel/debugfs/entry.rs
@@ -8,7 +8,7 @@
         CStr,
         CStrExt as _, //
     },
-    sync::Arc,
+    sync::Arc, //
 };
 
 use core::marker::PhantomData;
@@ -87,6 +87,19 @@ pub(crate) unsafe fn dynamic_file<T>(
 }
 
 impl<'a> Entry<'a> {
+    /// Wraps a raw dentry pointer.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure the dentry is valid and outlives this `Entry`.
+    pub(crate) unsafe fn from_raw(entry: *mut bindings::dentry) -> Self {
+        Self {
+            entry,
+            _parent: None,
+            _phantom: PhantomData,
+        }
+    }
+
     pub(crate) fn dir(name: &CStr, parent: Option<&'a Entry<'_>>) -> Self {
         let parent_ptr = match &parent {
             Some(entry) => entry.as_ptr(),

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 4/9] drm: move debugfs_init after dev->registered is set
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
                   ` (2 preceding siblings ...)
  2026-07-30 17:05 ` [PATCH v2 3/9] rust: debugfs: add Entry::from_raw and ScopedDir::from_dentry Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 5/9] rust: drm: add debugfs_init callback to Driver trait Alvin Sun
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

The debugfs_init callback was invoked by drm_debugfs_register before
dev->registered is set to true. Moving it to drm_dev_register after
dev->registered = true fixes the Ioctl type invariant violation.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 drivers/gpu/drm/drm_debugfs.c | 3 ---
 drivers/gpu/drm/drm_drv.c     | 5 +++++
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index ae1c6126c2c59..38cf6ce387cc8 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -442,9 +442,6 @@ int drm_debugfs_register(struct drm_minor *minor, int minor_id)
 	/* TODO: Only for compatibility with drivers */
 	minor->debugfs_root = dev->debugfs_root;
 
-	if (dev->driver->debugfs_init && dev->render != minor)
-		dev->driver->debugfs_init(minor);
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index e890052061f30..15669764fe625 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -1101,6 +1101,11 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 	dev->registered = true;
 	dev->unplugged = false;
 
+	/* Call debugfs_init after the device is fully registered. */
+	if (dev->driver->debugfs_init && dev->primary &&
+	    dev->render != dev->primary)
+		dev->driver->debugfs_init(dev->primary);
+
 	if (driver->load) {
 		ret = driver->load(dev, flags);
 		if (ret)

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 5/9] rust: drm: add debugfs_init callback to Driver trait
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
                   ` (3 preceding siblings ...)
  2026-07-30 17:05 ` [PATCH v2 4/9] drm: move debugfs_init after dev->registered is set Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 6/9] rust: drm: add DrmSeqShow seq_file adapter Alvin Sun
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add debugfs_init method to the Driver trait, enabling Rust DRM
drivers to populate debugfs entries during device registration.
The C callback converts from raw C minor/dentry types to Rust Device
and ScopedDir references.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/bindings/bindings_helper.h |  1 +
 rust/kernel/drm/device.rs       | 36 ++++++++++++++++++++++++++++++++++--
 rust/kernel/drm/driver.rs       | 11 +++++++++++
 3 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 1124785e210b3..c3b2a86528934 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -30,6 +30,7 @@
 
 #include <linux/acpi.h>
 #include <linux/gpu_buddy.h>
+#include <drm/drm_debugfs.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_file.h>
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 7a3a0e21e9557..c9aa5d2374444 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -7,6 +7,7 @@
 use crate::{
     alloc::allocator::Kmalloc,
     bindings,
+    debugfs::ScopedDir,
     device,
     drm::{
         self,
@@ -39,7 +40,7 @@
     ptr::{
         self,
         NonNull, //
-    },
+    }, //
 };
 
 #[cfg(CONFIG_DRM_LEGACY)]
@@ -170,7 +171,7 @@ const fn compute_features() -> u32 {
         release: Some(Device::<T>::release),
         master_set: None,
         master_drop: None,
-        debugfs_init: None,
+        debugfs_init: Some(Device::<T, Normal>::debugfs_init_callback),
 
         gem_create_object: T::Object::ALLOC_OPS.gem_create_object,
         prime_handle_to_fd: T::Object::ALLOC_OPS.prime_handle_to_fd,
@@ -353,6 +354,37 @@ extern "C" fn release(ptr: *mut bindings::drm_device) {
         unsafe { core::ptr::drop_in_place(this) };
     }
 
+    /// C callback for `drm_driver.debugfs_init`.
+    ///
+    /// # Safety
+    ///
+    /// The DRM core guarantees that `minor` is valid and non-null when calling
+    /// this callback, and that `minor->dev` is a valid `drm_device` embedded
+    /// in a `Device<T>`.
+    unsafe extern "C" fn debugfs_init_callback(minor: *mut bindings::drm_minor) {
+        // SAFETY: `minor` is valid and non-null per the function's safety
+        // precondition.
+        let dev_ptr = unsafe { (*minor).dev };
+        // SAFETY: `minor` is valid per the function's safety precondition.
+        let debugfs_root = unsafe { (*minor).debugfs_root };
+
+        // Debugfs may be disabled.
+        if debugfs_root.is_null() {
+            return;
+        }
+
+        // SAFETY: `dev_ptr` points to a valid `drm_device` embedded in
+        // `Device<T, Normal>`. `debugfs_init` runs during registration, so
+        // the `Normal` context is correct.
+        let device = unsafe { Device::<T, Normal>::from_raw(dev_ptr) };
+
+        // SAFETY: `debugfs_root` is a valid dentry that remains alive as long as the
+        // DRM device is registered, which outlives this `ScopedDir`.
+        let dir = unsafe { ScopedDir::from_dentry(debugfs_root) };
+
+        T::debugfs_init(device, &dir);
+    }
+
     /// Change the [`DeviceContext`] for a [`Device`].
     ///
     /// # Safety
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index 08b2a318cf02a..7f3a6eaeddc5e 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -6,6 +6,7 @@
 
 use crate::{
     bindings,
+    debugfs::ScopedDir,
     device,
     drm,
     error::to_result,
@@ -138,6 +139,16 @@ pub trait Driver {
     /// usable from the render node (i.e. marked DRM_RENDER_ALLOW), whereas
     /// userspace processes using the master node can invoke any ioctl.
     const FEAT_RENDER: bool = false;
+
+    /// Populates debugfs for this DRM device.
+    ///
+    /// Called by the DRM core during registration, once per minor (callback
+    /// runs after `dev->registered`).
+    fn debugfs_init<'a>(_dev: &'a drm::Device<Self, drm::Normal>, _dir: &ScopedDir<'a, 'static>)
+    where
+        Self: Sized,
+    {
+    }
 }
 
 /// The registration type of a `drm::Device`.

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 6/9] rust: drm: add DrmSeqShow seq_file adapter
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
                   ` (4 preceding siblings ...)
  2026-07-30 17:05 ` [PATCH v2 5/9] rust: drm: add debugfs_init callback to Driver trait Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 7/9] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm Alvin Sun
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add DrmSeqShow trait and its SeqShow blanket impl for Device<T, Normal>,
enabling Rust DRM drivers to expose device state via debugfs seq_file
entries. Device registration data is kept alive for the duration of
each seq_file read.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/drm/debugfs.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++
 rust/kernel/drm/mod.rs     |  1 +
 2 files changed, 50 insertions(+)

diff --git a/rust/kernel/drm/debugfs.rs b/rust/kernel/drm/debugfs.rs
new file mode 100644
index 0000000000000..26f3b400e24ac
--- /dev/null
+++ b/rust/kernel/drm/debugfs.rs
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+
+//! DRM-specific debugfs seq_file helpers.
+
+use crate::{
+    debugfs,
+    drm,
+    prelude::*,
+    seq_file,
+    sync::aref::AlwaysRefCounted, //
+};
+use core::ptr::NonNull;
+
+/// Renders DRM device state into a seq_file under SRCU protection.
+///
+/// Pass an implementing type to
+/// [`debugfs::ScopedDir::seq_file`]. The `show`
+/// method receives a [`drm::RegistrationGuard`] that keeps DRM device data alive
+/// for its duration.
+pub trait DrmSeqShow<T: drm::Driver> {
+    /// Writes debugfs output for the file.
+    fn show(guard: &drm::RegistrationGuard<'_, T>, m: &seq_file::SeqFile) -> Result;
+}
+
+impl<S: DrmSeqShow<T>, T: drm::Driver> debugfs::SeqShow<drm::Device<T, drm::Normal>> for S {
+    fn show(dev: &drm::Device<T, drm::Normal>, m: &seq_file::SeqFile) -> Result {
+        // SAFETY: `debugfs_init` runs after `dev->registered = true` is set,
+        // so the `Ioctl` invariant is satisfied. `Normal` and `Ioctl` share
+        // an identical layout.
+        let dev = unsafe { dev.assume_ctx::<drm::Ioctl>() };
+
+        let Some(guard) = dev.registration_guard() else {
+            return Err(ENODEV);
+        };
+        S::show(&guard, m)
+    }
+
+    fn open(dev: &drm::Device<T, drm::Normal>) -> Result {
+        // Hold a device reference so the device is not freed while the file is open.
+        dev.inc_ref();
+        Ok(())
+    }
+
+    unsafe fn release(dev: NonNull<drm::Device<T, drm::Normal>>) {
+        // Drop the reference taken in `open`.
+        // SAFETY: `dev` is valid per this function's safety contract.
+        unsafe { drm::Device::<T>::dec_ref(dev) };
+    }
+}
diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs
index fd6ed35bc35a9..5ed2e6bb764eb 100644
--- a/rust/kernel/drm/mod.rs
+++ b/rust/kernel/drm/mod.rs
@@ -2,6 +2,7 @@
 
 //! DRM subsystem abstractions.
 
+pub mod debugfs;
 pub mod device;
 pub mod driver;
 pub mod file;

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 7/9] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
                   ` (5 preceding siblings ...)
  2026-07-30 17:05 ` [PATCH v2 6/9] rust: drm: add DrmSeqShow seq_file adapter Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 8/9] drm/tyr: add gpuvas debugfs file Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 9/9] drm/debugfs: hold device reference for the lifetime of open files Alvin Sun
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add method wrapping drm_debugfs_gpuva_info to dump GPU VA space
mappings into a seq_file. Needed by the Tyr gpuvas debugfs file.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 rust/kernel/drm/gpuvm/mod.rs | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/rust/kernel/drm/gpuvm/mod.rs b/rust/kernel/drm/gpuvm/mod.rs
index 20a08b3defeb8..9da88501a4206 100644
--- a/rust/kernel/drm/gpuvm/mod.rs
+++ b/rust/kernel/drm/gpuvm/mod.rs
@@ -312,6 +312,14 @@ pub fn data_ref(&self) -> &T {
         unsafe { &*self.0.data.get() }
     }
 
+    /// Dumps GPU VA space info into a seq_file.
+    ///
+    /// Wraps the C `drm_debugfs_gpuva_info` function.
+    pub fn dump_gpuva_info(&self, m: &crate::seq_file::SeqFile) -> Result {
+        // SAFETY: `m.as_raw()` and `self.as_raw()` are valid by the type invariants.
+        to_result(unsafe { bindings::drm_debugfs_gpuva_info(m.as_raw(), self.as_raw()) })
+    }
+
     /// Access the data owned by this `UniqueRefGpuVm` mutably.
     #[inline]
     pub fn data(&mut self) -> &mut T {

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 8/9] drm/tyr: add gpuvas debugfs file
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
                   ` (6 preceding siblings ...)
  2026-07-30 17:05 ` [PATCH v2 7/9] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  2026-07-30 17:05 ` [PATCH v2 9/9] drm/debugfs: hold device reference for the lifetime of open files Alvin Sun
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Add a gpuvas debugfs file listing all GPU VAs for the Tyr DRM driver.
Collects VMs into a shared list during firmware init and renders them
via dump_gpuva_info on read.

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 drivers/gpu/drm/tyr/debugfs.rs | 65 ++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tyr/driver.rs  | 16 +++++++++++
 drivers/gpu/drm/tyr/fw.rs      |  8 ++++++
 drivers/gpu/drm/tyr/tyr.rs     |  1 +
 drivers/gpu/drm/tyr/vm.rs      |  5 ++++
 5 files changed, 95 insertions(+)

diff --git a/drivers/gpu/drm/tyr/debugfs.rs b/drivers/gpu/drm/tyr/debugfs.rs
new file mode 100644
index 0000000000000..d381b1901bd08
--- /dev/null
+++ b/drivers/gpu/drm/tyr/debugfs.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+
+//! Debugfs support for the Tyr DRM driver.
+
+use kernel::{
+    alloc::KVec,
+    drm,
+    new_mutex,
+    prelude::*,
+    seq_file,
+    sync::{
+        Arc,
+        Mutex, //
+    }, //
+};
+
+use crate::{
+    driver::TyrDrmDriver,
+    vm::Vm, //
+};
+
+/// Registry of VMs for debugfs access.
+#[pin_data]
+pub(crate) struct VmRegistry<'drm> {
+    #[pin]
+    vms: Mutex<KVec<Arc<Vm<'drm>>>>,
+}
+
+impl<'drm> VmRegistry<'drm> {
+    pub(crate) fn new() -> impl PinInit<Self> {
+        pin_init!(Self { vms <- new_mutex!(KVec::new()) })
+    }
+
+    pub(crate) fn register(&self, vm: Arc<Vm<'drm>>) -> Result {
+        Ok(self.vms.lock().push(vm, GFP_KERNEL)?)
+    }
+
+    fn for_each(&self, mut f: impl FnMut(&Vm<'drm>) -> Result) -> Result {
+        for vm in self.vms.lock().iter() {
+            f(vm)?;
+        }
+        Ok(())
+    }
+}
+
+/// Debugfs data associated with a device.
+///
+/// Each field corresponds to a debugfs file.
+pub(crate) struct DebugfsData<'drm> {
+    pub(crate) gpuvas: Pin<KBox<VmRegistry<'drm>>>,
+}
+
+/// `DrmSeqShow` implementation for the `gpuvas` debugfs file.
+pub(crate) struct GpuvasShow;
+
+impl drm::debugfs::DrmSeqShow<TyrDrmDriver> for GpuvasShow {
+    fn show(guard: &drm::RegistrationGuard<'_, TyrDrmDriver>, m: &seq_file::SeqFile) -> Result {
+        guard.registration_data_with(|reg_data| {
+            reg_data
+                .debugfs_data
+                .gpuvas
+                .for_each(|vm| vm.dump_gpuva_info(m))
+        })
+    }
+}
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index a6694400be659..6af3e464994b4 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -7,6 +7,7 @@
         Clk,
         OptionalClk, //
     },
+    debugfs::ScopedDir,
     device::{
         Bound,
         Core,
@@ -45,6 +46,11 @@
 };
 
 use crate::{
+    debugfs::{
+        DebugfsData,
+        GpuvasShow,
+        VmRegistry, //
+    },
     file::TyrDrmFileData,
     fw::{
         irq::{
@@ -86,6 +92,8 @@ pub(crate) struct TyrDrmRegistrationData<'drm> {
     /// Firmware sections.
     pub(crate) fw: Arc<Firmware<'drm>>,
 
+    pub(crate) debugfs_data: DebugfsData<'drm>,
+
     #[pin]
     clks: Mutex<Clocks>,
 
@@ -167,11 +175,14 @@ fn probe<'bound>(
 
         let mmu = Mmu::new(pdev.as_ref(), iomem.as_arc_borrow(), &gpu_info)?;
 
+        let vms = KBox::pin_init(VmRegistry::new(), GFP_KERNEL)?;
+
         let firmware = Firmware::new(
             pdev.as_ref(),
             iomem.clone(),
             &unreg_dev,
             mmu.as_arc_borrow(),
+            &vms,
             &gpu_info,
         )?;
 
@@ -194,6 +205,7 @@ fn probe<'bound>(
         let reg_data = pin_init!(TyrDrmRegistrationData {
                 pdev,
                 fw: firmware,
+                debugfs_data: DebugfsData { gpuvas: vms },
                 clks <- new_mutex!(Clocks {
                     core: core_clk,
                     stacks: stacks_clk,
@@ -248,6 +260,10 @@ impl drm::Driver for TyrDrmDriver {
     kernel::declare_drm_ioctls! {
         (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
     }
+
+    fn debugfs_init<'a>(dev: &'a drm::Device<Self, drm::Normal>, dir: &ScopedDir<'a, 'static>) {
+        dir.seq_file::<GpuvasShow, _>(c"gpuvas", dev);
+    }
 }
 
 struct Clocks {
diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
index 65ac18b92b4f2..3f45767e93853 100644
--- a/drivers/gpu/drm/tyr/fw.rs
+++ b/drivers/gpu/drm/tyr/fw.rs
@@ -47,6 +47,7 @@
 };
 
 use crate::{
+    debugfs::VmRegistry,
     driver::{
         IoMem,
         TyrDrmDevice, //
@@ -251,6 +252,7 @@ pub(crate) fn new(
         iomem: Arc<IoMem<'drm>>,
         ddev: &TyrDrmDevice,
         mmu: ArcBorrow<'_, Mmu<'drm>>,
+        gpuvas: &VmRegistry<'drm>,
         gpu_info: &GpuInfo,
     ) -> Result<Arc<Firmware<'drm>>> {
         let vm = Vm::new(dev, ddev, mmu, gpu_info)?;
@@ -300,6 +302,12 @@ pub(crate) fn new(
             )?)
         })();
 
+        if result.is_ok() {
+            if let Err(e) = gpuvas.register(vm.clone()) {
+                dev_warn!(dev, "failed to register VM: {e:?}\n");
+            }
+        }
+
         if result.is_err() {
             vm.kill();
         }
diff --git a/drivers/gpu/drm/tyr/tyr.rs b/drivers/gpu/drm/tyr/tyr.rs
index e7ec450bdc9c0..6eb13c15d1657 100644
--- a/drivers/gpu/drm/tyr/tyr.rs
+++ b/drivers/gpu/drm/tyr/tyr.rs
@@ -7,6 +7,7 @@
 
 use crate::driver::TyrPlatformDriver;
 
+mod debugfs;
 mod driver;
 mod file;
 mod fw;
diff --git a/drivers/gpu/drm/tyr/vm.rs b/drivers/gpu/drm/tyr/vm.rs
index 74c3d6c8efc49..927d4605b1e8d 100644
--- a/drivers/gpu/drm/tyr/vm.rs
+++ b/drivers/gpu/drm/tyr/vm.rs
@@ -401,6 +401,11 @@ pub(crate) fn activate(&self) -> Result {
             })
     }
 
+    /// Dumps GPU VA space info into a seq_file.
+    pub(crate) fn dump_gpuva_info(&self, m: &kernel::seq_file::SeqFile) -> Result {
+        self.gpuvm_unique.lock().dump_gpuva_info(m)
+    }
+
     /// Deactivate the VM by evicting it from its address space slot.
     fn deactivate(&self) -> Result {
         self.mmu.deactivate_vm(&self.as_data).inspect_err(|e| {

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 9/9] drm/debugfs: hold device reference for the lifetime of open files
  2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
                   ` (7 preceding siblings ...)
  2026-07-30 17:05 ` [PATCH v2 8/9] drm/tyr: add gpuvas debugfs file Alvin Sun
@ 2026-07-30 17:05 ` Alvin Sun
  8 siblings, 0 replies; 10+ messages in thread
From: Alvin Sun @ 2026-07-30 17:05 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Greg Kroah-Hartman,
	Rafael J. Wysocki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Matthew Brost,
	Thomas Hellström, Maíra Canal, Melissa Wen,
	Wambui Karuga, Eric Anholt, Ben Gamari, rust-for-linux,
	driver-core, dri-devel, Alvin Sun

Hold a device reference (via drm_dev_get/put) across the lifetime of open
debugfs files. Prevents use-after-free when a device is unregistered while
a debugfs file remains open. Both drm_debugfs_open (legacy info_list)
and drm_debugfs_entry_open (drm_debugfs_add_file) paths are covered.

Fixes: 1c9cacbea8805 ("drm/debugfs: create device-centered debugfs functions")
Fixes: 28a62277e06f9 ("drm: Convert proc files to seq_file and introduce debugfs")

Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
---
 drivers/gpu/drm/drm_debugfs.c | 42 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 38cf6ce387cc8..5262a708f1602 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -159,11 +159,28 @@ static const struct drm_debugfs_info drm_debugfs_list[] = {
 static int drm_debugfs_open(struct inode *inode, struct file *file)
 {
 	struct drm_info_node *node = inode->i_private;
+	struct drm_device *dev = node->minor->dev;
+	int ret;
 
 	if (!device_is_registered(node->minor->kdev))
 		return -ENODEV;
 
-	return single_open(file, node->info_ent->show, node);
+	drm_dev_get(dev);
+
+	ret = single_open(file, node->info_ent->show, node);
+	if (ret)
+		drm_dev_put(dev);
+
+	return ret;
+}
+
+static int drm_debugfs_release(struct inode *inode, struct file *file)
+{
+	struct drm_info_node *node =
+		((struct seq_file *)file->private_data)->private;
+
+	drm_dev_put(node->minor->dev);
+	return single_release(inode, file);
 }
 
 static int drm_debugfs_entry_open(struct inode *inode, struct file *file)
@@ -171,11 +188,28 @@ static int drm_debugfs_entry_open(struct inode *inode, struct file *file)
 	struct drm_debugfs_entry *entry = inode->i_private;
 	struct drm_debugfs_info *node = &entry->file;
 	struct drm_minor *minor = entry->dev->primary ?: entry->dev->accel;
+	struct drm_device *dev = entry->dev;
+	int ret;
 
 	if (!device_is_registered(minor->kdev))
 		return -ENODEV;
 
-	return single_open(file, node->show, entry);
+	drm_dev_get(dev);
+
+	ret = single_open(file, node->show, entry);
+	if (ret)
+		drm_dev_put(dev);
+
+	return ret;
+}
+
+static int drm_debugfs_entry_release(struct inode *inode, struct file *file)
+{
+	struct drm_debugfs_entry *entry =
+		((struct seq_file *)file->private_data)->private;
+
+	drm_dev_put(entry->dev);
+	return single_release(inode, file);
 }
 
 static const struct file_operations drm_debugfs_entry_fops = {
@@ -183,7 +217,7 @@ static const struct file_operations drm_debugfs_entry_fops = {
 	.open = drm_debugfs_entry_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.release = single_release,
+	.release = drm_debugfs_entry_release,
 };
 
 static const struct file_operations drm_debugfs_fops = {
@@ -191,7 +225,7 @@ static const struct file_operations drm_debugfs_fops = {
 	.open = drm_debugfs_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.release = single_release,
+	.release = drm_debugfs_release,
 };
 
 /**

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-07-30 17:05 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 17:05 [PATCH v2 0/9] drm/tyr: add debugfs support Alvin Sun
2026-07-30 17:05 ` [PATCH v2 1/9] rust: seq_file: add as_raw() method Alvin Sun
2026-07-30 17:05 ` [PATCH v2 2/9] rust: debugfs: add SeqShow trait and seq_file file operations Alvin Sun
2026-07-30 17:05 ` [PATCH v2 3/9] rust: debugfs: add Entry::from_raw and ScopedDir::from_dentry Alvin Sun
2026-07-30 17:05 ` [PATCH v2 4/9] drm: move debugfs_init after dev->registered is set Alvin Sun
2026-07-30 17:05 ` [PATCH v2 5/9] rust: drm: add debugfs_init callback to Driver trait Alvin Sun
2026-07-30 17:05 ` [PATCH v2 6/9] rust: drm: add DrmSeqShow seq_file adapter Alvin Sun
2026-07-30 17:05 ` [PATCH v2 7/9] rust: drm: gpuvm: add dump_gpuva_info to UniqueRefGpuVm Alvin Sun
2026-07-30 17:05 ` [PATCH v2 8/9] drm/tyr: add gpuvas debugfs file Alvin Sun
2026-07-30 17:05 ` [PATCH v2 9/9] drm/debugfs: hold device reference for the lifetime of open files Alvin Sun

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.