rust: DebugFS Bindings
Subsystems (2)
v6 cover rust: DebugFS Bindings
This series provides safe DebugFS bindings for Rust, with a sample driver using them.
---
Changes in v6:
- Replaced explicit lifetimes with children keeping their parents alive.
- Added support for attaching owned data.
- Removed recomendation to only keep root handles and handles you want
to delete around.
- Refactored some code into separate files to improve clarity.
- Link to v5: https://lore.kernel.org/r/[email protected]
Changes in v5:
- Made Dir + File wrappers around Entry
- All functions return owning handles. To discard without drop, use forget. To keep a handle without drop, use ManuallyDrop.
- Fixed bugs around not(CONFIG_DEBUG_FS)
- Removed unnecessary addr_of!
- Link to v4: https://lore.kernel.org/r/[email protected]
Changes in v4:
- Remove SubDir, replace with type-level constant.
- Add lifetime to Dir to prevent subdirectories and files from outliving their parents and triggering an Oops when accessed.
- Split unsafe blocks with two calls into two blocks
- Access private field through direct pointer dereference, avoiding creation of a reference to it.
- Notably not changed - owning/non-owning handle defaults. The best read
I had from the thread was to continue with this mode, but I'm willing
to change if need be.
- Comment changes
- More comment markdown
- Remove scopes from examples
- Put as_ptr properties into a # Guarantees section.
- Link to v3: https://lore.kernel.org/r/[email protected]
Changes in v3:
- Split Dir into Dir/SubDir/File to improve API.
- Add "." to end of all comments.
- Convert INVARIANT to # Invariants on types.
- Add backticks everywhere I found variables/types in my comments.
- Promoted invariant comment to doc comment.
- Extended sample commenting to make it clearer what is happening.
- Link to v2: https://lore.kernel.org/r/[email protected]
Changes in v2:
- Drop support for builder / pinned bindings in initial series
- Remove ARef usage to abstract the dentry nature of handles
- Remove error handling to discourage users from caring whether DebugFS
is enabled.
- Support CONFIG_DEBUG_FS=n while leaving the API available
- Fixed mistaken decimal/octal mixup
- Doc/comment cleanup
- Link to v1: https://lore.kernel.org/r/[email protected]
---
Matthew Maurer (5):
rust: debugfs: Bind DebugFS directory creation
rust: debugfs: Bind file creation for long-lived Display
rust: debugfs: Support arbitrary owned backing for File
rust: debugfs: Support format hooks
rust: samples: Add debugfs sample
MAINTAINERS | 3 + rust/bindings/bindings_helper.h | 1 + rust/kernel/debugfs.rs | 218 ++++++++++++++++++++++++++++++++++++ rust/kernel/debugfs/display_file.rs | 115 +++++++++++++++++++ rust/kernel/debugfs/entry.rs | 66 +++++++++++ rust/kernel/lib.rs | 1 + samples/rust/Kconfig | 11 ++ samples/rust/Makefile | 1 + samples/rust/rust_debugfs.rs | 76 +++++++++++++ 9 files changed, 492 insertions(+)
---
base-commit: 6a7635cd013da3b41bf1e66bbdb9ae4a570d7449
change-id: 20250428-debugfs-rust-3cd5c97eb7d1
Best regards,
Signature · 1 line
Matthew Maurer <[email protected]>
PATCH v6 1/5 rust: debugfs: Bind DebugFS directory creation
Support creating DebugFS directories and subdirectories. Similar to the original DebugFS API, errors are hidden.
Directories persist until their handle and the handles of any child objects have been dropped.
--- MAINTAINERS | 2 + rust/bindings/bindings_helper.h | 1 + rust/kernel/debugfs.rs | 88 +++++++++++++++++++++++++++++++++++++++++ rust/kernel/debugfs/entry.rs | 58 +++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 5 files changed, 150 insertions(+)
MAINTAINERS +2 -0
@@ -7373,6 +7373,8 @@ F: include/linux/kobj* F: include/linux/property.h F: include/linux/sysfs.h F: lib/kobj* +F: rust/kernel/debugfs.rs +F: rust/kernel/debugfs/ F: rust/kernel/device.rs F: rust/kernel/device/ F: rust/kernel/device_id.rs
rust/bindings/bindings_helper.h +1 -0
@@ -45,6 +45,7 @@#include <linux/cpufreq.h> #include <linux/cpumask.h> #include <linux/cred.h> +#include <linux/debugfs.h> #include <linux/device/faux.h> #include <linux/dma-mapping.h> #include <linux/errname.h>
rust/kernel/debugfs.rs new file +88 -0
88 lines not on this page · raw message
rust/kernel/debugfs/entry.rs new file +58 -0
58 lines not on this page · raw message
rust/kernel/lib.rs +1 -0
@@ -66,6 +66,7 @@pub mod cpufreq;pub mod cpumask;pub mod cred; +pub mod debugfs;pub mod device;pub mod device_id;pub mod devres;
Signature · 1 line
2.50.0.rc2.696.g1fc2a0284f-goog
Danilo Krummrich
maintainerRe: [PATCH v6 1/5] rust: debugfs: Bind DebugFS directory creation
rust/kernel/debugfs.rs line 23
Quoted 10 lines · Matthew Maurer
rust/kernel/debugfs.rs new file +10
-0+#[cfg( CONFIG_DEBUG_FS )] +mod entry; + +/// Owning handle to a DebugFS directory. +/// +/// This directory will be cleaned up when the handle and all child directory/file handles have +/// been dropped. +// We hold a reference to our parent if it exists to prevent the dentry we point to from being +// cleaned up when our parent is removed. +pub struct Dir (#[cfg( CONFIG_DEBUG_FS )] Option <Arc <entry::Entry >>);
NIT: Can we import Entry, such that we don't have to refer to it as entry::Entry all the time?
PATCH v6 2/5 rust: debugfs: Bind file creation for long-lived Display
In reply to Matthew MaurerAllows creation of files for references that live forever and lack metadata through the Display implementation.
The reference must live forever because we do not have a maximum lifetime for the file we are creating.
The Display implementation is used because seq_printf needs to route through %pA, which in turn routes through Arguments.
--- rust/kernel/debugfs.rs | 62 +++++++++++++++++++++++++++++++++++++ rust/kernel/debugfs/display_file.rs | 60 +++++++++++++++++++++++++++++++++++ rust/kernel/debugfs/entry.rs | 8 +++++ 3 files changed, 130 insertions(+)
rust/kernel/debugfs.rs +62 -0
@@ -10,7 +10,10 @@use crate ::str::CStr ;#[cfg( CONFIG_DEBUG_FS )] use crate ::sync::Arc ; +use core::fmt::Display ; +#[cfg( CONFIG_DEBUG_FS )] +mod display_file;#[cfg( CONFIG_DEBUG_FS )] mod entry;
@@ -57,6 +60,43 @@ fn create(_name: &CStr, _parent: Option<&Dir>) -> Self {Self () } +#[cfg( CONFIG_DEBUG_FS )] +fn create_file <T :Display +Sized >(&self, name: &CStr , data: &'staticT ) ->File { +let Some (parent) = &self.0 else { +return File { + _entry: entry::Entry ::empty (), + }; + }; +// SAFETY: +// * `name` is a NUL-terminated C string, living across the call, by `CStr` invariant. +// * `parent` is a live `dentry` since we have a reference to it. +// * `vtable` is all stock `seq_file` implementations except for `open`. +// `open`'s only requirement beyond what is provided to all open functions is that the +// inode's data pointer must point to a `T` that will outlive it, which we know because +// we have a static reference. +let ptr =unsafe { + bindings::debugfs_create_file_full ( + name.as_char_ptr (), +0o444 , + parent.as_ptr (), + dataas *const _ as *mut _ , + core::ptr::null (), + &<T as display_file::DisplayFile >::VTABLE , + ) + }; + +// SAFETY: `debugfs_create_file_full` either returns an error code or a legal +// dentry pointer, so `Entry::new` is safe to call here. +let entry =unsafe { entry::Entry ::new (ptr,Some (parent.clone ())) }; + +File { _entry: entry } + } + +#[cfg(not( CONFIG_DEBUG_FS ))] +fn create_file <T :Display +Sized >(&self, _name: &CStr , _data: &'staticT ) ->File { +File {} + } +/// Create a DebugFS subdirectory. /// /// Subdirectory handles cannot outlive the directory handle they were created from.
@@ -73,6 +113,22 @@ pub fn subdir(&self, name: &CStr) -> Self {Dir ::create (name,Some (self)) } +/// Create a file in a DebugFS directory with the provided name, and contents from invoking +/// [`Display::fmt`] on the provided reference. +/// +/// # Examples +/// +/// ``` +/// # use kernel::c_str; +/// # use kernel::debugfs::Dir; +/// let dir = Dir::new(c_str!("my_debugfs_dir")); +/// dir.display_file(c_str!("foo"), &200); +/// // "my_debugfs_dir/foo" now contains the number 200. +/// ``` +pub fn display_file <T :Display +Sized >(&self, name: &CStr , data: &'staticT ) ->File { + self.create_file (name, data) + } +/// Create a new directory in DebugFS at the root. /// /// # Examples
@@ -86,3 +142,9 @@ pub fn new(name: &CStr) -> Self {Dir ::create (name,None ) } } + +/// Handle to a DebugFS file. +pub struct File { +#[cfg( CONFIG_DEBUG_FS )] + _entry: entry::Entry , +}
rust/kernel/debugfs/display_file.rs new file +60 -0
60 lines not on this page · raw message
rust/kernel/debugfs/entry.rs +8 -0
@@ -38,6 +38,14 @@ pub(crate) unsafe fn new(entry: *mut bindings::dentry, parent: Option<Arc<Entry> } } +/// Constructs a placeholder DebugFS [`Entry`]. +pub (crate )fn empty () ->Self { +Self { + entry: core::ptr::null_mut (), + _parent:None , + } + } +/// Returns the pointer representation of the DebugFS directory. /// /// # Guarantees
Signature · 1 line
2.50.0.rc2.696.g1fc2a0284f-goog
Danilo Krummrich
maintainerRe: [PATCH v6 2/5] rust: debugfs: Bind file creation for long-lived Display
Quoted 14 lines · Matthew Maurer
rust/kernel/debugfs/display_file.rs new file +8
-0@@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Google LLC. + +use crate ::seq_file::SeqFile ; +use crate ::seq_print; +use core::fmt::Display ; + +/// Implements `open` for `file_operations` via `single_open` to fill out a `seq_file`.
rust/kernel/debugfs/display_file.rs line 18
Quoted 10 lines
rust/kernel/debugfs/display_file.rs new file +10
-0+/// +/// # Safety +/// +/// * `inode`'s private pointer must point to a value of type `T` which will outlive the `inode` +/// and will not be mutated during this call. +/// * `file` must point to a live, not-yet-initialized file object. +pub (crate )unsafe extern "C" fn display_open <T :Display >( + inode: *mut bindings::inode , + file: *mut bindings::file , +) ->i32 {
Please use kernel::ffi::c_int instead.
Quoted 9 lines
rust/kernel/debugfs/display_file.rs new file +9
-0+// SAFETY: +// * `file` is acceptable by caller precondition. +// * `print_act` will be called on a `seq_file` with private data set to the third argument, +// so we meet its safety requirements. +// * The `data` pointer passed in the third argument is a valid `T` pointer that outlives +// this call by caller preconditions. +unsafe { bindings::single_open (file,Some (display_act ::<T >), (*inode).i_private) } +} +
rust/kernel/debugfs/display_file.rs line 37
Quoted 10 lines
rust/kernel/debugfs/display_file.rs new file +10
-0+/// Prints private data stashed in a seq_file to that seq file. +/// +/// # Safety +/// +/// `seq` must point to a live `seq_file` whose private data is a live pointer to a `T` which is +/// not being mutated. +pub (crate )unsafe extern "C" fn display_act <T :Display >( + seq: *mut bindings::seq_file , + _: *mut core::ffi::c_void , +) ->i32 {
kernel::ffi::c_int
Quoted 7 lines
rust/kernel/debugfs/display_file.rs new file +7
-0+// SAFETY: By caller precondition, this pointer is live, points to a value of type `T`, and +// is not being mutated. +let data =unsafe { &*((*seq).privateas *mut T ) }; +// SAFETY: By caller precondition, `seq_file` points to a live `seq_file`, so we can lift +// it. +let seq_file =unsafe {SeqFile ::from_raw (seq) }; +seq_print! (seq_file,"{}" , data);
rust/kernel/debugfs/display_file.rs line 54
Quoted 10 lines
rust/kernel/debugfs/display_file.rs new file +10
-0+0 +} + +// Work around lack of generic const items. +pub (crate )trait DisplayFile :Display +Sized { +const VTABLE : bindings::file_operations = bindings::file_operations { + read:Some (bindings::seq_read), + llseek:Some (bindings::seq_lseek), + release:Some (bindings::single_release), + open:Some (display_open ::<Self >as _ ),
Why the cast? That shouldn't be needed.
Quoted 4 lines
rust/kernel/debugfs/display_file.rs new file +4
-0+// SAFETY: `file_operations` supports zeroes in all fields. + ..unsafe { core::mem::zeroed () } + }; +}
Alice Ryhl
reviewerRe: [PATCH v6 2/5] rust: debugfs: Bind file creation for long-lived Display
Quoted 20 lines · Danilo Krummrich
Quoted 18 lines · Matthew Maurer
rust/kernel/debugfs/display_file.rs new file +12
-0@@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Google LLC. + +use crate ::seq_file::SeqFile ; +use crate ::seq_print; +use core::fmt::Display ; + +/// Implements `open` for `file_operations` via `single_open` to fill out a `seq_file`. +/// +/// # Safety +/// +/// * `inode`'s private pointer must point to a value of type `T` which will outlive the `inode`
Quoted 8 lines
rust/kernel/debugfs/display_file.rs line 18
Quoted 6 lines
rust/kernel/debugfs/display_file.rs new file +6
-0+/// and will not be mutated during this call. +/// * `file` must point to a live, not-yet-initialized file object. +pub (crate )unsafe extern "C" fn display_open <T :Display >( + inode: *mut bindings::inode , + file: *mut bindings::file , +) ->i32 {Please use
kernel::ffi::c_intinstead.
And please use it without the fully qualified path. The c_int typedef is available in the prelude, so if you import kernel::prelude::* it should be available.
Alice
PATCH v6 3/5 rust: debugfs: Support arbitrary owned backing for File
In reply to Matthew MaurerThis allows Files to be backed by Deref<Target=T> rather than just &'static T. This means that dynamically allocated objects can be attached to Files without needing to take extra steps to create a pinned reference that's guaranteed to live long enough.
--- rust/kernel/debugfs.rs | 51 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-)
rust/kernel/debugfs.rs +39 -12
@@ -5,12 +5,13 @@//! //! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) -#[cfg( CONFIG_DEBUG_FS )] +use crate ::alloc::KBox ;use crate ::prelude::GFP_KERNEL ;use crate ::str::CStr ;#[cfg( CONFIG_DEBUG_FS )] use crate ::sync::Arc ;use core::fmt::Display ; +use core::ops::Deref ;#[cfg( CONFIG_DEBUG_FS )] mod display_file;
@@ -61,40 +62,59 @@ fn create(_name: &CStr, _parent: Option<&Dir>) -> Self { }#[cfg( CONFIG_DEBUG_FS )] -fn create_file <T :Display +Sized >(&self, name: &CStr , data: &'staticT ) ->File { +fn create_file <D :Deref <Target =T > + 'static +Send +Sync ,T :Display >( + &self, + name: &CStr , + data:D , + ) ->File { +let mut file =File { + _entry: entry::Entry ::empty (), + _data:None , + }; +let Some (data) =KBox ::new (data,GFP_KERNEL ).ok ()else { +return file; + }; +let Some (parent) = &self.0 else { -return File { - _entry: entry::Entry ::empty (), - }; +return file; }; +// SAFETY: // * `name` is a NUL-terminated C string, living across the call, by `CStr` invariant. // * `parent` is a live `dentry` since we have a reference to it. // * `vtable` is all stock `seq_file` implementations except for `open`. // `open`'s only requirement beyond what is provided to all open functions is that the // inode's data pointer must point to a `T` that will outlive it, which we know because -// we have a static reference. +// we have an owning `D` in the `File`, and we tear down the file during `Drop`. let ptr =unsafe { bindings::debugfs_create_file_full ( name.as_char_ptr (),0o444 , parent.as_ptr (), - dataas *const _ as *mut _ , + data.deref ()as *const _ as *mut _ , core::ptr::null (), &<T as display_file::DisplayFile >::VTABLE , ) }; + file._data =Some (data); +// SAFETY: `debugfs_create_file_full` either returns an error code or a legal // dentry pointer, so `Entry::new` is safe to call here. -let entry =unsafe { entry::Entry ::new (ptr,Some (parent.clone ())) }; + file._entry =unsafe { entry::Entry ::new (ptr,Some (parent.clone ())) }; -File { _entry: entry } + file }#[cfg(not( CONFIG_DEBUG_FS ))] -fn create_file <T :Display +Sized >(&self, _name: &CStr , _data: &'staticT ) ->File { -File {} +fn create_file <D :Deref <Target =T > + 'static +Send +Sync ,T :Display >( + &self, + _name: &CStr , + data:D , + ) ->File { +File { + _data:KBox ::new (data,GFP_KERNEL ).ok ().map (|x| xas _ ), + } }/// Create a DebugFS subdirectory.
@@ -125,7 +145,11 @@ pub fn subdir(&self, name: &CStr) -> Self {/// dir.display_file(c_str!("foo"), &200); /// // "my_debugfs_dir/foo" now contains the number 200. /// ``` -pub fn display_file <T :Display +Sized >(&self, name: &CStr , data: &'staticT ) ->File { +pub fn display_file <D :Deref <Target =T > + 'static +Send +Sync ,T :Display >( + &self, + name: &CStr , + data:D , + ) ->File { self.create_file (name, data) }
@@ -147,4 +171,7 @@ pub fn new(name: &CStr) -> Self {pub struct File {#[cfg( CONFIG_DEBUG_FS )] _entry: entry::Entry , +// The data needs to be kept in a `Box` to prevent it from moving when the file does, as +// this might invalidate the pointer that's been passed to debugfs. + _data:Option <KBox <dyn Send +Sync >>, }
Signature · 1 line
2.50.0.rc2.696.g1fc2a0284f-goog
Alice Ryhl
reviewerRe: [PATCH v6 3/5] rust: debugfs: Support arbitrary owned backing for File
Quoted 36 lines · Matthew Maurer
This allows
Files to be backed byDeref<Target=T>rather than just&'static T. This means that dynamically allocated objects can be attached toFiles without needing to take extra steps to create a pinned reference that's guaranteed to live long enough.Signed-off-by Matthew Maurer <[email protected]>--- rust/kernel/debugfs.rs | 51 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-)rust/kernel/debugfs.rs +4
-2@@ -5,12 +5,13 @@//! //! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) -#[cfg( CONFIG_DEBUG_FS )] +use crate ::alloc::KBox ;use crate ::prelude::GFP_KERNEL ;use crate ::str::CStr ;#[cfg( CONFIG_DEBUG_FS )] use crate ::sync::Arc ;use core::fmt::Display ; +use core::ops::Deref ;#[cfg( CONFIG_DEBUG_FS )] mod display_file;@@ -61,40 +62,59 @@ fn create(_name: &CStr, _parent: Option<&Dir>) -> Self { }#[cfg( CONFIG_DEBUG_FS )] -fn create_file <T :Display +Sized >(&self, name: &CStr , data: &'staticT ) ->File { +fn create_file <D :Deref <Target =T > + 'static +Send +Sync ,T :Display >( + &self,
rust/kernel/debugfs.rs fn create(_name: &CStr, _parent: Option<&Dir>) -> Self { · line 76
Quoted 10 lines
rust/kernel/debugfs.rs +10
-0+ name: &CStr, + data: D, + ) -> File { + let mut file = File { + _entry: entry::Entry ::empty (), + _data:None , + }; +let Some (data) =KBox ::new (data,GFP_KERNEL ).ok ()else { +return file; + };
We may want to consider using the ForeignOwnable trait here instead. The trait is implemented by anything that can be converted to/from a void pointer, so you can:
* When creating the file, convert it to a void pointer that you store in File and pass to debugfs_create_file_full.
* When displaying the file, create a borrowed version of the void pointer and display that.
* When freeing the File, convert the void pointer back into an owned value and drop it.
For cases where a box really is necessary, the user can create a box and pass it themselves. But if the user already has a pointer type (e.g. and Arc<T> or &'static T) then they can pass that pointer directly and the pointer is stored as a void pointer without the Box indirection.
Alice
Re: [PATCH v6 3/5] rust: debugfs: Support arbitrary owned backing for File
Quoted 1 line
We may want to consider using the ForeignOwnable trait here instead. The
I was considering trying to switch over to StableDeref-like trait
[1] in a follow-up patchset. The core property I need is that moving the D cannot result in the pointer it would deref to changing.
The problem with ForeignOwnable is that it forbids the user from passing in a Box<dyn Foo>, because that doesn't fit in a void* A StableDeref version would not have this issue. I agree that ForeignOwnable would be a strict upgrade to what I have now, since a user can still pass in a Box<Box<dyn Foo>> and have it work with ForeignOwnable, and if we ever added StableDeref, then ForeignOwnable would have a blanket impl for it.
I'll send a new version using ForeignOwnable, and we can consider the StableDeref version in the future.
[1]: https://docs.rs/gimli/latest/gimli/trait.StableDeref.html
Quoted 16 lines
trait is implemented by anything that can be converted to/from a void pointer, so you can:
* When creating the file, convert it to a void pointer that you store in File and pass to
debugfs_create_file_full.
* When displaying the file, create a borrowed version of the void pointer and display that.
* When freeing the File, convert the void pointer back into an owned value and drop it.For cases where a box really is necessary, the user can create a box and pass it themselves. But if the user already has a pointer type (e.g. and Arc<T> or &'static T) then they can pass that pointer directly and the pointer is stored as a void pointer without the Box indirection.
Alice
Danilo Krummrich
maintainerRe: [PATCH v6 3/5] rust: debugfs: Support arbitrary owned backing for File
Quoted 14 lines · Matthew Maurer
Quoted 1 line
We may want to consider using the ForeignOwnable trait here instead. The
I was considering trying to switch over to
StableDeref-like trait
[1] in a follow-up patchset. The core property I need is that moving theDcannot result in the pointer it wouldderefto changing.The problem with
ForeignOwnableis that it forbids the user from passing in aBox<dyn Foo>, because that doesn't fit in avoid*AStableDerefversion would not have this issue. I agree thatForeignOwnablewould be a strict upgrade to what I have now, since a user can still pass in aBox<Box<dyn Foo>>and have it work withForeignOwnable, and if we ever addedStableDeref, thenForeignOwnablewould have a blanket impl for it.
Quoted 2 lines
I'll send a new version using
ForeignOwnable, and we can consider theStableDerefversion in the future.
Yes, please do that for now. It's rather common case that drivers want to expose reference counted data, i.e. an Arc, through debugfs and having to go through the indirection with an additional Box isn't quite nice.
Quoted 19 lines
[1]: https://docs.rs/gimli/latest/gimli/trait.StableDeref.html
Quoted 16 lines
trait is implemented by anything that can be converted to/from a void pointer, so you can:
* When creating the file, convert it to a void pointer that you store in File and pass to
debugfs_create_file_full.
* When displaying the file, create a borrowed version of the void pointer and display that.
* When freeing the File, convert the void pointer back into an owned value and drop it.For cases where a box really is necessary, the user can create a box and pass it themselves. But if the user already has a pointer type (e.g. and Arc<T> or &'static T) then they can pass that pointer directly and the pointer is stored as a void pointer without the Box indirection.
Alice
PATCH v6 4/5 rust: debugfs: Support format hooks
In reply to Matthew MaurerRather than always using Display, allow hooking arbitrary functions to arbitrary files. Display technically has the expressiveness to do this, but requires a new type be declared for every different way to render things, which can be very clumsy.
--- rust/kernel/debugfs.rs | 41 ++++++++++++++++++++++++++ rust/kernel/debugfs/display_file.rs | 57 ++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-)
rust/kernel/debugfs.rs +41 -0
@@ -10,6 +10,7 @@use crate ::str::CStr ;#[cfg( CONFIG_DEBUG_FS )] use crate ::sync::Arc ; +use core::fmt;use core::fmt::Display ;use core::ops::Deref ;
@@ -153,6 +154,46 @@ pub fn display_file<D: Deref<Target = T> + 'static + Send + Sync, T: Display>( self.create_file (name, data) } +/// Create a file in a DebugFS directory with the provided name, and contents from invoking `f` +/// on the provided reference. +/// +/// `f` must be a function item or a non-capturing closure, or this will fail to compile. +/// +/// # Examples +/// +/// ``` +/// # use core::sync::atomic::{AtomicU32, Ordering}; +/// # use kernel::c_str; +/// # use kernel::debugfs::Dir; +/// let dir = Dir::new(c_str!("foo")); +/// static MY_ATOMIC: AtomicU32 = AtomicU32::new(3); +/// let file = dir.fmt_file(c_str!("bar"), &MY_ATOMIC, &|val, f| { +/// let out = val.load(Ordering::Relaxed); +/// writeln!(f, "{out:#010x}") +/// }); +/// MY_ATOMIC.store(10, Ordering::Relaxed); +/// ``` +pub fn fmt_file < +D :Deref <Target =T > + 'static +Send +Sync , +T :Sync , +F :Fn (&T , &mut fmt::Formatter <'_>) -> fmt::Result +Send +Sync , + >( + &self, + name: &CStr , + data:D , + f: &'staticF , + ) ->File { +#[cfg( CONFIG_DEBUG_FS )] +let data_adapted = display_file::FormatAdapter ::new (data, f); +#[cfg(not( CONFIG_DEBUG_FS ))] +let data_adapted = { +// Mark used +let (_, _) = (data, f); + &0 + }; + self.display_file (name, data_adapted) + } +/// Create a new directory in DebugFS at the root. /// /// # Examples
rust/kernel/debugfs/display_file.rs +56 -1
66 lines not on this page · raw message
Signature · 1 line
2.50.0.rc2.696.g1fc2a0284f-goog
PATCH v6 5/5 rust: samples: Add debugfs sample
In reply to Matthew MaurerProvides an example of using the Rust DebugFS bindings.
--- MAINTAINERS | 1 + samples/rust/Kconfig | 11 +++++++ samples/rust/Makefile | 1 + samples/rust/rust_debugfs.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+)
MAINTAINERS +1 -0
@@ -7382,6 +7382,7 @@ F: rust/kernel/devres.rs F: rust/kernel/driver.rs F: rust/kernel/faux.rs F: rust/kernel/platform.rs +F: samples/rust/rust_debugfs.rs F: samples/rust/rust_driver_platform.rs F: samples/rust/rust_driver_faux.rs
samples/rust/Kconfig +11 -0
@@ -62,6 +62,17 @@ config SAMPLE_RUST_DMA If unsure, say N. +config SAMPLE_RUST_DEBUGFS + tristate "DebugFS Test Driver" + depends on DEBUG_FS + help + This option builds the Rust DebugFS Test driver sample. + + To compile this as a module, choose M here: + the module will be called rust_debugfs. + + If unsure, say N. + config SAMPLE_RUST_DRIVER_PCI tristate "PCI Driver" depends on PCI
samples/rust/Makefile +1 -0
@@ -4,6 +4,7 @@ ccflags-y += -I$(src) # needed for trace events obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o +obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) += rust_debugfs.o obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o
samples/rust/rust_debugfs.rs new file +76 -0
76 lines not on this page · raw message
Signature · 1 line
2.50.0.rc2.696.g1fc2a0284f-goog
Danilo Krummrich
maintainerRe: [PATCH v6 5/5] rust: samples: Add debugfs sample
samples/rust/Kconfig config SAMPLE_RUST_DMA · line 66
Quoted 2 lines · Matthew Maurer
samples/rust/Kconfig +2
-0+config SAMPLE_RUST_DEBUGFS + tristate "DebugFS Test Driver"
s/driver/module/
samples/rust/Kconfig config SAMPLE_RUST_DMA · line 69
Quoted 3 lines
samples/rust/Kconfig +3
-0+ depends on DEBUG_FS + help + This option builds the Rust DebugFS Test driver sample.
s/driver/module/
Alice Ryhl
reviewerQuoted 4 lines · Matthew Maurer
This series provides safe DebugFS bindings for Rust, with a sample driver using them.
Signed-off-by Matthew Maurer <[email protected]>
Overall I think this series looks great. I left one comment, but overall LGTM.
Alice
Quoted 4 lines · Matthew Maurer
This series provides safe DebugFS bindings for Rust, with a sample driver using them.
Signed-off-by Matthew Maurer <[email protected]>
Having this series applied on top of v6.16-rc1 and adapting a proprietary driver exposing some simple u64 values via debugfs on ARM64 looks good.
Thanks!
Dirk
Quoted 75 lines
---
Changes in v6:
- Replaced explicit lifetimes with children keeping their parents alive.
- Added support for attaching owned data.
- Removed recomendation to only keep root handles and handles you want
to delete around.
- Refactored some code into separate files to improve clarity.
- Link to v5: https://lore.kernel.org/r/[email protected]Changes in v5:
- Made Dir + File wrappers around Entry
- All functions return owning handles. To discard without drop, useforget. To keep a handle without drop, useManuallyDrop.
- Fixed bugs aroundnot(CONFIG_DEBUG_FS)
- Removed unnecessaryaddr_of!
- Link to v4: https://lore.kernel.org/r/[email protected]Changes in v4:
- Remove SubDir, replace with type-level constant.
- Add lifetime to Dir to prevent subdirectories and files from outliving their parents and triggering an Oops when accessed.
- Split unsafe blocks with two calls into two blocks
- Accessprivatefield through direct pointer dereference, avoiding creation of a reference to it.
- Notably not changed - owning/non-owning handle defaults. The best read
I had from the thread was to continue with this mode, but I'm willing
to change if need be.
- Comment changes
- More comment markdown
- Remove scopes from examples
- Putas_ptrproperties into a# Guaranteessection.
- Link to v3: https://lore.kernel.org/r/[email protected]Changes in v3:
- SplitDirintoDir/SubDir/Fileto improve API.
- Add "." to end of all comments.
- Convert INVARIANT to # Invariants on types.
- Add backticks everywhere I found variables/types in my comments.
- Promoted invariant comment to doc comment.
- Extended sample commenting to make it clearer what is happening.
- Link to v2: https://lore.kernel.org/r/[email protected]Changes in v2:
- Drop support for builder / pinned bindings in initial series
- RemoveARefusage to abstract the dentry nature of handles
- Remove error handling to discourage users from caring whether DebugFS
is enabled.
- SupportCONFIG_DEBUG_FS=nwhile leaving the API available
- Fixed mistaken decimal/octal mixup
- Doc/comment cleanup
- Link to v1: https://lore.kernel.org/r/[email protected]---
Matthew Maurer (5):
rust: debugfs: Bind DebugFS directory creation
rust: debugfs: Bind file creation for long-lived Display
rust: debugfs: Support arbitrary owned backing for File
rust: debugfs: Support format hooks
rust: samples: Add debugfs sampleMAINTAINERS | 3 + rust/bindings/bindings_helper.h | 1 + rust/kernel/debugfs.rs | 218 ++++++++++++++++++++++++++++++++++++ rust/kernel/debugfs/display_file.rs | 115 +++++++++++++++++++ rust/kernel/debugfs/entry.rs | 66 +++++++++++ rust/kernel/lib.rs | 1 + samples/rust/Kconfig | 11 ++ samples/rust/Makefile | 1 + samples/rust/rust_debugfs.rs | 76 +++++++++++++ 9 files changed, 492 insertions(+)---
base-commit:6a7635cd013da3b41bf1e66bbdb9ae4a570d7449
change-id: 20250428-debugfs-rust-3cd5c97eb7d1Best regards,
Signature · 17 lines
======================================================================
Dirk Behme Robert Bosch Car Multimedia GmbH
CM/ESO2
Phone: +49 5121 49-3274 Dirk Behme
Fax: +49 711 811 5053274 PO Box 77 77 77
mailto:[email protected] D-31132 Hildesheim - Germany
Bosch Group, Car Multimedia (CM)
Engineering SW Operating Systems 2 (ESO2)
Robert Bosch Car Multimedia GmbH - Ein Unternehmen der Bosch Gruppe
Sitz: Hildesheim
Registergericht: Amtsgericht Hildesheim HRB 201334
Aufsichtsratsvorsitzender: Dr. Dirk Hoheisel
Geschäftsführung: Dr. Steffen Berns;
Dr. Sven Ost, Jörg Pollak, Dr. Walter Schirm
======================================================================