* [PATCH v3 00/10] Binary Large Objects for Rust DebugFS
@ 2025-10-22 14:30 Danilo Krummrich
  2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
                   ` (10 more replies)
  0 siblings, 11 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
This series adds support for exposing binary large objects via Rust debugfs.
The first two patches extend UserSliceReader and UserSliceWriter with partial
read/write helpers.
The series further introduces read_binary_file(), write_binary_file() and
read_write_binary_file() methods for the Dir and ScopedDir types.
It also introduces the BinaryWriter and BinaryReader traits, which are used to
read/write the implementing type's binary representation with the help of the
backing file operations from/to debugfs.
Additional to some more generic blanked implementations for the BinaryWriter and
BinaryReader traits it also provides implementations for common smart pointer
types.
Both samples (file-based and scoped) are updated with corresponding examples.
A branch containing the patches can be found in [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=debugfs_blobs
Changes in v3:
  - Add UserSliceReader::read_slice_file() and
    UserSliceWriter::write_slice_file() taking an &mut file::Offset to
    adjust it internally and make use of them.
  - Add a new type file::Offset, rather than a type alias.
  - Move affected delegate comments to previous patch.
  - Add a brief comment for BinaryReadFile, BinaryWriteFile and
    BinaryReadWriteFile.
Changes in v2:
  - Add file::Offset type alias.
  - uaccess:
    - Saturate at buffer length on offset overflow.
    - Use file::Offset instead of usize.
  - debugfs:
    - Use file::Offset instead of usize.
    - Handle potential overflow when updating ppos.
    - Use &T::FILE_OPS directly if possible.
    - Fix safety comment in BinaryReaderMut::read_from_slice_mut().
Danilo Krummrich (10):
  rust: fs: add new type file::Offset
  rust: uaccess: add UserSliceReader::read_slice_partial()
  rust: uaccess: add UserSliceReader::read_slice_file()
  rust: uaccess: add UserSliceWriter::write_slice_partial()
  rust: uaccess: add UserSliceWriter::write_slice_file()
  rust: debugfs: support for binary large objects
  rust: debugfs: support blobs from smart pointers
  samples: rust: debugfs: add example for blobs
  rust: debugfs: support binary large objects for ScopedDir
  samples: rust: debugfs_scoped: add example for blobs
 rust/kernel/debugfs.rs              | 110 ++++++++++++-
 rust/kernel/debugfs/file_ops.rs     | 146 ++++++++++++++++-
 rust/kernel/debugfs/traits.rs       | 238 +++++++++++++++++++++++++++-
 rust/kernel/fs/file.rs              | 142 ++++++++++++++++-
 rust/kernel/uaccess.rs              |  81 ++++++++++
 samples/rust/rust_debugfs.rs        |  13 ++
 samples/rust/rust_debugfs_scoped.rs |  14 +-
 7 files changed, 732 insertions(+), 12 deletions(-)
base-commit: e6901808a3b28d8bdabfa98a618b2eab6f8798e8
-- 
2.51.0
^ permalink raw reply	[flat|nested] 39+ messages in thread
* [PATCH v3 01/10] rust: fs: add new type file::Offset
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-22 14:42   ` Miguel Ojeda
                     ` (3 more replies)
  2025-10-22 14:30 ` [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial() Danilo Krummrich
                   ` (9 subsequent siblings)
  10 siblings, 4 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich,
	Alexander Viro, Christian Brauner, Jan Kara
Add a new type for file offsets, i.e. bindings::loff_t. Trying to avoid
using raw bindings types, this seems to be the better alternative
compared to just using i64.
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/fs/file.rs | 142 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 141 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index cf06e73a6da0..681b8a9e5d52 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -15,7 +15,147 @@
     sync::aref::{ARef, AlwaysRefCounted},
     types::{NotThreadSafe, Opaque},
 };
-use core::ptr;
+use core::{num::TryFromIntError, ptr};
+
+/// Representation of an offset within a [`File`].
+///
+/// Transparent wrapper around `bindings::loff_t`.
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
+pub struct Offset(bindings::loff_t);
+
+impl Offset {
+    /// The largest value that can be represented by this type.
+    pub const MAX: Self = Self(bindings::loff_t::MAX);
+
+    /// The smallest value that can be represented by this type.
+    pub const MIN: Self = Self(bindings::loff_t::MIN);
+
+    /// Create a mutable [`Offset`] reference from the raw `*mut bindings::loff_t`.
+    ///
+    /// # Safety
+    ///
+    /// - `offset` must be a valid pointer to a `bindings::loff_t`.
+    /// - The caller must guarantee exclusive access to `offset`.
+    #[inline]
+    pub const unsafe fn from_raw<'a>(offset: *mut bindings::loff_t) -> &'a mut Self {
+        // SAFETY: By the safety requirements of this function
+        // - `offset` is a valid pointer to a `bindings::loff_t`,
+        // - we have exclusive access to `offset`.
+        unsafe { &mut *offset.cast() }
+    }
+
+    /// Returns `true` if the [`Offset`] is negative.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use kernel::fs::file::Offset;
+    ///
+    /// let offset = Offset::from(1);
+    /// assert!(!offset.is_negative());
+    ///
+    /// let offset = Offset::from(-1);
+    /// assert!(offset.is_negative());
+    /// ```
+    #[inline]
+    pub const fn is_negative(self) -> bool {
+        self.0.is_negative()
+    }
+
+    /// Saturating addition with another [`Offset`].
+    #[inline]
+    pub fn saturating_add(self, rhs: Offset) -> Offset {
+        Self(self.0.saturating_add(rhs.0))
+    }
+
+    /// Saturating addition with a [`usize`].
+    ///
+    /// If the [`usize`] fits in `bindings::loff_t` it is converted and added; otherwise the result
+    /// saturates to [`Offset::MAX`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use kernel::fs::file::Offset;
+    ///
+    /// let offset = Offset::from(40);
+    ///
+    /// let offset = offset.saturating_add_usize(2);
+    /// assert_eq!(offset, Offset::from(42));
+    ///
+    /// let offset = Offset::MAX.saturating_sub_usize(1);
+    /// let offset = offset.saturating_add_usize(usize::MAX);
+    /// assert_eq!(offset, Offset::MAX);
+    /// ```
+    pub fn saturating_add_usize(self, rhs: usize) -> Offset {
+        match bindings::loff_t::try_from(rhs) {
+            Ok(rhs_loff) => Self(self.0.saturating_add(rhs_loff)),
+            Err(_) => Self::MAX,
+        }
+    }
+
+    /// Saturating subtraction with another [`Offset`].
+    #[inline]
+    pub fn saturating_sub(self, rhs: Offset) -> Offset {
+        Offset(self.0.saturating_sub(rhs.0))
+    }
+
+    /// Saturating subtraction with a [`usize`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use kernel::fs::file::Offset;
+    ///
+    /// let offset = Offset::from(100);
+    /// let offset = offset.saturating_sub_usize(58);
+    /// assert_eq!(offset, Offset::from(42));
+    ///
+    /// let offset = Offset::MIN.saturating_add_usize(1);
+    /// let offset = offset.saturating_sub_usize(usize::MAX);
+    /// assert_eq!(offset, Offset::MIN);
+    /// ```
+    #[inline]
+    pub fn saturating_sub_usize(self, rhs: usize) -> Offset {
+        match bindings::loff_t::try_from(rhs) {
+            Ok(rhs_loff) => Offset(self.0.saturating_sub(rhs_loff)),
+            Err(_) => Self::MIN,
+        }
+    }
+}
+
+impl From<bindings::loff_t> for Offset {
+    #[inline]
+    fn from(v: bindings::loff_t) -> Self {
+        Self(v)
+    }
+}
+
+impl From<Offset> for bindings::loff_t {
+    #[inline]
+    fn from(offset: Offset) -> Self {
+        offset.0
+    }
+}
+
+impl TryFrom<usize> for Offset {
+    type Error = TryFromIntError;
+
+    #[inline]
+    fn try_from(u: usize) -> Result<Self, Self::Error> {
+        Ok(Self(bindings::loff_t::try_from(u)?))
+    }
+}
+
+impl TryFrom<Offset> for usize {
+    type Error = TryFromIntError;
+
+    #[inline]
+    fn try_from(offset: Offset) -> Result<Self, Self::Error> {
+        usize::try_from(offset.0)
+    }
+}
 
 /// Flags associated with a [`File`].
 pub mod flags {
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial()
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
  2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-24 10:39   ` Alice Ryhl
  2025-11-01 14:16   ` Alexandre Courbot
  2025-10-22 14:30 ` [PATCH v3 03/10] rust: uaccess: add UserSliceReader::read_slice_file() Danilo Krummrich
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
The existing read_slice() method is a wrapper around copy_from_user()
and expects the user buffer to be larger than the destination buffer.
However, userspace may split up writes in multiple partial operations
providing an offset into the destination buffer and a smaller user
buffer.
In order to support this common case, provide a helper for partial
reads.
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Matthew Maurer <mmaurer@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/uaccess.rs | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index a8fb4764185a..c1cd3a76cff8 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -287,6 +287,22 @@ pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
         self.read_raw(out)
     }
 
+    /// Reads raw data from the user slice into a kernel buffer partially.
+    ///
+    /// This is the same as [`Self::read_slice`] but considers the given `offset` into `out` and
+    /// truncates the read to the boundaries of `self` and `out`.
+    ///
+    /// On success, returns the number of bytes read.
+    pub fn read_slice_partial(&mut self, out: &mut [u8], offset: usize) -> Result<usize> {
+        let end = offset
+            .checked_add(self.len())
+            .unwrap_or(out.len())
+            .min(out.len());
+
+        out.get_mut(offset..end)
+            .map_or(Ok(0), |dst| self.read_slice(dst).map(|()| dst.len()))
+    }
+
     /// Reads a value of the specified type.
     ///
     /// Fails with [`EFAULT`] if the read happens on a bad address, or if the read goes out of
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 03/10] rust: uaccess: add UserSliceReader::read_slice_file()
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
  2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
  2025-10-22 14:30 ` [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial() Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-11-01 14:16   ` Alexandre Courbot
  2025-10-22 14:30 ` [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial() Danilo Krummrich
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
Add UserSliceReader::read_slice_file(), which is the same as
UserSliceReader::read_slice_partial() but updates the given file::Offset
by the number of bytes read.
This is equivalent to C's `simple_write_to_buffer()` and useful when
dealing with file offsets from file operations.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/uaccess.rs | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index c1cd3a76cff8..c2d3dfee8934 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -9,6 +9,7 @@
     bindings,
     error::Result,
     ffi::{c_char, c_void},
+    fs::file,
     prelude::*,
     transmute::{AsBytes, FromBytes},
 };
@@ -303,6 +304,30 @@ pub fn read_slice_partial(&mut self, out: &mut [u8], offset: usize) -> Result<us
             .map_or(Ok(0), |dst| self.read_slice(dst).map(|()| dst.len()))
     }
 
+    /// Reads raw data from the user slice into a kernel buffer partially.
+    ///
+    /// This is the same as [`Self::read_slice_partial`] but updates the given [`file::Offset`] by
+    /// the number of bytes read.
+    ///
+    /// This is equivalent to C's `simple_write_to_buffer()`.
+    ///
+    /// On success, returns the number of bytes read.
+    pub fn read_slice_file(&mut self, out: &mut [u8], offset: &mut file::Offset) -> Result<usize> {
+        if offset.is_negative() {
+            return Err(EINVAL);
+        }
+
+        let Ok(offset_index) = (*offset).try_into() else {
+            return Ok(0);
+        };
+
+        let read = self.read_slice_partial(out, offset_index)?;
+
+        *offset = offset.saturating_add_usize(read);
+
+        Ok(read)
+    }
+
     /// Reads a value of the specified type.
     ///
     /// Fails with [`EFAULT`] if the read happens on a bad address, or if the read goes out of
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial()
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (2 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 03/10] rust: uaccess: add UserSliceReader::read_slice_file() Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-23  8:33   ` Alice Ryhl
  2025-11-01 14:19   ` Alexandre Courbot
  2025-10-22 14:30 ` [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file() Danilo Krummrich
                   ` (6 subsequent siblings)
  10 siblings, 2 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
The existing write_slice() method is a wrapper around copy_to_user() and
expects the user buffer to be larger than the source buffer.
However, userspace may split up reads in multiple partial operations
providing an offset into the source buffer and a smaller user buffer.
In order to support this common case, provide a helper for partial
writes.
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Matthew Maurer <mmaurer@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/uaccess.rs | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index c2d3dfee8934..539e77a09cbc 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -479,6 +479,22 @@ pub fn write_slice(&mut self, data: &[u8]) -> Result {
         Ok(())
     }
 
+    /// Writes raw data to this user pointer from a kernel buffer partially.
+    ///
+    /// This is the same as [`Self::write_slice`] but considers the given `offset` into `data` and
+    /// truncates the write to the boundaries of `self` and `data`.
+    ///
+    /// On success, returns the number of bytes written.
+    pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usize> {
+        let end = offset
+            .checked_add(self.len())
+            .unwrap_or(data.len())
+            .min(data.len());
+
+        data.get(offset..end)
+            .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
+    }
+
     /// Writes the provided Rust value to this userspace pointer.
     ///
     /// Fails with [`EFAULT`] if the write happens on a bad address, or if the write goes out of
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (3 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial() Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-23  8:30   ` Alice Ryhl
  2025-10-28 14:07   ` Miguel Ojeda
  2025-10-22 14:30 ` [PATCH v3 06/10] rust: debugfs: support for binary large objects Danilo Krummrich
                   ` (5 subsequent siblings)
  10 siblings, 2 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
Add UserSliceWriter::write_slice_file(), which is the same as
UserSliceWriter::write_slice_partial() but updates the given
file::Offset by the number of bytes written.
This is equivalent to C's `simple_read_from_buffer()` and useful when
dealing with file offsets from file operations.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/uaccess.rs | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 539e77a09cbc..20ea31781efb 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -495,6 +495,30 @@ pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usiz
             .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
     }
 
+    /// Writes raw data to this user pointer from a kernel buffer partially.
+    ///
+    /// This is the same as [`Self::write_slice_partial`] but updates the given [`file::Offset`] by
+    /// the number of bytes written.
+    ///
+    /// This is equivalent to C's `simple_read_from_buffer()`.
+    ///
+    /// On success, returns the number of bytes written.
+    pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Result<usize> {
+        if offset.is_negative() {
+            return Err(EINVAL);
+        }
+
+        let Ok(offset_index) = (*offset).try_into() else {
+            return Ok(0);
+        };
+
+        let written = self.write_slice_partial(data, offset_index)?;
+
+        *offset = offset.saturating_add_usize(written);
+
+        Ok(written)
+    }
+
     /// Writes the provided Rust value to this userspace pointer.
     ///
     /// Fails with [`EFAULT`] if the write happens on a bad address, or if the write goes out of
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 06/10] rust: debugfs: support for binary large objects
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (4 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file() Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-23  8:26   ` Alice Ryhl
  2025-10-22 14:30 ` [PATCH v3 07/10] rust: debugfs: support blobs from smart pointers Danilo Krummrich
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
Introduce support for read-only, write-only, and read-write binary files
in Rust debugfs. This adds:
- BinaryWriter and BinaryReader traits for writing to and reading from
  user slices in binary form.
- New Dir methods: read_binary_file(), write_binary_file(),
  `read_write_binary_file`.
- Corresponding FileOps implementations: BinaryReadFile,
  BinaryWriteFile, BinaryReadWriteFile.
This allows kernel modules to expose arbitrary binary data through
debugfs, with proper support for offsets and partial reads/writes.
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Matthew Maurer <mmaurer@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/debugfs.rs          |  66 ++++++++++++++-
 rust/kernel/debugfs/file_ops.rs | 146 +++++++++++++++++++++++++++++++-
 rust/kernel/debugfs/traits.rs   |  68 ++++++++++++++-
 3 files changed, 273 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index 381c23b3dd83..95cd3376ecbe 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -21,12 +21,15 @@
 use core::ops::Deref;
 
 mod traits;
-pub use traits::{Reader, Writer};
+pub use traits::{BinaryReader, BinaryWriter, Reader, Writer};
 
 mod callback_adapters;
 use callback_adapters::{FormatAdapter, NoWriter, WritableAdapter};
 mod file_ops;
-use file_ops::{FileOps, ReadFile, ReadWriteFile, WriteFile};
+use file_ops::{
+    BinaryReadFile, BinaryReadWriteFile, BinaryWriteFile, FileOps, ReadFile, ReadWriteFile,
+    WriteFile,
+};
 #[cfg(CONFIG_DEBUG_FS)]
 mod entry;
 #[cfg(CONFIG_DEBUG_FS)]
@@ -150,6 +153,32 @@ pub fn read_only_file<'a, T, E: 'a>(
         self.create_file(name, data, file_ops)
     }
 
+    /// Creates a read-only binary file in this directory.
+    ///
+    /// The file's contents are produced by invoking [`BinaryWriter::write_to_slice`] on the value
+    /// initialized by `data`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::debugfs::Dir;
+    /// # use kernel::prelude::*;
+    /// # let dir = Dir::new(c_str!("my_debugfs_dir"));
+    /// let file = KBox::pin_init(dir.read_binary_file(c_str!("foo"), [0x1, 0x2]), GFP_KERNEL)?;
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn read_binary_file<'a, T, E: 'a>(
+        &'a self,
+        name: &'a CStr,
+        data: impl PinInit<T, E> + 'a,
+    ) -> impl PinInit<File<T>, E> + 'a
+    where
+        T: BinaryWriter + Send + Sync + 'static,
+    {
+        self.create_file(name, data, &T::FILE_OPS)
+    }
+
     /// Creates a read-only file in this directory, with contents from a callback.
     ///
     /// `f` must be a function item or a non-capturing closure.
@@ -206,6 +235,22 @@ pub fn read_write_file<'a, T, E: 'a>(
         self.create_file(name, data, file_ops)
     }
 
+    /// Creates a read-write binary file in this directory.
+    ///
+    /// Reading the file uses the [`BinaryWriter`] implementation.
+    /// Writing to the file uses the [`BinaryReader`] implementation.
+    pub fn read_write_binary_file<'a, T, E: 'a>(
+        &'a self,
+        name: &'a CStr,
+        data: impl PinInit<T, E> + 'a,
+    ) -> impl PinInit<File<T>, E> + 'a
+    where
+        T: BinaryWriter + BinaryReader + Send + Sync + 'static,
+    {
+        let file_ops = &<T as BinaryReadWriteFile<_>>::FILE_OPS;
+        self.create_file(name, data, file_ops)
+    }
+
     /// Creates a read-write file in this directory, with logic from callbacks.
     ///
     /// Reading from the file is handled by `f`. Writing to the file is handled by `w`.
@@ -248,6 +293,23 @@ pub fn write_only_file<'a, T, E: 'a>(
         self.create_file(name, data, &T::FILE_OPS)
     }
 
+    /// Creates a write-only binary file in this directory.
+    ///
+    /// The file owns its backing data. Writing to the file uses the [`BinaryReader`]
+    /// implementation.
+    ///
+    /// The file is removed when the returned [`File`] is dropped.
+    pub fn write_binary_file<'a, T, E: 'a>(
+        &'a self,
+        name: &'a CStr,
+        data: impl PinInit<T, E> + 'a,
+    ) -> impl PinInit<File<T>, E> + 'a
+    where
+        T: BinaryReader + Send + Sync + 'static,
+    {
+        self.create_file(name, data, &T::FILE_OPS)
+    }
+
     /// Creates a write-only file in this directory, with write logic from a callback.
     ///
     /// `w` must be a function item or a non-capturing closure.
diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs
index 50fead17b6f3..ebdd2427d2ce 100644
--- a/rust/kernel/debugfs/file_ops.rs
+++ b/rust/kernel/debugfs/file_ops.rs
@@ -1,13 +1,14 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (C) 2025 Google LLC.
 
-use super::{Reader, Writer};
+use super::{BinaryReader, BinaryWriter, Reader, Writer};
 use crate::debugfs::callback_adapters::Adapter;
+use crate::fs::file;
 use crate::prelude::*;
 use crate::seq_file::SeqFile;
 use crate::seq_print;
 use crate::uaccess::UserSlice;
-use core::fmt::{Display, Formatter, Result};
+use core::fmt;
 use core::marker::PhantomData;
 
 #[cfg(CONFIG_DEBUG_FS)]
@@ -65,8 +66,8 @@ fn deref(&self) -> &Self::Target {
 
 struct WriterAdapter<T>(T);
 
-impl<'a, T: Writer> Display for WriterAdapter<&'a T> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+impl<'a, T: Writer> fmt::Display for WriterAdapter<&'a T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.write(f)
     }
 }
