From: "Danilo Krummrich" <dakr@kernel.org>
To: "Matthew Maurer" <mmaurer@google.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Sami Tolvanen" <samitolvanen@google.com>,
"Timur Tabi" <ttabi@nvidia.com>,
"Benno Lossin" <lossin@kernel.org>,
"Dirk Beheme" <dirk.behme@de.bosch.com>,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org
Subject: Re: [PATCH v10 3/7] rust: debugfs: Add support for writable files
Date: Tue, 26 Aug 2025 21:38:25 +0200 [thread overview]
Message-ID: <DCCM3G61QPMD.2R4QDAG1U7NCQ@kernel.org> (raw)
In-Reply-To: <20250819-debugfs-rust-v10-3-86e20f3cf3bb@google.com>
On Wed Aug 20, 2025 at 12:53 AM CEST, Matthew Maurer wrote:
> + /// Creates a read-write file in this directory.
> + ///
> + /// Reading the file uses the [`Render`] implementation.
> + /// Writing to the file uses the [`UpdateFromSlice`] implementation.
> + pub fn read_write_file<
> + 'a,
> + T: Render + UpdateFromSlice + Send + Sync + 'static,
> + E: 'a,
> + TI: PinInit<T, E> + 'a,
Same comments as in the previous patch, I think using a where clause is a bit
cleaner, even though with this formatting it'd be fine too, but this is not
guaranteed.
> + >(
> + &'a self,
> + name: &'a CStr,
> + data: TI,
impl PinInit<T, E> + 'a
> + ) -> impl PinInit<File<T>, E> + 'a {
> + let file_ops = &<T as ReadWriteFile<_>>::FILE_OPS;
> + self.create_file(name, data, file_ops)
> + }
> +fn update<T: UpdateFromSlice + Sync>(data: &T, buf: *const c_char, count: usize) -> isize {
> + let mut reader = UserSlice::new(UserPtr::from_ptr(buf as *mut c_void), count).reader();
This naming is pretty close to what I was about to propose for the UpdateFromSlice
trait. :)
Given that I proposed debugfs::Writer instead of debugfs::Render, I think we
should just rename debugfs::UpdateFromSlice to debugfs::Reader.
> +
> + if let Err(e) = data.update_from_slice(&mut reader) {
> + return e.to_errno() as isize;
> + }
> +
> + count as isize
> +}
<snip>
> +/// # Safety
> +///
> +/// `inode` must be a valid pointer to an `inode` struct.
> +/// `file` must be a valid pointer to a `file` struct.
> +unsafe extern "C" fn write_only_open(
> + inode: *mut bindings::inode,
> + file: *mut bindings::file,
> +) -> c_int {
> + // SAFETY: The caller ensures that `inode` and `file` are valid pointers.
> + unsafe {
> + (*file).private_data = (*inode).i_private;
> + }
NIT: If you move the semicolon at the end of the unsafe block it goes into a
single line.
> + 0
> +}
<snip>
> +impl<T: UpdateFromSlice + Sync> WriteFile<T> for T {
> + const FILE_OPS: FileOps<T> = {
> + let operations = bindings::file_operations {
> + open: Some(write_only_open),
> + write: Some(write_only_write::<T>),
> + llseek: Some(bindings::noop_llseek),
> + // SAFETY: `file_operations` supports zeroes in all fields.
> + ..unsafe { core::mem::zeroed() }
> + };
> + // SAFETY:
> + // * `write_only_open` populates the file private data with the inode private data
> + // * `write_only_write`'s only requirement is that the private data of the file point to
> + // a `T` and be legal to convert to a shared reference, which `write_only_open`
> + // satisfies.
> + unsafe { FileOps::new(operations, 0o200) }
I think it'd be nice to have an abstraction for file modes, but this can be done
separately.
> + };
> +}
> diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs
> index 2939e18e3dda39571cd7255505e5f605f0e3d154..d64638898faaa1a6a9898c374b8c1114993376c9 100644
> --- a/rust/kernel/debugfs/traits.rs
> +++ b/rust/kernel/debugfs/traits.rs
> @@ -3,8 +3,15 @@
>
> //! Traits for rendering or updating values exported to DebugFS.
>
> +use crate::prelude::*;
> use crate::sync::Mutex;
> +use crate::uaccess::UserSliceReader;
> use core::fmt::{self, Debug, Formatter};
> +use core::str::FromStr;
> +use core::sync::atomic::{
> + AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64,
> + AtomicU8, AtomicUsize, Ordering,
> +};
>
> /// A trait for types that can be rendered into a string.
> ///
> @@ -26,3 +33,65 @@ fn render(&self, f: &mut Formatter<'_>) -> fmt::Result {
> writeln!(f, "{self:?}")
> }
> }
> +
> +/// A trait for types that can be updated from a user slice.
> +///
> +/// This works similarly to `FromStr`, but operates on a `UserSliceReader` rather than a &str.
> +///
> +/// It is automatically implemented for all atomic integers, or any type that implements `FromStr`
> +/// wrapped in a `Mutex`.
> +pub trait UpdateFromSlice {
As mentioned above, I think we should name this Reader and the Render thing
Writer.
> + /// Updates the value from the given user slice.
> + fn update_from_slice(&self, reader: &mut UserSliceReader) -> Result<()>;
read_from_slice()?
> +}
> +
> +impl<T: FromStr> UpdateFromSlice for Mutex<T> {
> + fn update_from_slice(&self, reader: &mut UserSliceReader) -> Result<()> {
> + let mut buf = [0u8; 128];
> + if reader.len() > buf.len() {
> + return Err(EINVAL);
> + }
> + let n = reader.len();
> + reader.read_slice(&mut buf[..n])?;
> +
> + let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?;
> + let val = s.trim().parse::<T>().map_err(|_| EINVAL)?;
> + *self.lock() = val;
> + Ok(())
> + }
> +}
> +
> +macro_rules! impl_update_from_slice_for_atomic {
> + ($(($atomic_type:ty, $int_type:ty)),*) => {
> + $(
> + impl UpdateFromSlice for $atomic_type {
> + fn update_from_slice(&self, reader: &mut UserSliceReader) -> Result<()> {
> + let mut buf = [0u8; 21]; // Enough for a 64-bit number.
> + if reader.len() > buf.len() {
> + return Err(EINVAL);
> + }
> + let n = reader.len();
> + reader.read_slice(&mut buf[..n])?;
> +
> + let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?;
> + let val = s.trim().parse::<$int_type>().map_err(|_| EINVAL)?;
> + self.store(val, Ordering::Relaxed);
> + Ok(())
> + }
> + }
> + )*
> + };
> +}
> +
> +impl_update_from_slice_for_atomic!(
> + (AtomicI16, i16),
> + (AtomicI32, i32),
> + (AtomicI64, i64),
> + (AtomicI8, i8),
> + (AtomicIsize, isize),
> + (AtomicU16, u16),
> + (AtomicU32, u32),
> + (AtomicU64, u64),
> + (AtomicU8, u8),
> + (AtomicUsize, usize)
> +);
>
> --
> 2.51.0.rc1.167.g924127e9c0-goog
next prev parent reply other threads:[~2025-08-26 19:38 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-19 22:53 [PATCH v10 0/7] rust: DebugFS Bindings Matthew Maurer
2025-08-19 22:53 ` [PATCH v10 1/7] rust: debugfs: Add initial support for directories Matthew Maurer
2025-08-26 15:39 ` Danilo Krummrich
2025-08-19 22:53 ` [PATCH v10 2/7] rust: debugfs: Add support for read-only files Matthew Maurer
2025-08-26 18:45 ` Danilo Krummrich
2025-08-19 22:53 ` [PATCH v10 3/7] rust: debugfs: Add support for writable files Matthew Maurer
2025-08-26 19:38 ` Danilo Krummrich [this message]
2025-08-19 22:53 ` [PATCH v10 4/7] rust: debugfs: Add support for callback-based files Matthew Maurer
2025-08-19 22:53 ` [PATCH v10 5/7] samples: rust: Add debugfs sample driver Matthew Maurer
2025-08-20 0:34 ` Danilo Krummrich
2025-08-20 0:40 ` Matthew Maurer
2025-08-20 0:42 ` Matthew Maurer
2025-08-20 7:46 ` Benno Lossin
2025-08-19 22:53 ` [PATCH v10 6/7] rust: debugfs: Add support for scoped directories Matthew Maurer
2025-08-19 22:53 ` [PATCH v10 7/7] samples: rust: Add scoped debugfs sample driver Matthew Maurer
2025-08-19 23:14 ` [PATCH v10 0/7] rust: DebugFS Bindings Matthew Maurer
2025-08-25 11:51 ` Dirk Behme
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=DCCM3G61QPMD.2R4QDAG1U7NCQ@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dirk.behme@de.bosch.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=mmaurer@google.com \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=samitolvanen@google.com \
--cc=tmgross@umich.edu \
--cc=ttabi@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.