rust/kernel/debugfs.rs | 52 +++++++++++++++++++++ samples/rust/rust_debugfs.rs | 91 ++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+)
Introduce `impl_debugfs_primitive!` to implement debugfs attribute
creation for native Rust primitive types by wrapping C debugfs creation
helpers.
Signed-off-by: Matthias Kaehlcke <matthias@kaehlcke.net>
---
rust/kernel/debugfs.rs | 52 +++++++++++++++++++++
samples/rust/rust_debugfs.rs | 91 ++++++++++++++++++++++++++++++++++++
2 files changed, 143 insertions(+)
diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index d7b8014a6474..bec600c67a06 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -400,6 +400,58 @@ pub fn scope<'a, T: 'a, E: 'a, F>(
}
}
+/// Implements `debugfs` interface operations for a single primitive type.
+///
+/// This macro generates the necessary FFI wrappers and glue code to expose
+/// a specific primitive type (e.g., `u32`, `bool`) to the `debugfs` filesystem.
+///
+/// # Type Support
+///
+/// Accepts standard integer primitives (`u8` through `u64`, `x8` through `x64`),
+/// `bool`, and `usize`.
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// impl_debugfs_primitive!(u32, create_u32, debugfs_create_u32);
+/// ```
+macro_rules! impl_debugfs_primitive {
+ ($type:ty, $fn_name:ident,$c_func:ident) => {
+ impl Dir {
+ /// Creates a debugfs entry for a primitive `$type` value inside this directory.
+ ///
+ /// # Safety
+ ///
+ /// `value` must point to a valid memory location that outlives this directory `Dir`
+ /// (e.g., inside a pinned driver state structure or a `static` location).
+ pub unsafe fn $fn_name(&self, name: &CStr, mode: u16, value: *mut $type) {
+ let parent_ptr = match self.0.as_deref() {
+ Some(entry) => entry.as_ptr(),
+ None => core::ptr::null_mut(),
+ };
+
+ // SAFETY: `name` is a valid CStr. `parent_ptr` points to a valid parent
+ // dentry or NULL. The caller guarantees that `value` outlives the debugfs node.
+ unsafe {
+ bindings::$c_func(name.as_char_ptr(), mode, parent_ptr, value);
+ }
+ }
+ }
+ };
+}
+
+// Bind native Rust primitive types to their corresponding C debugfs helpers.
+impl_debugfs_primitive!(u8, create_u8, debugfs_create_u8);
+impl_debugfs_primitive!(u16, create_u16, debugfs_create_u16);
+impl_debugfs_primitive!(u32, create_u32, debugfs_create_u32);
+impl_debugfs_primitive!(u64, create_u64, debugfs_create_u64);
+impl_debugfs_primitive!(u8, create_x8, debugfs_create_x8);
+impl_debugfs_primitive!(u16, create_x16, debugfs_create_x16);
+impl_debugfs_primitive!(u32, create_x32, debugfs_create_x32);
+impl_debugfs_primitive!(u64, create_x64, debugfs_create_x64);
+impl_debugfs_primitive!(bool, create_bool, debugfs_create_bool);
+impl_debugfs_primitive!(usize, create_size_t, debugfs_create_size_t);
+
#[pin_data]
/// Handle to a DebugFS scope, which ensures that attached `data` will outlive the DebugFS entry
/// without moving.
diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
index 77c19a437695..b2ef8c71f7ee 100644
--- a/samples/rust/rust_debugfs.rs
+++ b/samples/rust/rust_debugfs.rs
@@ -34,6 +34,7 @@
use core::str::FromStr;
use kernel::{
acpi,
+ c_str,
debugfs::{
Dir,
File, //
@@ -79,6 +80,8 @@ struct RustDebugFs {
array_blob: File<Mutex<[u8; 4]>>,
#[pin]
vector_blob: File<Mutex<KVec<u8>>>,
+ #[pin]
+ primitive_values: PrimitiveValues,
}
#[derive(Debug)]
@@ -87,6 +90,36 @@ struct Inner {
y: u32,
}
+struct PrimitiveValues {
+ u8: u8,
+ u16: u16,
+ u32: u32,
+ u64: u64,
+ x8: u8,
+ x16: u16,
+ x32: u32,
+ x64: u64,
+ size_t: usize,
+ bool: bool,
+}
+
+impl PrimitiveValues {
+ fn new() -> Self {
+ Self {
+ u8: 8,
+ u16: 16,
+ u32: 32,
+ u64: 64,
+ x8: 0x88,
+ x16: 0x1616,
+ x32: 0x32323232,
+ x64: 0x6464646464646464,
+ size_t: 12345678,
+ bool: true,
+ }
+ }
+}
+
impl FromStr for Inner {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
@@ -171,9 +204,67 @@ fn new<'a, 'b>(
c"vector_blob",
new_mutex!(kernel::kvec!(0x42; SZ_4K)?),
),
+ primitive_values <- PrimitiveValues::new(),
_debugfs: debugfs,
pdev: pdev.into(),
}
}
+ .pin_chain(|this| {
+ // SAFETY: primitive values live until the module is dropped
+ unsafe {
+ this._debugfs.create_u8(
+ c_str!("u8"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.u8) as *mut _,
+ );
+ this._debugfs.create_u16(
+ c_str!("u16"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.u16) as *mut _,
+ );
+ this._debugfs.create_u32(
+ c_str!("u32"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.u32) as *mut _,
+ );
+ this._debugfs.create_u64(
+ c_str!("u64"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.u64) as *mut _,
+ );
+ this._debugfs.create_x8(
+ c_str!("x8"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.x8) as *mut _,
+ );
+ this._debugfs.create_x16(
+ c_str!("x16"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.x16) as *mut _,
+ );
+ this._debugfs.create_x32(
+ c_str!("x32"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.x32) as *mut _,
+ );
+ this._debugfs.create_x64(
+ c_str!("x64"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.x64) as *mut _,
+ );
+ this._debugfs.create_bool(
+ c_str!("bool"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.bool) as *mut _,
+ );
+ this._debugfs.create_size_t(
+ c_str!("usize"),
+ 0644,
+ core::ptr::addr_of!(this.primitive_values.size_t) as *mut _,
+ );
+ }
+
+ Ok(())
+ })
}
}
--
2.47.3
sashiko-bot@kernel.org pointed out a few issues that seem valid,
I'll try to address these first before human reviewer time is
needed.
El Tue, Sep 22, 2026 at 09:18:58PM +0200 Matthias Kaehlcke ha dit:
> Introduce `impl_debugfs_primitive!` to implement debugfs attribute
> creation for native Rust primitive types by wrapping C debugfs creation
> helpers.
>
> Signed-off-by: Matthias Kaehlcke <matthias@kaehlcke.net>
> ---
> rust/kernel/debugfs.rs | 52 +++++++++++++++++++++
> samples/rust/rust_debugfs.rs | 91 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 143 insertions(+)
>
> diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
> index d7b8014a6474..bec600c67a06 100644
> --- a/rust/kernel/debugfs.rs
> +++ b/rust/kernel/debugfs.rs
> @@ -400,6 +400,58 @@ pub fn scope<'a, T: 'a, E: 'a, F>(
> }
> }
>
> +/// Implements `debugfs` interface operations for a single primitive type.
> +///
> +/// This macro generates the necessary FFI wrappers and glue code to expose
> +/// a specific primitive type (e.g., `u32`, `bool`) to the `debugfs` filesystem.
> +///
> +/// # Type Support
> +///
> +/// Accepts standard integer primitives (`u8` through `u64`, `x8` through `x64`),
> +/// `bool`, and `usize`.
> +///
> +/// # Examples
> +///
> +/// ```rust,ignore
> +/// impl_debugfs_primitive!(u32, create_u32, debugfs_create_u32);
> +/// ```
> +macro_rules! impl_debugfs_primitive {
> + ($type:ty, $fn_name:ident,$c_func:ident) => {
> + impl Dir {
> + /// Creates a debugfs entry for a primitive `$type` value inside this directory.
> + ///
> + /// # Safety
> + ///
> + /// `value` must point to a valid memory location that outlives this directory `Dir`
> + /// (e.g., inside a pinned driver state structure or a `static` location).
> + pub unsafe fn $fn_name(&self, name: &CStr, mode: u16, value: *mut $type) {
> + let parent_ptr = match self.0.as_deref() {
> + Some(entry) => entry.as_ptr(),
> + None => core::ptr::null_mut(),
> + };
> +
> + // SAFETY: `name` is a valid CStr. `parent_ptr` points to a valid parent
> + // dentry or NULL. The caller guarantees that `value` outlives the debugfs node.
> + unsafe {
> + bindings::$c_func(name.as_char_ptr(), mode, parent_ptr, value);
> + }
> + }
> + }
> + };
> +}
> +
> +// Bind native Rust primitive types to their corresponding C debugfs helpers.
> +impl_debugfs_primitive!(u8, create_u8, debugfs_create_u8);
> +impl_debugfs_primitive!(u16, create_u16, debugfs_create_u16);
> +impl_debugfs_primitive!(u32, create_u32, debugfs_create_u32);
> +impl_debugfs_primitive!(u64, create_u64, debugfs_create_u64);
> +impl_debugfs_primitive!(u8, create_x8, debugfs_create_x8);
> +impl_debugfs_primitive!(u16, create_x16, debugfs_create_x16);
> +impl_debugfs_primitive!(u32, create_x32, debugfs_create_x32);
> +impl_debugfs_primitive!(u64, create_x64, debugfs_create_x64);
> +impl_debugfs_primitive!(bool, create_bool, debugfs_create_bool);
> +impl_debugfs_primitive!(usize, create_size_t, debugfs_create_size_t);
> +
> #[pin_data]
> /// Handle to a DebugFS scope, which ensures that attached `data` will outlive the DebugFS entry
> /// without moving.
> diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
> index 77c19a437695..b2ef8c71f7ee 100644
> --- a/samples/rust/rust_debugfs.rs
> +++ b/samples/rust/rust_debugfs.rs
> @@ -34,6 +34,7 @@
> use core::str::FromStr;
> use kernel::{
> acpi,
> + c_str,
> debugfs::{
> Dir,
> File, //
> @@ -79,6 +80,8 @@ struct RustDebugFs {
> array_blob: File<Mutex<[u8; 4]>>,
> #[pin]
> vector_blob: File<Mutex<KVec<u8>>>,
> + #[pin]
> + primitive_values: PrimitiveValues,
> }
>
> #[derive(Debug)]
> @@ -87,6 +90,36 @@ struct Inner {
> y: u32,
> }
>
> +struct PrimitiveValues {
> + u8: u8,
> + u16: u16,
> + u32: u32,
> + u64: u64,
> + x8: u8,
> + x16: u16,
> + x32: u32,
> + x64: u64,
> + size_t: usize,
> + bool: bool,
> +}
> +
> +impl PrimitiveValues {
> + fn new() -> Self {
> + Self {
> + u8: 8,
> + u16: 16,
> + u32: 32,
> + u64: 64,
> + x8: 0x88,
> + x16: 0x1616,
> + x32: 0x32323232,
> + x64: 0x6464646464646464,
> + size_t: 12345678,
> + bool: true,
> + }
> + }
> +}
> +
> impl FromStr for Inner {
> type Err = Error;
> fn from_str(s: &str) -> Result<Self> {
> @@ -171,9 +204,67 @@ fn new<'a, 'b>(
> c"vector_blob",
> new_mutex!(kernel::kvec!(0x42; SZ_4K)?),
> ),
> + primitive_values <- PrimitiveValues::new(),
> _debugfs: debugfs,
> pdev: pdev.into(),
> }
> }
> + .pin_chain(|this| {
> + // SAFETY: primitive values live until the module is dropped
> + unsafe {
> + this._debugfs.create_u8(
> + c_str!("u8"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.u8) as *mut _,
> + );
> + this._debugfs.create_u16(
> + c_str!("u16"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.u16) as *mut _,
> + );
> + this._debugfs.create_u32(
> + c_str!("u32"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.u32) as *mut _,
> + );
> + this._debugfs.create_u64(
> + c_str!("u64"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.u64) as *mut _,
> + );
> + this._debugfs.create_x8(
> + c_str!("x8"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.x8) as *mut _,
> + );
> + this._debugfs.create_x16(
> + c_str!("x16"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.x16) as *mut _,
> + );
> + this._debugfs.create_x32(
> + c_str!("x32"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.x32) as *mut _,
> + );
> + this._debugfs.create_x64(
> + c_str!("x64"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.x64) as *mut _,
> + );
> + this._debugfs.create_bool(
> + c_str!("bool"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.bool) as *mut _,
> + );
> + this._debugfs.create_size_t(
> + c_str!("usize"),
> + 0644,
> + core::ptr::addr_of!(this.primitive_values.size_t) as *mut _,
> + );
> + }
> +
> + Ok(())
> + })
> }
> }
> --
> 2.47.3
© 2016 - 2026 Red Hat, Inc.