@@ -245,3 +246,140 @@ impl<T: Reader + Sync> WriteFile<T> for T {
         unsafe { FileOps::new(operations, 0o200) }
     };
 }
+
+extern "C" fn blob_read<T: BinaryWriter>(
+    file: *mut bindings::file,
+    buf: *mut c_char,
+    count: usize,
+    ppos: *mut bindings::loff_t,
+) -> isize {
+    // SAFETY:
+    // - `file` is a valid pointer to a `struct file`.
+    // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`.
+    let this = unsafe { &*((*file).private_data.cast::<T>()) };
+
+    // SAFETY:
+    // `ppos` is a valid `file::Offset` pointer.
+    // We have exclusive access to `ppos`.
+    let pos = unsafe { file::Offset::from_raw(ppos) };
+
+    let mut writer = UserSlice::new(UserPtr::from_ptr(buf.cast()), count).writer();
+
+    let ret = || -> Result<isize> {
+        let written = this.write_to_slice(&mut writer, pos)?;
+
+        Ok(written.try_into()?)
+    }();
+
+    match ret {
+        Ok(n) => n,
+        Err(e) => e.to_errno() as isize,
+    }
+}
+
+/// Representation of [`FileOps`] for read only binary files.
+pub(crate) trait BinaryReadFile<T> {
+    const FILE_OPS: FileOps<T>;
+}
+
+impl<T: BinaryWriter + Sync> BinaryReadFile<T> for T {
+    const FILE_OPS: FileOps<T> = {
+        let operations = bindings::file_operations {
+            read: Some(blob_read::<T>),
+            llseek: Some(bindings::default_llseek),
+            open: Some(bindings::simple_open),
+            // SAFETY: `file_operations` supports zeroes in all fields.
+            ..unsafe { core::mem::zeroed() }
+        };
+
+        // SAFETY:
+        // - The private data of `struct inode` does always contain a pointer to a valid `T`.
+        // - `simple_open()` stores the `struct inode`'s private data in the private data of the
+        //   corresponding `struct file`.
+        // - `blob_read()` re-creates a reference to `T` from the `struct file`'s private data.
+        // - `default_llseek()` does not access the `struct file`'s private data.
+        unsafe { FileOps::new(operations, 0o400) }
+    };
+}
+
+extern "C" fn blob_write<T: BinaryReader>(
+    file: *mut bindings::file,
+    buf: *const c_char,
+    count: usize,
+    ppos: *mut bindings::loff_t,
+) -> isize {
+    // SAFETY:
+    // - `file` is a valid pointer to a `struct file`.
+    // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`.
+    let this = unsafe { &*((*file).private_data.cast::<T>()) };
+
+    // SAFETY:
+    // `ppos` is a valid `file::Offset` pointer.
+    // We have exclusive access to `ppos`.
+    let pos = unsafe { file::Offset::from_raw(ppos) };
+
+    let mut reader = UserSlice::new(UserPtr::from_ptr(buf.cast_mut().cast()), count).reader();
+
+    let ret = || -> Result<isize> {
+        let read = this.read_from_slice(&mut reader, pos)?;
+
+        Ok(read.try_into()?)
+    }();
+
+    match ret {
+        Ok(n) => n,
+        Err(e) => e.to_errno() as isize,
+    }
+}
+
+/// Representation of [`FileOps`] for write only binary files.
+pub(crate) trait BinaryWriteFile<T> {
+    const FILE_OPS: FileOps<T>;
+}
+
+impl<T: BinaryReader + Sync> BinaryWriteFile<T> for T {
+    const FILE_OPS: FileOps<T> = {
+        let operations = bindings::file_operations {
+            write: Some(blob_write::<T>),
+            llseek: Some(bindings::default_llseek),
+            open: Some(bindings::simple_open),
+            // SAFETY: `file_operations` supports zeroes in all fields.
+            ..unsafe { core::mem::zeroed() }
+        };
+
+        // SAFETY:
+        // - The private data of `struct inode` does always contain a pointer to a valid `T`.
+        // - `simple_open()` stores the `struct inode`'s private data in the private data of the
+        //   corresponding `struct file`.
+        // - `blob_write()` re-creates a reference to `T` from the `struct file`'s private data.
+        // - `default_llseek()` does not access the `struct file`'s private data.
+        unsafe { FileOps::new(operations, 0o200) }
+    };
+}
+
+/// Representation of [`FileOps`] for read/write binary files.
+pub(crate) trait BinaryReadWriteFile<T> {
+    const FILE_OPS: FileOps<T>;
+}
+
+impl<T: BinaryWriter + BinaryReader + Sync> BinaryReadWriteFile<T> for T {
+    const FILE_OPS: FileOps<T> = {
+        let operations = bindings::file_operations {
+            read: Some(blob_read::<T>),
+            write: Some(blob_write::<T>),
+            llseek: Some(bindings::default_llseek),
+            open: Some(bindings::simple_open),
+            // SAFETY: `file_operations` supports zeroes in all fields.
+            ..unsafe { core::mem::zeroed() }
+        };
+
+        // SAFETY:
+        // - The private data of `struct inode` does always contain a pointer to a valid `T`.
+        // - `simple_open()` stores the `struct inode`'s private data in the private data of the
+        //   corresponding `struct file`.
+        // - `blob_read()` re-creates a reference to `T` from the `struct file`'s private data.
+        // - `blob_write()` re-creates a reference to `T` from the `struct file`'s private data.
+        // - `default_llseek()` does not access the `struct file`'s private data.
+        unsafe { FileOps::new(operations, 0o600) }
+    };
+}
diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs
index ab009eb254b3..bd38eb988d51 100644
--- a/rust/kernel/debugfs/traits.rs
+++ b/rust/kernel/debugfs/traits.rs
@@ -3,9 +3,11 @@
 
 //! Traits for rendering or updating values exported to DebugFS.
 
+use crate::fs::file;
 use crate::prelude::*;
 use crate::sync::Mutex;
-use crate::uaccess::UserSliceReader;
+use crate::transmute::{AsBytes, FromBytes};
+use crate::uaccess::{UserSliceReader, UserSliceWriter};
 use core::fmt::{self, Debug, Formatter};
 use core::str::FromStr;
 use core::sync::atomic::{
@@ -39,6 +41,44 @@ fn write(&self, f: &mut Formatter<'_>) -> fmt::Result {
     }
 }
 
+/// Trait for types that can be written out as binary.
+pub trait BinaryWriter {
+    /// Writes the binary form of `self` into `writer`.
+    ///
+    /// `offset` is the requested offset into the binary representation of `self`.
+    ///
+    /// On success, returns the number of bytes written in to `writer`.
+    fn write_to_slice(
+        &self,
+        writer: &mut UserSliceWriter,
+        offset: &mut file::Offset,
+    ) -> Result<usize>;
+}
+
+// Base implementation for any `T: AsBytes`.
+impl<T: AsBytes> BinaryWriter for T {
+    fn write_to_slice(
+        &self,
+        writer: &mut UserSliceWriter,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        writer.write_slice_file(self.as_bytes(), offset)
+    }
+}
+
+// Delegate for `Mutex<T>`: Support a `T` with an outer mutex.
+impl<T: BinaryWriter> BinaryWriter for Mutex<T> {
+    fn write_to_slice(
+        &self,
+        writer: &mut UserSliceWriter,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        let guard = self.lock();
+
+        guard.write_to_slice(writer, offset)
+    }
+}
+
 /// 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.
@@ -66,6 +106,32 @@ fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
     }
 }
 
+/// Trait for types that can be constructed from a binary representation.
+pub trait BinaryReader {
+    /// Reads the binary form of `self` from `reader`.
+    ///
+    /// `offset` is the requested offset into the binary representation of `self`.
+    ///
+    /// On success, returns the number of bytes read from `reader`.
+    fn read_from_slice(
+        &self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize>;
+}
+
+impl<T: AsBytes + FromBytes> BinaryReader for Mutex<T> {
+    fn read_from_slice(
+        &self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        let mut this = self.lock();
+
+        reader.read_slice_file(this.as_bytes_mut(), offset)
+    }
+}
+
 macro_rules! impl_reader_for_atomic {
     ($(($atomic_type:ty, $int_type:ty)),*) => {
         $(
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 07/10] rust: debugfs: support blobs from smart pointers
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (5 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 06/10] rust: debugfs: support for binary large objects Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-23  8:24   ` Alice Ryhl
  2025-10-22 14:30 ` [PATCH v3 08/10] samples: rust: debugfs: add example for blobs Danilo Krummrich
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
Extend Rust debugfs binary support to allow exposing data stored in
common smart pointers and heap-allocated collections.
- Implement BinaryWriter for Box<T>, Pin<Box<T>>, Arc<T>, and Vec<T>.
- Introduce BinaryReaderMut for mutable binary access with outer locks.
- Implement BinaryReaderMut for Box<T>, Vec<T>, and base types.
- Update BinaryReader to delegate to BinaryReaderMut for Mutex<T>,
  Box<T>, Pin<Box<T>> and Arc<T>.
This enables debugfs files to directly expose or update data stored
inside heap-allocated, reference-counted, or lock-protected containers
without manual dereferencing or locking.
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Matthew Maurer <mmaurer@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/debugfs.rs        |   2 +-
 rust/kernel/debugfs/traits.rs | 174 +++++++++++++++++++++++++++++++++-
 2 files changed, 173 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index 95cd3376ecbe..d2bc7550d81e 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -21,7 +21,7 @@
 use core::ops::Deref;
 
 mod traits;
-pub use traits::{BinaryReader, BinaryWriter, Reader, Writer};
+pub use traits::{BinaryReader, BinaryReaderMut, BinaryWriter, Reader, Writer};
 
 mod callback_adapters;
 use callback_adapters::{FormatAdapter, NoWriter, WritableAdapter};
diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs
index bd38eb988d51..2c32ddf9826f 100644
--- a/rust/kernel/debugfs/traits.rs
+++ b/rust/kernel/debugfs/traits.rs
@@ -3,12 +3,15 @@
 
 //! Traits for rendering or updating values exported to DebugFS.
 
+use crate::alloc::Allocator;
 use crate::fs::file;
 use crate::prelude::*;
+use crate::sync::Arc;
 use crate::sync::Mutex;
 use crate::transmute::{AsBytes, FromBytes};
 use crate::uaccess::{UserSliceReader, UserSliceWriter};
 use core::fmt::{self, Debug, Formatter};
+use core::ops::{Deref, DerefMut};
 use core::str::FromStr;
 use core::sync::atomic::{
     AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64,
@@ -79,6 +82,72 @@ fn write_to_slice(
     }
 }
 
+// Delegate for `Box<T, A>`: Support a `Box<T, A>` with no lock or an inner lock.
+impl<T, A> BinaryWriter for Box<T, A>
+where
+    T: BinaryWriter,
+    A: Allocator,
+{
+    fn write_to_slice(
+        &self,
+        writer: &mut UserSliceWriter,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        self.deref().write_to_slice(writer, offset)
+    }
+}
+
+// Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with no lock or an inner lock.
+impl<T, A> BinaryWriter for Pin<Box<T, A>>
+where
+    T: BinaryWriter,
+    A: Allocator,
+{
+    fn write_to_slice(
+        &self,
+        writer: &mut UserSliceWriter,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        self.deref().write_to_slice(writer, offset)
+    }
+}
+
+// Delegate for `Arc<T>`: Support a `Arc<T>` with no lock or an inner lock.
+impl<T> BinaryWriter for Arc<T>
+where
+    T: BinaryWriter,
+{
+    fn write_to_slice(
+        &self,
+        writer: &mut UserSliceWriter,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        self.deref().write_to_slice(writer, offset)
+    }
+}
+
+// Delegate for `Vec<T, A>`.
+impl<T, A> BinaryWriter for Vec<T, A>
+where
+    T: AsBytes,
+    A: Allocator,
+{
+    fn write_to_slice(
+        &self,
+        writer: &mut UserSliceWriter,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        let slice = self.as_slice();
+
+        // SAFETY: `T: AsBytes` allows us to treat `&[T]` as `&[u8]`.
+        let buffer = unsafe {
+            core::slice::from_raw_parts(slice.as_ptr().cast(), core::mem::size_of_val(slice))
+        };
+
+        writer.write_slice_file(buffer, offset)
+    }
+}
+
 /// 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.
@@ -107,6 +176,73 @@ fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
 }
 
 /// Trait for types that can be constructed from a binary representation.
+///
+/// See also [`BinaryReader`] for interior mutability.
+pub trait BinaryReaderMut {
+    /// Reads the binary form of `self` from `reader`.
+    ///
+    /// Same as [`BinaryReader::read_from_slice`], but takes a mutable reference.
+    ///
+    /// `offset` is the requested offset into the binary representation of `self`.
+    ///
+    /// On success, returns the number of bytes read from `reader`.
+    fn read_from_slice_mut(
+        &mut self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize>;
+}
+
+// Base implementation for any `T: AsBytes + FromBytes`.
+impl<T: AsBytes + FromBytes> BinaryReaderMut for T {
+    fn read_from_slice_mut(
+        &mut self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        reader.read_slice_file(self.as_bytes_mut(), offset)
+    }
+}
+
+// Delegate for `Box<T, A>`: Support a `Box<T, A>` with an outer lock.
+impl<T: ?Sized + BinaryReaderMut, A: Allocator> BinaryReaderMut for Box<T, A> {
+    fn read_from_slice_mut(
+        &mut self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        self.deref_mut().read_from_slice_mut(reader, offset)
+    }
+}
+
+// Delegate for `Vec<T, A>`: Support a `Vec<T, A>` with an outer lock.
+impl<T, A> BinaryReaderMut for Vec<T, A>
+where
+    T: AsBytes + FromBytes,
+    A: Allocator,
+{
+    fn read_from_slice_mut(
+        &mut self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        let slice = self.as_mut_slice();
+
+        // SAFETY: `T: AsBytes + FromBytes` allows us to treat `&mut [T]` as `&mut [u8]`.
+        let buffer = unsafe {
+            core::slice::from_raw_parts_mut(
+                slice.as_mut_ptr().cast(),
+                core::mem::size_of_val(slice),
+            )
+        };
+
+        reader.read_slice_file(buffer, offset)
+    }
+}
+
+/// Trait for types that can be constructed from a binary representation.
+///
+/// See also [`BinaryReaderMut`] for the mutable version.
 pub trait BinaryReader {
     /// Reads the binary form of `self` from `reader`.
     ///
@@ -120,7 +256,8 @@ fn read_from_slice(
     ) -> Result<usize>;
 }
 
-impl<T: AsBytes + FromBytes> BinaryReader for Mutex<T> {
+// Delegate for `Mutex<T>`: Support a `T` with an outer `Mutex`.
+impl<T: BinaryReaderMut> BinaryReader for Mutex<T> {
     fn read_from_slice(
         &self,
         reader: &mut UserSliceReader,
@@ -128,7 +265,40 @@ fn read_from_slice(
     ) -> Result<usize> {
         let mut this = self.lock();
 
-        reader.read_slice_file(this.as_bytes_mut(), offset)
+        this.read_from_slice_mut(reader, offset)
+    }
+}
+
+// Delegate for `Box<T, A>`: Support a `Box<T, A>` with an inner lock.
+impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Box<T, A> {
+    fn read_from_slice(
+        &self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        self.deref().read_from_slice(reader, offset)
+    }
+}
+
+// Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with an inner lock.
+impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Pin<Box<T, A>> {
+    fn read_from_slice(
+        &self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        self.deref().read_from_slice(reader, offset)
+    }
+}
+
+// Delegate for `Arc<T>`: Support an `Arc<T>` with an inner lock.
+impl<T: ?Sized + BinaryReader> BinaryReader for Arc<T> {
+    fn read_from_slice(
+        &self,
+        reader: &mut UserSliceReader,
+        offset: &mut file::Offset,
+    ) -> Result<usize> {
+        self.deref().read_from_slice(reader, offset)
     }
 }
 
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 08/10] samples: rust: debugfs: add example for blobs
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (6 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 07/10] rust: debugfs: support blobs from smart pointers Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-22 14:30 ` [PATCH v3 09/10] rust: debugfs: support binary large objects for ScopedDir Danilo Krummrich
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
Extend the Rust debugfs sample to demonstrate usage of binary file
support. The example now shows how to expose both fixed-size arrays
and dynamically sized vectors as binary blobs in debugfs.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Matthew Maurer <mmaurer@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 samples/rust/rust_debugfs.rs | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
index 82b61a15a34b..75ceb95276fa 100644
--- a/samples/rust/rust_debugfs.rs
+++ b/samples/rust/rust_debugfs.rs
@@ -38,6 +38,7 @@
 use kernel::debugfs::{Dir, File};
 use kernel::new_mutex;
 use kernel::prelude::*;
+use kernel::sizes::*;
 use kernel::sync::Mutex;
 
 use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef};
@@ -62,6 +63,10 @@ struct RustDebugFs {
     counter: File<AtomicUsize>,
     #[pin]
     inner: File<Mutex<Inner>>,
+    #[pin]
+    array_blob: File<Mutex<[u8; 4]>>,
+    #[pin]
+    vector_blob: File<Mutex<KVec<u8>>>,
 }
 
 #[derive(Debug)]
@@ -143,6 +148,14 @@ fn new(pdev: &platform::Device<Core>) -> impl PinInit<Self, Error> + '_ {
                 ),
                 counter <- Self::build_counter(&debugfs),
                 inner <- Self::build_inner(&debugfs),
+                array_blob <- debugfs.read_write_binary_file(
+                    c_str!("array_blob"),
+                    new_mutex!([0x62, 0x6c, 0x6f, 0x62]),
+                ),
+                vector_blob <- debugfs.read_write_binary_file(
+                    c_str!("vector_blob"),
+                    new_mutex!(kernel::kvec!(0x42; SZ_4K)?),
+                ),
                 _debugfs: debugfs,
                 pdev: pdev.into(),
             }
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 09/10] rust: debugfs: support binary large objects for ScopedDir
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (7 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 08/10] samples: rust: debugfs: add example for blobs Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-23  8:23   ` Alice Ryhl
  2025-10-22 14:30 ` [PATCH v3 10/10] samples: rust: debugfs_scoped: add example for blobs Danilo Krummrich
  2025-10-28 13:47 ` [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Miguel Ojeda
  10 siblings, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
Add support for creating binary debugfs files via ScopedDir. This
mirrors the existing functionality for Dir, but without producing an
owning handle -- files are automatically removed when the associated
Scope is dropped.
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Matthew Maurer <mmaurer@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/debugfs.rs | 44 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index d2bc7550d81e..e8139d2e5730 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -530,6 +530,20 @@ pub fn read_only_file<T: Writer + Send + Sync + 'static>(&self, name: &CStr, dat
         self.create_file(name, data, &T::FILE_OPS)
     }
 
+    /// Creates a read-only binary file in this directory.
+    ///
+    /// The file's contents are produced by invoking [`BinaryWriter::write_to_slice`].
+    ///
+    /// This function does not produce an owning handle to the file. The created file is removed
+    /// when the [`Scope`] that this directory belongs to is dropped.
+    pub fn read_binary_file<T: BinaryWriter + Send + Sync + 'static>(
+        &self,
+        name: &CStr,
+        data: &'data T,
+    ) {
+        self.create_file(name, data, &T::FILE_OPS)
+    }
+
     /// Creates a read-only file in this directory, with contents from a callback.
     ///
     /// The file contents are generated by calling `f` with `data`.
@@ -567,6 +581,22 @@ pub fn read_write_file<T: Writer + Reader + Send + Sync + 'static>(
         self.create_file(name, data, vtable)
     }
 
+    /// Creates a read-write binary file in this directory.
+    ///
+    /// Reading the file uses the [`BinaryWriter`] implementation on `data`. Writing to the file
+    /// uses the [`BinaryReader`] implementation on `data`.
+    ///
+    /// This function does not produce an owning handle to the file. The created file is removed
+    /// when the [`Scope`] that this directory belongs to is dropped.
+    pub fn read_write_binary_file<T: BinaryWriter + BinaryReader + Send + Sync + 'static>(
+        &self,
+        name: &CStr,
+        data: &'data T,
+    ) {
+        let vtable = &<T as BinaryReadWriteFile<_>>::FILE_OPS;
+        self.create_file(name, data, vtable)
+    }
+
     /// Creates a read-write file in this directory, with logic from callbacks.
     ///
     /// Reading from the file is handled by `f`. Writing to the file is handled by `w`.
@@ -606,6 +636,20 @@ pub fn write_only_file<T: Reader + Send + Sync + 'static>(&self, name: &CStr, da
         self.create_file(name, data, vtable)
     }
 
+    /// Creates a write-only binary file in this directory.
+    ///
+    /// Writing to the file uses the [`BinaryReader`] implementation on `data`.
+    ///
+    /// This function does not produce an owning handle to the file. The created file is removed
+    /// when the [`Scope`] that this directory belongs to is dropped.
+    pub fn write_binary_file<T: BinaryReader + Send + Sync + 'static>(
+        &self,
+        name: &CStr,
+        data: &'data T,
+    ) {
+        self.create_file(name, data, &T::FILE_OPS)
+    }
+
     /// Creates a write-only file in this directory, with write logic from a callback.
     ///
     /// Writing to the file is handled by `w`.
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* [PATCH v3 10/10] samples: rust: debugfs_scoped: add example for blobs
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (8 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 09/10] rust: debugfs: support binary large objects for ScopedDir Danilo Krummrich
@ 2025-10-22 14:30 ` Danilo Krummrich
  2025-10-28 13:47 ` [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Miguel Ojeda
  10 siblings, 0 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-22 14:30 UTC (permalink / raw)
  To: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Danilo Krummrich
Extend the rust_debugfs_scoped sample to demonstrate how to export a
large binary object through a ScopedDir.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Matthew Maurer <mmaurer@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 samples/rust/rust_debugfs_scoped.rs | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/samples/rust/rust_debugfs_scoped.rs b/samples/rust/rust_debugfs_scoped.rs
index b0c4e76b123e..c80312cf168d 100644
--- a/samples/rust/rust_debugfs_scoped.rs
+++ b/samples/rust/rust_debugfs_scoped.rs
@@ -9,6 +9,7 @@
 use core::sync::atomic::AtomicUsize;
 use kernel::debugfs::{Dir, Scope};
 use kernel::prelude::*;
+use kernel::sizes::*;
 use kernel::sync::Mutex;
 use kernel::{c_str, new_mutex, str::CString};
 
@@ -66,18 +67,22 @@ fn create_file_write(
             GFP_KERNEL,
         )?;
     }
+    let blob = KBox::pin_init(new_mutex!([0x42; SZ_4K]), GFP_KERNEL)?;
 
     let scope = KBox::pin_init(
-        mod_data
-            .device_dir
-            .scope(DeviceData { name, nums }, &file_name, |dev_data, dir| {
+        mod_data.device_dir.scope(
+            DeviceData { name, nums, blob },
+            &file_name,
+            |dev_data, dir| {
                 for (idx, val) in dev_data.nums.iter().enumerate() {
                     let Ok(name) = CString::try_from_fmt(fmt!("{idx}")) else {
                         return;
                     };
                     dir.read_write_file(&name, val);
                 }
-            }),
+                dir.read_write_binary_file(c_str!("blob"), &dev_data.blob);
+            },
+        ),
         GFP_KERNEL,
     )?;
     (*mod_data.devices.lock()).push(scope, GFP_KERNEL)?;
@@ -110,6 +115,7 @@ fn init(device_dir: Dir) -> impl PinInit<Self> {
 struct DeviceData {
     name: CString,
     nums: KVec<AtomicUsize>,
+    blob: Pin<KBox<Mutex<[u8; SZ_4K]>>>,
 }
 
 fn init_control(base_dir: &Dir, dyn_dirs: Dir) -> impl PinInit<Scope<ModuleData>> + '_ {
-- 
2.51.0
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 01/10] rust: fs: add new type file::Offset
  2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
@ 2025-10-22 14:42   ` Miguel Ojeda
  2025-10-24 12:15   ` Alice Ryhl
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 39+ messages in thread
From: Miguel Ojeda @ 2025-10-22 14:42 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel, Alexander Viro, Christian Brauner,
	Jan Kara
On Wed, Oct 22, 2025 at 4:32 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Add a new type for file offsets, i.e. bindings::loff_t. Trying to avoid
> using raw bindings types, this seems to be the better alternative
> compared to just using i64.
>
> Cc: Alexander Viro <viro@zeniv.linux.org.uk>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: Jan Kara <jack@suse.cz>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Thanks a lot for this!
Suggested-by: Miguel Ojeda <ojeda@kernel.org>
Link: https://github.com/Rust-for-Linux/linux/issues/1198
Cheers,
Miguel
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 09/10] rust: debugfs: support binary large objects for ScopedDir
  2025-10-22 14:30 ` [PATCH v3 09/10] rust: debugfs: support binary large objects for ScopedDir Danilo Krummrich
@ 2025-10-23  8:23   ` Alice Ryhl
  0 siblings, 0 replies; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23  8:23 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 04:30:43PM +0200, Danilo Krummrich wrote:
> Add support for creating binary debugfs files via ScopedDir. This
> mirrors the existing functionality for Dir, but without producing an
> owning handle -- files are automatically removed when the associated
> Scope is dropped.
> 
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 07/10] rust: debugfs: support blobs from smart pointers
  2025-10-22 14:30 ` [PATCH v3 07/10] rust: debugfs: support blobs from smart pointers Danilo Krummrich
@ 2025-10-23  8:24   ` Alice Ryhl
  0 siblings, 0 replies; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23  8:24 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 04:30:41PM +0200, Danilo Krummrich wrote:
> Extend Rust debugfs binary support to allow exposing data stored in
> common smart pointers and heap-allocated collections.
> 
> - Implement BinaryWriter for Box<T>, Pin<Box<T>>, Arc<T>, and Vec<T>.
> - Introduce BinaryReaderMut for mutable binary access with outer locks.
> - Implement BinaryReaderMut for Box<T>, Vec<T>, and base types.
> - Update BinaryReader to delegate to BinaryReaderMut for Mutex<T>,
>   Box<T>, Pin<Box<T>> and Arc<T>.
> 
> This enables debugfs files to directly expose or update data stored
> inside heap-allocated, reference-counted, or lock-protected containers
> without manual dereferencing or locking.
> 
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 06/10] rust: debugfs: support for binary large objects
  2025-10-22 14:30 ` [PATCH v3 06/10] rust: debugfs: support for binary large objects Danilo Krummrich
@ 2025-10-23  8:26   ` Alice Ryhl
  2025-10-23 10:09     ` Danilo Krummrich
  0 siblings, 1 reply; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23  8:26 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 04:30:40PM +0200, Danilo Krummrich wrote:
> Introduce support for read-only, write-only, and read-write binary files
> in Rust debugfs. This adds:
> 
> - BinaryWriter and BinaryReader traits for writing to and reading from
>   user slices in binary form.
> - New Dir methods: read_binary_file(), write_binary_file(),
>   `read_write_binary_file`.
> - Corresponding FileOps implementations: BinaryReadFile,
>   BinaryWriteFile, BinaryReadWriteFile.
> 
> This allows kernel modules to expose arbitrary binary data through
> debugfs, with proper support for offsets and partial reads/writes.
> 
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> +extern "C" fn blob_read<T: BinaryWriter>(
> +    file: *mut bindings::file,
> +    buf: *mut c_char,
> +    count: usize,
> +    ppos: *mut bindings::loff_t,
> +) -> isize {
> +    // SAFETY:
> +    // - `file` is a valid pointer to a `struct file`.
> +    // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`.
> +    let this = unsafe { &*((*file).private_data.cast::<T>()) };
> +
> +    // SAFETY:
> +    // `ppos` is a valid `file::Offset` pointer.
> +    // We have exclusive access to `ppos`.
> +    let pos = unsafe { file::Offset::from_raw(ppos) };
> +
> +    let mut writer = UserSlice::new(UserPtr::from_ptr(buf.cast()), count).writer();
> +
> +    let ret = || -> Result<isize> {
> +        let written = this.write_to_slice(&mut writer, pos)?;
> +
> +        Ok(written.try_into()?)
Hmm ... a conversion? Sounds like write_to_slice() has the wrong return
type.
Alice
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-22 14:30 ` [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file() Danilo Krummrich
@ 2025-10-23  8:30   ` Alice Ryhl
  2025-10-23 10:35     ` Danilo Krummrich
  2025-10-28 14:07   ` Miguel Ojeda
  1 sibling, 1 reply; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23  8:30 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 04:30:39PM +0200, Danilo Krummrich wrote:
> Add UserSliceWriter::write_slice_file(), which is the same as
> UserSliceWriter::write_slice_partial() but updates the given
> file::Offset by the number of bytes written.
> 
> This is equivalent to C's `simple_read_from_buffer()` and useful when
> dealing with file offsets from file operations.
> 
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/uaccess.rs | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index 539e77a09cbc..20ea31781efb 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -495,6 +495,30 @@ pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usiz
>              .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
>      }
>  
> +    /// Writes raw data to this user pointer from a kernel buffer partially.
> +    ///
> +    /// This is the same as [`Self::write_slice_partial`] but updates the given [`file::Offset`] by
> +    /// the number of bytes written.
> +    ///
> +    /// This is equivalent to C's `simple_read_from_buffer()`.
> +    ///
> +    /// On success, returns the number of bytes written.
> +    pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Result<usize> {
> +        if offset.is_negative() {
> +            return Err(EINVAL);
> +        }
> +
> +        let Ok(offset_index) = (*offset).try_into() else {
> +            return Ok(0);
> +        };
> +
> +        let written = self.write_slice_partial(data, offset_index)?;
> +
> +        *offset = offset.saturating_add_usize(written);
This addition should never overflow:
	offset + written <= data.len() <= isize::MAX <= Offset::MAX
I can't help but think that maybe this should be a + operation instead?
Alice
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial()
  2025-10-22 14:30 ` [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial() Danilo Krummrich
@ 2025-10-23  8:33   ` Alice Ryhl
  2025-10-28 13:57     ` Miguel Ojeda
  2025-11-01 14:19   ` Alexandre Courbot
  1 sibling, 1 reply; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23  8:33 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 04:30:38PM +0200, Danilo Krummrich wrote:
> The existing write_slice() method is a wrapper around copy_to_user() and
> expects the user buffer to be larger than the source buffer.
> 
> However, userspace may split up reads in multiple partial operations
> providing an offset into the source buffer and a smaller user buffer.
> 
> In order to support this common case, provide a helper for partial
> writes.
> 
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This code is ok
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
but:
> +    /// Writes raw data to this user pointer from a kernel buffer partially.
> +    ///
> +    /// This is the same as [`Self::write_slice`] but considers the given `offset` into `data` and
> +    /// truncates the write to the boundaries of `self` and `data`.
> +    ///
> +    /// On success, returns the number of bytes written.
> +    pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usize> {
> +        let end = offset
> +            .checked_add(self.len())
> +            .unwrap_or(data.len())
> +            .min(data.len());
> +
> +        data.get(offset..end)
> +            .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
Isn't it more readable to write it like this?
	let Some(src) = data.get(offset..end) else {
	    return Ok(0);
	};
	
	self.write_slice(src)?;
	Ok(src.len())
Alice
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 06/10] rust: debugfs: support for binary large objects
  2025-10-23  8:26   ` Alice Ryhl
@ 2025-10-23 10:09     ` Danilo Krummrich
  2025-10-23 10:21       ` Alice Ryhl
  0 siblings, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-23 10:09 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu Oct 23, 2025 at 10:26 AM CEST, Alice Ryhl wrote:
> On Wed, Oct 22, 2025 at 04:30:40PM +0200, Danilo Krummrich wrote:
>> Introduce support for read-only, write-only, and read-write binary files
>> in Rust debugfs. This adds:
>> 
>> - BinaryWriter and BinaryReader traits for writing to and reading from
>>   user slices in binary form.
>> - New Dir methods: read_binary_file(), write_binary_file(),
>>   `read_write_binary_file`.
>> - Corresponding FileOps implementations: BinaryReadFile,
>>   BinaryWriteFile, BinaryReadWriteFile.
>> 
>> This allows kernel modules to expose arbitrary binary data through
>> debugfs, with proper support for offsets and partial reads/writes.
>> 
>> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Reviewed-by: Matthew Maurer <mmaurer@google.com>
>> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
>
>> +extern "C" fn blob_read<T: BinaryWriter>(
>> +    file: *mut bindings::file,
>> +    buf: *mut c_char,
>> +    count: usize,
>> +    ppos: *mut bindings::loff_t,
>> +) -> isize {
>> +    // SAFETY:
>> +    // - `file` is a valid pointer to a `struct file`.
>> +    // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`.
>> +    let this = unsafe { &*((*file).private_data.cast::<T>()) };
>> +
>> +    // SAFETY:
>> +    // `ppos` is a valid `file::Offset` pointer.
>> +    // We have exclusive access to `ppos`.
>> +    let pos = unsafe { file::Offset::from_raw(ppos) };
>> +
>> +    let mut writer = UserSlice::new(UserPtr::from_ptr(buf.cast()), count).writer();
>> +
>> +    let ret = || -> Result<isize> {
>> +        let written = this.write_to_slice(&mut writer, pos)?;
>> +
>> +        Ok(written.try_into()?)
>
> Hmm ... a conversion? Sounds like write_to_slice() has the wrong return
> type.
write_to_slice() returns the number of bytes written as usize, which seems
correct, no?
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 06/10] rust: debugfs: support for binary large objects
  2025-10-23 10:09     ` Danilo Krummrich
@ 2025-10-23 10:21       ` Alice Ryhl
  2025-10-24 10:36         ` Alice Ryhl
  0 siblings, 1 reply; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23 10:21 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu, Oct 23, 2025 at 12:09 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu Oct 23, 2025 at 10:26 AM CEST, Alice Ryhl wrote:
> > On Wed, Oct 22, 2025 at 04:30:40PM +0200, Danilo Krummrich wrote:
> >> Introduce support for read-only, write-only, and read-write binary files
> >> in Rust debugfs. This adds:
> >>
> >> - BinaryWriter and BinaryReader traits for writing to and reading from
> >>   user slices in binary form.
> >> - New Dir methods: read_binary_file(), write_binary_file(),
> >>   `read_write_binary_file`.
> >> - Corresponding FileOps implementations: BinaryReadFile,
> >>   BinaryWriteFile, BinaryReadWriteFile.
> >>
> >> This allows kernel modules to expose arbitrary binary data through
> >> debugfs, with proper support for offsets and partial reads/writes.
> >>
> >> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> >> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> >> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> >
> >> +extern "C" fn blob_read<T: BinaryWriter>(
> >> +    file: *mut bindings::file,
> >> +    buf: *mut c_char,
> >> +    count: usize,
> >> +    ppos: *mut bindings::loff_t,
> >> +) -> isize {
> >> +    // SAFETY:
> >> +    // - `file` is a valid pointer to a `struct file`.
> >> +    // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`.
> >> +    let this = unsafe { &*((*file).private_data.cast::<T>()) };
> >> +
> >> +    // SAFETY:
> >> +    // `ppos` is a valid `file::Offset` pointer.
> >> +    // We have exclusive access to `ppos`.
> >> +    let pos = unsafe { file::Offset::from_raw(ppos) };
> >> +
> >> +    let mut writer = UserSlice::new(UserPtr::from_ptr(buf.cast()), count).writer();
> >> +
> >> +    let ret = || -> Result<isize> {
> >> +        let written = this.write_to_slice(&mut writer, pos)?;
> >> +
> >> +        Ok(written.try_into()?)
> >
> > Hmm ... a conversion? Sounds like write_to_slice() has the wrong return
> > type.
>
> write_to_slice() returns the number of bytes written as usize, which seems
> correct, no?
Yes, you're right, I think usize is the right value. The cast is
unfortunate, but it can't really be avoided. In practice it should
never fail because slice lengths always fit in an isize, but isize
isn't the right type.
Alice
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-23  8:30   ` Alice Ryhl
@ 2025-10-23 10:35     ` Danilo Krummrich
  2025-10-23 10:37       ` Alice Ryhl
  0 siblings, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-23 10:35 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu Oct 23, 2025 at 10:30 AM CEST, Alice Ryhl wrote:
> On Wed, Oct 22, 2025 at 04:30:39PM +0200, Danilo Krummrich wrote:
>> Add UserSliceWriter::write_slice_file(), which is the same as
>> UserSliceWriter::write_slice_partial() but updates the given
>> file::Offset by the number of bytes written.
>> 
>> This is equivalent to C's `simple_read_from_buffer()` and useful when
>> dealing with file offsets from file operations.
>> 
>> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
>> ---
>>  rust/kernel/uaccess.rs | 24 ++++++++++++++++++++++++
>>  1 file changed, 24 insertions(+)
>> 
>> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
>> index 539e77a09cbc..20ea31781efb 100644
>> --- a/rust/kernel/uaccess.rs
>> +++ b/rust/kernel/uaccess.rs
>> @@ -495,6 +495,30 @@ pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usiz
>>              .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
>>      }
>>  
>> +    /// Writes raw data to this user pointer from a kernel buffer partially.
>> +    ///
>> +    /// This is the same as [`Self::write_slice_partial`] but updates the given [`file::Offset`] by
>> +    /// the number of bytes written.
>> +    ///
>> +    /// This is equivalent to C's `simple_read_from_buffer()`.
>> +    ///
>> +    /// On success, returns the number of bytes written.
>> +    pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Result<usize> {
>> +        if offset.is_negative() {
>> +            return Err(EINVAL);
>> +        }
>> +
>> +        let Ok(offset_index) = (*offset).try_into() else {
>> +            return Ok(0);
>> +        };
>> +
>> +        let written = self.write_slice_partial(data, offset_index)?;
>> +
>> +        *offset = offset.saturating_add_usize(written);
>
> This addition should never overflow:
It probably never will (which is why this was a + operation in v1).
> 	offset + written <= data.len() <= isize::MAX <= Offset::MAX
However, this would rely on implementation details you listed, i.e. the
invariant that a slice length should be at most isize::MAX and what's the
maximum size of file::Offset::MAX.
Even though I don't expect any of the above to change any time soon
saturating_add_usize() seems reasonable to me.
> I can't help but think that maybe this should be a + operation instead?
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-23 10:35     ` Danilo Krummrich
@ 2025-10-23 10:37       ` Alice Ryhl
  2025-10-23 11:03         ` Danilo Krummrich
  0 siblings, 1 reply; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23 10:37 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu, Oct 23, 2025 at 12:35 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu Oct 23, 2025 at 10:30 AM CEST, Alice Ryhl wrote:
> > On Wed, Oct 22, 2025 at 04:30:39PM +0200, Danilo Krummrich wrote:
> >> Add UserSliceWriter::write_slice_file(), which is the same as
> >> UserSliceWriter::write_slice_partial() but updates the given
> >> file::Offset by the number of bytes written.
> >>
> >> This is equivalent to C's `simple_read_from_buffer()` and useful when
> >> dealing with file offsets from file operations.
> >>
> >> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> >> ---
> >>  rust/kernel/uaccess.rs | 24 ++++++++++++++++++++++++
> >>  1 file changed, 24 insertions(+)
> >>
> >> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> >> index 539e77a09cbc..20ea31781efb 100644
> >> --- a/rust/kernel/uaccess.rs
> >> +++ b/rust/kernel/uaccess.rs
> >> @@ -495,6 +495,30 @@ pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usiz
> >>              .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
> >>      }
> >>
> >> +    /// Writes raw data to this user pointer from a kernel buffer partially.
> >> +    ///
> >> +    /// This is the same as [`Self::write_slice_partial`] but updates the given [`file::Offset`] by
> >> +    /// the number of bytes written.
> >> +    ///
> >> +    /// This is equivalent to C's `simple_read_from_buffer()`.
> >> +    ///
> >> +    /// On success, returns the number of bytes written.
> >> +    pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Result<usize> {
> >> +        if offset.is_negative() {
> >> +            return Err(EINVAL);
> >> +        }
> >> +
> >> +        let Ok(offset_index) = (*offset).try_into() else {
> >> +            return Ok(0);
> >> +        };
> >> +
> >> +        let written = self.write_slice_partial(data, offset_index)?;
> >> +
> >> +        *offset = offset.saturating_add_usize(written);
> >
> > This addition should never overflow:
>
> It probably never will (which is why this was a + operation in v1).
>
> >       offset + written <= data.len() <= isize::MAX <= Offset::MAX
>
> However, this would rely on implementation details you listed, i.e. the
> invariant that a slice length should be at most isize::MAX and what's the
> maximum size of file::Offset::MAX.
It's not an implementation detail. All Rust allocations are guaranteed
to fit in isize::MAX bytes:
https://doc.rust-lang.org/stable/std/ptr/index.html#allocation
Alice
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-23 10:37       ` Alice Ryhl
@ 2025-10-23 11:03         ` Danilo Krummrich
  2025-10-23 11:20           ` Alice Ryhl
  0 siblings, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-23 11:03 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu Oct 23, 2025 at 12:37 PM CEST, Alice Ryhl wrote:
> On Thu, Oct 23, 2025 at 12:35 PM Danilo Krummrich <dakr@kernel.org> wrote:
>>
>> On Thu Oct 23, 2025 at 10:30 AM CEST, Alice Ryhl wrote:
>> > On Wed, Oct 22, 2025 at 04:30:39PM +0200, Danilo Krummrich wrote:
>> >> Add UserSliceWriter::write_slice_file(), which is the same as
>> >> UserSliceWriter::write_slice_partial() but updates the given
>> >> file::Offset by the number of bytes written.
>> >>
>> >> This is equivalent to C's `simple_read_from_buffer()` and useful when
>> >> dealing with file offsets from file operations.
>> >>
>> >> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
>> >> ---
>> >>  rust/kernel/uaccess.rs | 24 ++++++++++++++++++++++++
>> >>  1 file changed, 24 insertions(+)
>> >>
>> >> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
>> >> index 539e77a09cbc..20ea31781efb 100644
>> >> --- a/rust/kernel/uaccess.rs
>> >> +++ b/rust/kernel/uaccess.rs
>> >> @@ -495,6 +495,30 @@ pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usiz
>> >>              .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
>> >>      }
>> >>
>> >> +    /// Writes raw data to this user pointer from a kernel buffer partially.
>> >> +    ///
>> >> +    /// This is the same as [`Self::write_slice_partial`] but updates the given [`file::Offset`] by
>> >> +    /// the number of bytes written.
>> >> +    ///
>> >> +    /// This is equivalent to C's `simple_read_from_buffer()`.
>> >> +    ///
>> >> +    /// On success, returns the number of bytes written.
>> >> +    pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Result<usize> {
>> >> +        if offset.is_negative() {
>> >> +            return Err(EINVAL);
>> >> +        }
>> >> +
>> >> +        let Ok(offset_index) = (*offset).try_into() else {
>> >> +            return Ok(0);
>> >> +        };
>> >> +
>> >> +        let written = self.write_slice_partial(data, offset_index)?;
>> >> +
>> >> +        *offset = offset.saturating_add_usize(written);
>> >
>> > This addition should never overflow:
>>
>> It probably never will (which is why this was a + operation in v1).
>>
>> >       offset + written <= data.len() <= isize::MAX <= Offset::MAX
>>
>> However, this would rely on implementation details you listed, i.e. the
>> invariant that a slice length should be at most isize::MAX and what's the
>> maximum size of file::Offset::MAX.
>
> It's not an implementation detail. All Rust allocations are guaranteed
> to fit in isize::MAX bytes:
> https://doc.rust-lang.org/stable/std/ptr/index.html#allocation
Yeah, I'm aware -- I expressed this badly.
What I meant is that for the kernel we obviously know that there's no
architecture where isize::MAX > file::Offset::MAX.
However, in the core API the conversion from usize to u128 is considered
fallible. So, applying the assumption that isize::MAX <= file::Offset::MAX is at
least inconsistent.
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-23 11:03         ` Danilo Krummrich
@ 2025-10-23 11:20           ` Alice Ryhl
  2025-10-23 12:43             ` Danilo Krummrich
  2025-10-24 18:02             ` Miguel Ojeda
  0 siblings, 2 replies; 39+ messages in thread
From: Alice Ryhl @ 2025-10-23 11:20 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu, Oct 23, 2025 at 01:03:35PM +0200, Danilo Krummrich wrote:
> On Thu Oct 23, 2025 at 12:37 PM CEST, Alice Ryhl wrote:
> > On Thu, Oct 23, 2025 at 12:35 PM Danilo Krummrich <dakr@kernel.org> wrote:
> >>
> >> On Thu Oct 23, 2025 at 10:30 AM CEST, Alice Ryhl wrote:
> >> > On Wed, Oct 22, 2025 at 04:30:39PM +0200, Danilo Krummrich wrote:
> >> >> Add UserSliceWriter::write_slice_file(), which is the same as
> >> >> UserSliceWriter::write_slice_partial() but updates the given
> >> >> file::Offset by the number of bytes written.
> >> >>
> >> >> This is equivalent to C's `simple_read_from_buffer()` and useful when
> >> >> dealing with file offsets from file operations.
> >> >>
> >> >> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> >> >> ---
> >> >>  rust/kernel/uaccess.rs | 24 ++++++++++++++++++++++++
> >> >>  1 file changed, 24 insertions(+)
> >> >>
> >> >> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> >> >> index 539e77a09cbc..20ea31781efb 100644
> >> >> --- a/rust/kernel/uaccess.rs
> >> >> +++ b/rust/kernel/uaccess.rs
> >> >> @@ -495,6 +495,30 @@ pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usiz
> >> >>              .map_or(Ok(0), |src| self.write_slice(src).map(|()| src.len()))
> >> >>      }
> >> >>
> >> >> +    /// Writes raw data to this user pointer from a kernel buffer partially.
> >> >> +    ///
> >> >> +    /// This is the same as [`Self::write_slice_partial`] but updates the given [`file::Offset`] by
> >> >> +    /// the number of bytes written.
> >> >> +    ///
> >> >> +    /// This is equivalent to C's `simple_read_from_buffer()`.
> >> >> +    ///
> >> >> +    /// On success, returns the number of bytes written.
> >> >> +    pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Result<usize> {
> >> >> +        if offset.is_negative() {
> >> >> +            return Err(EINVAL);
> >> >> +        }
> >> >> +
> >> >> +        let Ok(offset_index) = (*offset).try_into() else {
> >> >> +            return Ok(0);
> >> >> +        };
> >> >> +
> >> >> +        let written = self.write_slice_partial(data, offset_index)?;
> >> >> +
> >> >> +        *offset = offset.saturating_add_usize(written);
> >> >
> >> > This addition should never overflow:
> >>
> >> It probably never will (which is why this was a + operation in v1).
> >>
> >> >       offset + written <= data.len() <= isize::MAX <= Offset::MAX
> >>
> >> However, this would rely on implementation details you listed, i.e. the
> >> invariant that a slice length should be at most isize::MAX and what's the
> >> maximum size of file::Offset::MAX.
> >
> > It's not an implementation detail. All Rust allocations are guaranteed
> > to fit in isize::MAX bytes:
> > https://doc.rust-lang.org/stable/std/ptr/index.html#allocation
> 
> Yeah, I'm aware -- I expressed this badly.
> 
> What I meant is that for the kernel we obviously know that there's no
> architecture where isize::MAX > file::Offset::MAX.
> 
> However, in the core API the conversion from usize to u128 is considered
> fallible. So, applying the assumption that isize::MAX <= file::Offset::MAX is at
> least inconsistent.
I would love to have infallible conversions from usize to u64 (and u32
to usize), but we can't really modify the stdlib to add them.
But even if we had them, it wouldn't help here since the target type is
i64, not u64. And there are usize values that don't fit in i64 - it's
just that in this case the usize fits in isize.
Alice
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-23 11:20           ` Alice Ryhl
@ 2025-10-23 12:43             ` Danilo Krummrich
  2025-10-24 10:37               ` Alice Ryhl
  2025-10-24 18:02             ` Miguel Ojeda
  1 sibling, 1 reply; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-23 12:43 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu Oct 23, 2025 at 1:20 PM CEST, Alice Ryhl wrote:
> I would love to have infallible conversions from usize to u64 (and u32
> to usize), but we can't really modify the stdlib to add them.
We can (and probably should) implement a kernel specific infallible one.
I think we also want a helper for `slice::len() as isize`.
> But even if we had them, it wouldn't help here since the target type is
> i64, not u64. And there are usize values that don't fit in i64 - it's
> just that in this case the usize fits in isize.
Sure, it doesn't change the code required for this case. Yet, I think that if we
agree on having a kernel specific infallible conversions for usize -> u64 and
isize -> i64, it makes this + operation formally more consistent.
Here's the diff I'd apply:
diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index 681b8a9e5d52..63478dd7deb8 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -125,6 +125,22 @@ pub fn saturating_sub_usize(self, rhs: usize) -> Offset {
     }
 }
+impl core::ops::Add<isize> for Offset {
+    type Output = Offset;
+
+    #[inline]
+    fn add(self, rhs: isize) -> Offset {
+        Offset(self.0 + rhs as bindings::loff_t)
+    }
+}
+
+impl core::ops::AddAssign<isize> for Offset {
+    #[inline]
+    fn add_assign(&mut self, rhs: isize) {
+        self.0 += rhs as bindings::loff_t;
+    }
+}
+
 impl From<bindings::loff_t> for Offset {
     #[inline]
     fn from(v: bindings::loff_t) -> Self {
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 20ea31781efb..44ee334c4507 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -514,7 +514,8 @@ pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Re
         let written = self.write_slice_partial(data, offset_index)?;
-        *offset = offset.saturating_add_usize(written);
+        // OVERFLOW: `offset + written <= data.len() <= isize::MAX <= Offset::MAX`
+        *offset += written as isize;
         Ok(written)
     }
^ permalink raw reply related	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 06/10] rust: debugfs: support for binary large objects
  2025-10-23 10:21       ` Alice Ryhl
@ 2025-10-24 10:36         ` Alice Ryhl
  0 siblings, 0 replies; 39+ messages in thread
From: Alice Ryhl @ 2025-10-24 10:36 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu, Oct 23, 2025 at 12:21:24PM +0200, Alice Ryhl wrote:
> On Thu, Oct 23, 2025 at 12:09 PM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > On Thu Oct 23, 2025 at 10:26 AM CEST, Alice Ryhl wrote:
> > > On Wed, Oct 22, 2025 at 04:30:40PM +0200, Danilo Krummrich wrote:
> > >> Introduce support for read-only, write-only, and read-write binary files
> > >> in Rust debugfs. This adds:
> > >>
> > >> - BinaryWriter and BinaryReader traits for writing to and reading from
> > >>   user slices in binary form.
> > >> - New Dir methods: read_binary_file(), write_binary_file(),
> > >>   `read_write_binary_file`.
> > >> - Corresponding FileOps implementations: BinaryReadFile,
> > >>   BinaryWriteFile, BinaryReadWriteFile.
> > >>
> > >> This allows kernel modules to expose arbitrary binary data through
> > >> debugfs, with proper support for offsets and partial reads/writes.
> > >>
> > >> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > >> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> > >> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > >
> > >> +extern "C" fn blob_read<T: BinaryWriter>(
> > >> +    file: *mut bindings::file,
> > >> +    buf: *mut c_char,
> > >> +    count: usize,
> > >> +    ppos: *mut bindings::loff_t,
> > >> +) -> isize {
> > >> +    // SAFETY:
> > >> +    // - `file` is a valid pointer to a `struct file`.
> > >> +    // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`.
> > >> +    let this = unsafe { &*((*file).private_data.cast::<T>()) };
> > >> +
> > >> +    // SAFETY:
> > >> +    // `ppos` is a valid `file::Offset` pointer.
> > >> +    // We have exclusive access to `ppos`.
> > >> +    let pos = unsafe { file::Offset::from_raw(ppos) };
> > >> +
> > >> +    let mut writer = UserSlice::new(UserPtr::from_ptr(buf.cast()), count).writer();
> > >> +
> > >> +    let ret = || -> Result<isize> {
> > >> +        let written = this.write_to_slice(&mut writer, pos)?;
> > >> +
> > >> +        Ok(written.try_into()?)
> > >
> > > Hmm ... a conversion? Sounds like write_to_slice() has the wrong return
> > > type.
> >
> > write_to_slice() returns the number of bytes written as usize, which seems
> > correct, no?
> 
> Yes, you're right, I think usize is the right value. The cast is
> unfortunate, but it can't really be avoided. In practice it should
> never fail because slice lengths always fit in an isize, but isize
> isn't the right type.
> 
> Alice
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-23 12:43             ` Danilo Krummrich
@ 2025-10-24 10:37               ` Alice Ryhl
  0 siblings, 0 replies; 39+ messages in thread
From: Alice Ryhl @ 2025-10-24 10:37 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Thu, Oct 23, 2025 at 02:43:20PM +0200, Danilo Krummrich wrote:
> On Thu Oct 23, 2025 at 1:20 PM CEST, Alice Ryhl wrote:
> > I would love to have infallible conversions from usize to u64 (and u32
> > to usize), but we can't really modify the stdlib to add them.
> 
> We can (and probably should) implement a kernel specific infallible one.
> 
> I think we also want a helper for `slice::len() as isize`.
> 
> > But even if we had them, it wouldn't help here since the target type is
> > i64, not u64. And there are usize values that don't fit in i64 - it's
> > just that in this case the usize fits in isize.
> 
> Sure, it doesn't change the code required for this case. Yet, I think that if we
> agree on having a kernel specific infallible conversions for usize -> u64 and
> isize -> i64, it makes this + operation formally more consistent.
> 
> Here's the diff I'd apply:
> 
> diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
> index 681b8a9e5d52..63478dd7deb8 100644
> --- a/rust/kernel/fs/file.rs
> +++ b/rust/kernel/fs/file.rs
> @@ -125,6 +125,22 @@ pub fn saturating_sub_usize(self, rhs: usize) -> Offset {
>      }
>  }
> 
> +impl core::ops::Add<isize> for Offset {
> +    type Output = Offset;
> +
> +    #[inline]
> +    fn add(self, rhs: isize) -> Offset {
> +        Offset(self.0 + rhs as bindings::loff_t)
> +    }
> +}
> +
> +impl core::ops::AddAssign<isize> for Offset {
> +    #[inline]
> +    fn add_assign(&mut self, rhs: isize) {
> +        self.0 += rhs as bindings::loff_t;
> +    }
> +}
> +
>  impl From<bindings::loff_t> for Offset {
>      #[inline]
>      fn from(v: bindings::loff_t) -> Self {
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index 20ea31781efb..44ee334c4507 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -514,7 +514,8 @@ pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Re
> 
>          let written = self.write_slice_partial(data, offset_index)?;
> 
> -        *offset = offset.saturating_add_usize(written);
> +        // OVERFLOW: `offset + written <= data.len() <= isize::MAX <= Offset::MAX`
> +        *offset += written as isize;
> 
>          Ok(written)
>      }
> 
This LGTM.
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial()
  2025-10-22 14:30 ` [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial() Danilo Krummrich
@ 2025-10-24 10:39   ` Alice Ryhl
  2025-11-01 14:16   ` Alexandre Courbot
  1 sibling, 0 replies; 39+ messages in thread
From: Alice Ryhl @ 2025-10-24 10:39 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 04:30:36PM +0200, Danilo Krummrich wrote:
> The existing read_slice() method is a wrapper around copy_from_user()
> and expects the user buffer to be larger than the destination buffer.
> 
> However, userspace may split up writes in multiple partial operations
> providing an offset into the destination buffer and a smaller user
> buffer.
> 
> In order to support this common case, provide a helper for partial
> reads.
> 
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/uaccess.rs | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index a8fb4764185a..c1cd3a76cff8 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -287,6 +287,22 @@ pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
>          self.read_raw(out)
>      }
>  
> +    /// Reads raw data from the user slice into a kernel buffer partially.
> +    ///
> +    /// This is the same as [`Self::read_slice`] but considers the given `offset` into `out` and
> +    /// truncates the read to the boundaries of `self` and `out`.
> +    ///
> +    /// On success, returns the number of bytes read.
> +    pub fn read_slice_partial(&mut self, out: &mut [u8], offset: usize) -> Result<usize> {
> +        let end = offset
> +            .checked_add(self.len())
> +            .unwrap_or(out.len())
> +            .min(out.len());
> +
> +        out.get_mut(offset..end)
> +            .map_or(Ok(0), |dst| self.read_slice(dst).map(|()| dst.len()))
Same comment applies as write_slice_partial().
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 01/10] rust: fs: add new type file::Offset
  2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
  2025-10-22 14:42   ` Miguel Ojeda
@ 2025-10-24 12:15   ` Alice Ryhl
  2025-10-28 11:04   ` Danilo Krummrich
  2025-11-01 14:16   ` Alexandre Courbot
  3 siblings, 0 replies; 39+ messages in thread
From: Alice Ryhl @ 2025-10-24 12:15 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel, Alexander Viro, Christian Brauner,
	Jan Kara
On Wed, Oct 22, 2025 at 04:30:35PM +0200, Danilo Krummrich wrote:
> Add a new type for file offsets, i.e. bindings::loff_t. Trying to avoid
> using raw bindings types, this seems to be the better alternative
> compared to just using i64.
> 
> Cc: Alexander Viro <viro@zeniv.linux.org.uk>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: Jan Kara <jack@suse.cz>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/fs/file.rs | 142 ++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 141 insertions(+), 1 deletion(-)
> 
> diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
> index cf06e73a6da0..681b8a9e5d52 100644
> --- a/rust/kernel/fs/file.rs
> +++ b/rust/kernel/fs/file.rs
> @@ -15,7 +15,147 @@
>      sync::aref::{ARef, AlwaysRefCounted},
>      types::{NotThreadSafe, Opaque},
>  };
> -use core::ptr;
> +use core::{num::TryFromIntError, ptr};
> +
> +/// Representation of an offset within a [`File`].
> +///
> +/// Transparent wrapper around `bindings::loff_t`.
> +#[repr(transparent)]
> +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
> +pub struct Offset(bindings::loff_t);
There is no invariant on this type, so the field can be public.
	pub struct Offset(pub bindings::loff_t);
Otherwise LGTM:
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Alice
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-23 11:20           ` Alice Ryhl
  2025-10-23 12:43             ` Danilo Krummrich
@ 2025-10-24 18:02             ` Miguel Ojeda
  2025-11-01 14:27               ` Alexandre Courbot
  1 sibling, 1 reply; 39+ messages in thread
From: Miguel Ojeda @ 2025-10-24 18:02 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor, boqun.feng,
	gary, bjorn3_gh, lossin, a.hindborg, tmgross, mmaurer,
	rust-for-linux, linux-fsdevel, linux-kernel
On Thu, Oct 23, 2025 at 1:20 PM Alice Ryhl <aliceryhl@google.com> wrote:
>
> I would love to have infallible conversions from usize to u64 (and u32
> to usize), but we can't really modify the stdlib to add them.
I don't have a link at hand now, but we already (recently too, I
think) discussed having these "we know it is infallible in the kernel"
conversions. Maybe there was a patch posted even.
Otherwise, I will create a good first issue.
Cheers,
Miguel
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 01/10] rust: fs: add new type file::Offset
  2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
  2025-10-22 14:42   ` Miguel Ojeda
  2025-10-24 12:15   ` Alice Ryhl
@ 2025-10-28 11:04   ` Danilo Krummrich
  2025-11-01 14:16   ` Alexandre Courbot
  3 siblings, 0 replies; 39+ messages in thread
From: Danilo Krummrich @ 2025-10-28 11:04 UTC (permalink / raw)
  To: Christian Brauner, Alexander Viro
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, gregkh, rafael,
	ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, mmaurer, Jan Kara
On Wed Oct 22, 2025 at 4:30 PM CEST, Danilo Krummrich wrote:
> Add a new type for file offsets, i.e. bindings::loff_t. Trying to avoid
> using raw bindings types, this seems to be the better alternative
> compared to just using i64.
>
> Cc: Alexander Viro <viro@zeniv.linux.org.uk>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: Jan Kara <jack@suse.cz>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Christian, Al: If you agree with the patch, can you please provide an ACK, so I
can take it through the driver-core tree?
Thanks,
Danilo
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 00/10] Binary Large Objects for Rust DebugFS
  2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
                   ` (9 preceding siblings ...)
  2025-10-22 14:30 ` [PATCH v3 10/10] samples: rust: debugfs_scoped: add example for blobs Danilo Krummrich
@ 2025-10-28 13:47 ` Miguel Ojeda
  10 siblings, 0 replies; 39+ messages in thread
From: Miguel Ojeda @ 2025-10-28 13:47 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 4:32 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
>   rust: uaccess: add UserSliceReader::read_slice_partial()
>   rust: uaccess: add UserSliceReader::read_slice_file()
>   rust: uaccess: add UserSliceWriter::write_slice_partial()
>   rust: uaccess: add UserSliceWriter::write_slice_file()
Acked-by: Miguel Ojeda <ojeda@kernel.org>
Cheers,
Miguel
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial()
  2025-10-23  8:33   ` Alice Ryhl
@ 2025-10-28 13:57     ` Miguel Ojeda
  0 siblings, 0 replies; 39+ messages in thread
From: Miguel Ojeda @ 2025-10-28 13:57 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor, boqun.feng,
	gary, bjorn3_gh, lossin, a.hindborg, tmgross, mmaurer,
	rust-for-linux, linux-fsdevel, linux-kernel
On Thu, Oct 23, 2025 at 10:33 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> Isn't it more readable to write it like this?
>
>         let Some(src) = data.get(offset..end) else {
>             return Ok(0);
>         };
>
>         self.write_slice(src)?;
>         Ok(src.len())
Yeah, I also tend to prefer that style for things like this, because
the "main" operation (like forwarding to `write_slice()`) is at the
top-level. rather than deep in a closure. Plus early returns look
closer to C.
Cheers,
Miguel
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-22 14:30 ` [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file() Danilo Krummrich
  2025-10-23  8:30   ` Alice Ryhl
@ 2025-10-28 14:07   ` Miguel Ojeda
  1 sibling, 0 replies; 39+ messages in thread
From: Miguel Ojeda @ 2025-10-28 14:07 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, mmaurer, rust-for-linux,
	linux-fsdevel, linux-kernel
On Wed, Oct 22, 2025 at 4:32 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> +    /// Writes raw data to this user pointer from a kernel buffer partially.
We use "user pointer" in a few places (including another of the added
ones), while "user slice" in others -- shouldn't we just use "user
slice"?
By the way, for new APIs with several arguments and potential paths
due to the `offset`, it wouldn't hurt to have an example (even if
build-only) with a couple asserts to show how the API behaves. But I
can create a good first issue for that if you prefer.
Similarly (another potential good first issue), should we use e.g.
    #[doc(alias = "simple_read_from_buffer")]`
?
Thanks!
Cheers,
Miguel
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 01/10] rust: fs: add new type file::Offset
  2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
                     ` (2 preceding siblings ...)
  2025-10-28 11:04   ` Danilo Krummrich
@ 2025-11-01 14:16   ` Alexandre Courbot
  3 siblings, 0 replies; 39+ messages in thread
From: Alexandre Courbot @ 2025-11-01 14:16 UTC (permalink / raw)
  To: Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor, boqun.feng,
	gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel, Alexander Viro,
	Christian Brauner, Jan Kara
On Wed Oct 22, 2025 at 11:30 PM JST, Danilo Krummrich wrote:
> Add a new type for file offsets, i.e. bindings::loff_t. Trying to avoid
> using raw bindings types, this seems to be the better alternative
> compared to just using i64.
>
> Cc: Alexander Viro <viro@zeniv.linux.org.uk>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: Jan Kara <jack@suse.cz>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/fs/file.rs | 142 ++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 141 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
> index cf06e73a6da0..681b8a9e5d52 100644
> --- a/rust/kernel/fs/file.rs
> +++ b/rust/kernel/fs/file.rs
> @@ -15,7 +15,147 @@
>      sync::aref::{ARef, AlwaysRefCounted},
>      types::{NotThreadSafe, Opaque},
>  };
> -use core::ptr;
> +use core::{num::TryFromIntError, ptr};
> +
> +/// Representation of an offset within a [`File`].
> +///
> +/// Transparent wrapper around `bindings::loff_t`.
> +#[repr(transparent)]
> +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
> +pub struct Offset(bindings::loff_t);
> +
> +impl Offset {
> +    /// The largest value that can be represented by this type.
> +    pub const MAX: Self = Self(bindings::loff_t::MAX);
> +
> +    /// The smallest value that can be represented by this type.
> +    pub const MIN: Self = Self(bindings::loff_t::MIN);
> +
> +    /// Create a mutable [`Offset`] reference from the raw `*mut bindings::loff_t`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// - `offset` must be a valid pointer to a `bindings::loff_t`.
> +    /// - The caller must guarantee exclusive access to `offset`.
> +    #[inline]
> +    pub const unsafe fn from_raw<'a>(offset: *mut bindings::loff_t) -> &'a mut Self {
> +        // SAFETY: By the safety requirements of this function
> +        // - `offset` is a valid pointer to a `bindings::loff_t`,
> +        // - we have exclusive access to `offset`.
> +        unsafe { &mut *offset.cast() }
> +    }
> +
> +    /// Returns `true` if the [`Offset`] is negative.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// use kernel::fs::file::Offset;
> +    ///
> +    /// let offset = Offset::from(1);
> +    /// assert!(!offset.is_negative());
> +    ///
> +    /// let offset = Offset::from(-1);
> +    /// assert!(offset.is_negative());
> +    /// ```
> +    #[inline]
> +    pub const fn is_negative(self) -> bool {
> +        self.0.is_negative()
> +    }
For symmetry with Rust's primitive types from which this method is
borrowed, do we want to also add `is_positive`?
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial()
  2025-10-22 14:30 ` [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial() Danilo Krummrich
  2025-10-24 10:39   ` Alice Ryhl
@ 2025-11-01 14:16   ` Alexandre Courbot
  1 sibling, 0 replies; 39+ messages in thread
From: Alexandre Courbot @ 2025-11-01 14:16 UTC (permalink / raw)
  To: Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor, boqun.feng,
	gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel
On Wed Oct 22, 2025 at 11:30 PM JST, Danilo Krummrich wrote:
> The existing read_slice() method is a wrapper around copy_from_user()
> and expects the user buffer to be larger than the destination buffer.
>
> However, userspace may split up writes in multiple partial operations
> providing an offset into the destination buffer and a smaller user
> buffer.
>
> In order to support this common case, provide a helper for partial
> reads.
>
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/uaccess.rs | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index a8fb4764185a..c1cd3a76cff8 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -287,6 +287,22 @@ pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
>          self.read_raw(out)
>      }
>  
> +    /// Reads raw data from the user slice into a kernel buffer partially.
> +    ///
> +    /// This is the same as [`Self::read_slice`] but considers the given `offset` into `out` and
> +    /// truncates the read to the boundaries of `self` and `out`.
> +    ///
> +    /// On success, returns the number of bytes read.
> +    pub fn read_slice_partial(&mut self, out: &mut [u8], offset: usize) -> Result<usize> {
> +        let end = offset
> +            .checked_add(self.len())
> +            .unwrap_or(out.len())
> +            .min(out.len());
IIUC you should be able to replace the `checked_add().unwrap_or()` with
`saturating_add()` and end up with the same result.
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 03/10] rust: uaccess: add UserSliceReader::read_slice_file()
  2025-10-22 14:30 ` [PATCH v3 03/10] rust: uaccess: add UserSliceReader::read_slice_file() Danilo Krummrich
@ 2025-11-01 14:16   ` Alexandre Courbot
  0 siblings, 0 replies; 39+ messages in thread
From: Alexandre Courbot @ 2025-11-01 14:16 UTC (permalink / raw)
  To: Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor, boqun.feng,
	gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel
On Wed Oct 22, 2025 at 11:30 PM JST, Danilo Krummrich wrote:
> Add UserSliceReader::read_slice_file(), which is the same as
> UserSliceReader::read_slice_partial() but updates the given file::Offset
> by the number of bytes read.
>
> This is equivalent to C's `simple_write_to_buffer()` and useful when
> dealing with file offsets from file operations.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/uaccess.rs | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
>
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index c1cd3a76cff8..c2d3dfee8934 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -9,6 +9,7 @@
>      bindings,
>      error::Result,
>      ffi::{c_char, c_void},
> +    fs::file,
>      prelude::*,
>      transmute::{AsBytes, FromBytes},
>  };
> @@ -303,6 +304,30 @@ pub fn read_slice_partial(&mut self, out: &mut [u8], offset: usize) -> Result<us
>              .map_or(Ok(0), |dst| self.read_slice(dst).map(|()| dst.len()))
>      }
>  
> +    /// Reads raw data from the user slice into a kernel buffer partially.
> +    ///
> +    /// This is the same as [`Self::read_slice_partial`] but updates the given [`file::Offset`] by
> +    /// the number of bytes read.
> +    ///
> +    /// This is equivalent to C's `simple_write_to_buffer()`.
> +    ///
> +    /// On success, returns the number of bytes read.
> +    pub fn read_slice_file(&mut self, out: &mut [u8], offset: &mut file::Offset) -> Result<usize> {
> +        if offset.is_negative() {
> +            return Err(EINVAL);
> +        }
> +
> +        let Ok(offset_index) = (*offset).try_into() else {
> +            return Ok(0);
> +        };
> +
> +        let read = self.read_slice_partial(out, offset_index)?;
> +
> +        *offset = offset.saturating_add_usize(read);
> +
> +        Ok(read)
Not sure whether this would be better, but you can avoid the `read`
local variable with the following:
    self.read_slice_partial(out, offset_index)
        .inspect(|&read| *offset = offset.saturating_add_usize(read))
In any case,
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial()
  2025-10-22 14:30 ` [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial() Danilo Krummrich
  2025-10-23  8:33   ` Alice Ryhl
@ 2025-11-01 14:19   ` Alexandre Courbot
  1 sibling, 0 replies; 39+ messages in thread
From: Alexandre Courbot @ 2025-11-01 14:19 UTC (permalink / raw)
  To: Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor, boqun.feng,
	gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, mmaurer
  Cc: rust-for-linux, linux-fsdevel, linux-kernel
On Wed Oct 22, 2025 at 11:30 PM JST, Danilo Krummrich wrote:
> The existing write_slice() method is a wrapper around copy_to_user() and
> expects the user buffer to be larger than the source buffer.
>
> However, userspace may split up reads in multiple partial operations
> providing an offset into the source buffer and a smaller user buffer.
>
> In order to support this common case, provide a helper for partial
> writes.
>
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Matthew Maurer <mmaurer@google.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/uaccess.rs | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index c2d3dfee8934..539e77a09cbc 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -479,6 +479,22 @@ pub fn write_slice(&mut self, data: &[u8]) -> Result {
>          Ok(())
>      }
>  
> +    /// Writes raw data to this user pointer from a kernel buffer partially.
> +    ///
> +    /// This is the same as [`Self::write_slice`] but considers the given `offset` into `data` and
> +    /// truncates the write to the boundaries of `self` and `data`.
> +    ///
> +    /// On success, returns the number of bytes written.
> +    pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usize> {
> +        let end = offset
> +            .checked_add(self.len())
> +            .unwrap_or(data.len())
> +            .min(data.len());
Same suggestion as the read counterpart about `saturating_add`.
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-10-24 18:02             ` Miguel Ojeda
@ 2025-11-01 14:27               ` Alexandre Courbot
  2025-11-01 15:06                 ` Miguel Ojeda
  0 siblings, 1 reply; 39+ messages in thread
From: Alexandre Courbot @ 2025-11-01 14:27 UTC (permalink / raw)
  To: Miguel Ojeda, Alice Ryhl
  Cc: Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor, boqun.feng,
	gary, bjorn3_gh, lossin, a.hindborg, tmgross, mmaurer,
	rust-for-linux, linux-fsdevel, linux-kernel
On Sat Oct 25, 2025 at 3:02 AM JST, Miguel Ojeda wrote:
> On Thu, Oct 23, 2025 at 1:20 PM Alice Ryhl <aliceryhl@google.com> wrote:
>>
>> I would love to have infallible conversions from usize to u64 (and u32
>> to usize), but we can't really modify the stdlib to add them.
>
> I don't have a link at hand now, but we already (recently too, I
> think) discussed having these "we know it is infallible in the kernel"
> conversions. Maybe there was a patch posted even.
>
> Otherwise, I will create a good first issue.
Are you referring to this discussion?
https://lore.kernel.org/rust-for-linux/DDK4KADWJHMG.1FUPL3SDR26XF@kernel.org/
If so, I have posted something along those lines:
https://lore.kernel.org/rust-for-linux/20251029-nova-as-v3-4-6a30c7333ad9@nvidia.com/
We planned to have it stew in Nova for a bit, but I don't mind moving
this to the core code if you think that looks good enough.
^ permalink raw reply	[flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file()
  2025-11-01 14:27               ` Alexandre Courbot
@ 2025-11-01 15:06                 ` Miguel Ojeda
  0 siblings, 0 replies; 39+ messages in thread
From: Miguel Ojeda @ 2025-11-01 15:06 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Alice Ryhl, Danilo Krummrich, gregkh, rafael, ojeda, alex.gaynor,
	boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, tmgross, mmaurer,
	rust-for-linux, linux-fsdevel, linux-kernel
On Sat, Nov 1, 2025 at 3:27 PM Alexandre Courbot <acourbot@nvidia.com> wrote:
>
> Are you referring to this discussion?
>
> https://lore.kernel.org/rust-for-linux/DDK4KADWJHMG.1FUPL3SDR26XF@kernel.org/
I saw that one and the patches  -- perhaps it was in meetings, but
dealing with guarantees that are only true in the kernel (assumptions,
conversions) has come up before several times over the years.
Cheers,
Miguel
^ permalink raw reply	[flat|nested] 39+ messages in thread
end of thread, other threads:[~2025-11-01 15:07 UTC | newest]
Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-22 14:30 [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Danilo Krummrich
2025-10-22 14:30 ` [PATCH v3 01/10] rust: fs: add new type file::Offset Danilo Krummrich
2025-10-22 14:42   ` Miguel Ojeda
2025-10-24 12:15   ` Alice Ryhl
2025-10-28 11:04   ` Danilo Krummrich
2025-11-01 14:16   ` Alexandre Courbot
2025-10-22 14:30 ` [PATCH v3 02/10] rust: uaccess: add UserSliceReader::read_slice_partial() Danilo Krummrich
2025-10-24 10:39   ` Alice Ryhl
2025-11-01 14:16   ` Alexandre Courbot
2025-10-22 14:30 ` [PATCH v3 03/10] rust: uaccess: add UserSliceReader::read_slice_file() Danilo Krummrich
2025-11-01 14:16   ` Alexandre Courbot
2025-10-22 14:30 ` [PATCH v3 04/10] rust: uaccess: add UserSliceWriter::write_slice_partial() Danilo Krummrich
2025-10-23  8:33   ` Alice Ryhl
2025-10-28 13:57     ` Miguel Ojeda
2025-11-01 14:19   ` Alexandre Courbot
2025-10-22 14:30 ` [PATCH v3 05/10] rust: uaccess: add UserSliceWriter::write_slice_file() Danilo Krummrich
2025-10-23  8:30   ` Alice Ryhl
2025-10-23 10:35     ` Danilo Krummrich
2025-10-23 10:37       ` Alice Ryhl
2025-10-23 11:03         ` Danilo Krummrich
2025-10-23 11:20           ` Alice Ryhl
2025-10-23 12:43             ` Danilo Krummrich
2025-10-24 10:37               ` Alice Ryhl
2025-10-24 18:02             ` Miguel Ojeda
2025-11-01 14:27               ` Alexandre Courbot
2025-11-01 15:06                 ` Miguel Ojeda
2025-10-28 14:07   ` Miguel Ojeda
2025-10-22 14:30 ` [PATCH v3 06/10] rust: debugfs: support for binary large objects Danilo Krummrich
2025-10-23  8:26   ` Alice Ryhl
2025-10-23 10:09     ` Danilo Krummrich
2025-10-23 10:21       ` Alice Ryhl
2025-10-24 10:36         ` Alice Ryhl
2025-10-22 14:30 ` [PATCH v3 07/10] rust: debugfs: support blobs from smart pointers Danilo Krummrich
2025-10-23  8:24   ` Alice Ryhl
2025-10-22 14:30 ` [PATCH v3 08/10] samples: rust: debugfs: add example for blobs Danilo Krummrich
2025-10-22 14:30 ` [PATCH v3 09/10] rust: debugfs: support binary large objects for ScopedDir Danilo Krummrich
2025-10-23  8:23   ` Alice Ryhl
2025-10-22 14:30 ` [PATCH v3 10/10] samples: rust: debugfs_scoped: add example for blobs Danilo Krummrich
2025-10-28 13:47 ` [PATCH v3 00/10] Binary Large Objects for Rust DebugFS Miguel Ojeda
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).