From nobody Sat Feb 7 23:23:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42AA6277CBC; Fri, 3 Oct 2025 22:27:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530464; cv=none; b=FHaZ69Kf5uzxb1R+422nmCrxBGZbUWR27cXr3iTSoE0gSIfYeb4KUT5Rjh7ufFNIhkff9Be0AM8WSFHEkl0nALAG7CsdYBqGQEZISwVdKuHQSRCZk4Lcn+RyEnzrgXumaHsTSLpULYFRF+i8E6bKPnMWs1g9GnUwHiP5pL1l/Kw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530464; c=relaxed/simple; bh=cK7y8EM5TvD+LEZO2NL54xS3FHkoaVuyX5mtLhgeqTw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oDnlsjmK7T1l0gNbviRpij+zVpMgXOlMd03M1V1J8dHdFYf2E19ii6uFgE7UV/rz+kyHQYPt1u6+7LCS7Dk8ykcPiCWL2q7SSN2S/6CmWBGd7ws6Qgy3YsUKX9zmhtol6QeRpC5urxkicNVOX/iccJfeSd/pSraGPfbfdgSgDdU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jpO935GX; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jpO935GX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C2CF1C4CEFA; Fri, 3 Oct 2025 22:27:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759530463; bh=cK7y8EM5TvD+LEZO2NL54xS3FHkoaVuyX5mtLhgeqTw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jpO935GXwmuubNHKO8PZdEMZ34j+Bzb5ebPBrJMyBWQRTQ6rCT4vIND80m1FLHI+i 0dncc/xmb6T78zx7CzGtkuliF8ZA+c9AXEuHjAncahneG5fq+gtzLLS0+9clv2ObSg VTo4UODgItohkkYwb8TGVLehYChVnm8BdRx6J1WFMbmgqLwG+CHW5npwfHTSgp283t EcnHErrwhT1dkxrGuyLhBsHukg6SW1vVijXV6R4xhYwXMSY6wWIvCYp+R3tHFSakNp BAXntWN3fkM3sBIX7IZ0D+14z9vBzsbvmo1XVpehYxrYkdy1qBuyrpqiRj26tMlY+/ leNk9oGt6BVnw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, mmaurer@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 1/7] rust: uaccess: add UserSliceReader::read_slice_partial() Date: Sat, 4 Oct 2025 00:26:38 +0200 Message-ID: <20251003222729.322059-2-dakr@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251003222729.322059-1-dakr@kernel.org> References: <20251003222729.322059-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Danilo Krummrich --- rust/kernel/uaccess.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index a8fb4764185a..1b0b57e855c9 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -287,6 +287,19 @@ pub fn read_slice(&mut self, out: &mut [u8]) -> Result= { self.read_raw(out) } =20 + /// 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 { + let end =3D offset.checked_add(self.len()).ok_or(EINVAL)?.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 --=20 2.51.0 From nobody Sat Feb 7 23:23:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6957D27F00E; Fri, 3 Oct 2025 22:27:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530467; cv=none; b=G6vd+jaE8qgT5/qR7XD7Kd/dsJ06HHOxezYF4+i3YuHUkyVMTyTjJIRlLxBZQpa/ZZfvxliusc3rNyIb5KcUUKyG7KW3NBxryHj8EUyYZTarkmCdNPoNkSOCgobz+/BvvTCWABwf0mILxm5an2f1UjxvsACQRb0TcyHbJnVi9zY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530467; c=relaxed/simple; bh=cesWEHmZ+3NQRP/sufBInnvawZo33gpkGKGDDCg4HlU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=L3mYoq/BuwmaA5Zkjmw0+AncDVVOc6WKVJyAlEFk4eZ/BS0vfqQOTOOED4t6IYOm+E68vxvdqmPSlXJpv/NofQrYyE8q5BuQ0VVIzAFvpzzOqUtrj6SeSW7inXR5TZbAsGOvnvWo5OJOolIZNPBKfgMQYlfs50wsL9NJujKnNFY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aKYlFYek; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="aKYlFYek" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 43262C4CEFB; Fri, 3 Oct 2025 22:27:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759530467; bh=cesWEHmZ+3NQRP/sufBInnvawZo33gpkGKGDDCg4HlU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aKYlFYekw/MBFMa1LvgCTutwElWGkj5ljCjCxCC4JSY2rOKNhT8xi3UBJEcxzeKJf 9oIlW2p+powTRZCQCYtWKUJKw57+eg9LQSCG5tOSWhUcpW0ZOfWDFR6eGEwZfZgb1/ GRa93ZNaXBaadVBfdfmgtIq8oxfN8C+VglC5GtXdQuRsIGCuj3bffWsJLIlzKLGWPb XHB3NMGm+uBI0GVhULH0ZM4ZNEnRhUcXARLaj50Ajlpo76TMqmH2knJnmX1qYUvatd SF59I+C9q1vjoHFhjyV0jWS+5rv5CqQKRyjXW+u+3xXOyZmcw08a26bXjaID9qPnrY XrvxLcWO6JsEA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, mmaurer@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 2/7] rust: uaccess: add UserSliceWriter::write_slice_partial() Date: Sat, 4 Oct 2025 00:26:39 +0200 Message-ID: <20251003222729.322059-3-dakr@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251003222729.322059-1-dakr@kernel.org> References: <20251003222729.322059-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Danilo Krummrich --- rust/kernel/uaccess.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index 1b0b57e855c9..11bb8f3265dd 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -451,6 +451,22 @@ pub fn write_slice(&mut self, data: &[u8]) -> Result { Ok(()) } =20 + /// Writes raw data to this user pointer from a kernel buffer partiall= y. + /// + /// 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) -> R= esult { + let end =3D offset + .checked_add(self.len()) + .ok_or(EINVAL)? + .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 --=20 2.51.0 From nobody Sat Feb 7 23:23:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3C60828150F; Fri, 3 Oct 2025 22:27:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530471; cv=none; b=Ow7FjMmCGGc/EddMYdUdp3Mw4OCnHttqe2qgz4Zd6LLFoxgBbrRoYfPZfmnDb43jvH5FKLVAdyqvmUncdBWoz3RfPB59A9WbnTUA2zm5NiDfURL9AEUqHvLzLBUly+fuDVm4UHOcz1jnf9TmXIPFK+XsLzu5eBuWPuvxJPtcaaY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530471; c=relaxed/simple; bh=5vnz4yasBC0Hhb6h1iW1ddCoH9nAsko8iD/DvIfGCnI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rijgyL65ug1PO5U8rwpP6btFNXx1SMTGAoiyCp5bh9LzbQ4yBm8ogaS+iNULMWG9U/a2khVYbNgUs7hMcHrAbL5wnHLjJKjZSRVfuCK3gAxSh0IzPqJ+xKnpM8rbiCkLJl7AIhICz7ANNnxKiQn4QNeCIkODUXgubXdEYu/VLuQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=h0ByLGsu; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="h0ByLGsu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B7824C4CEF5; Fri, 3 Oct 2025 22:27:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759530470; bh=5vnz4yasBC0Hhb6h1iW1ddCoH9nAsko8iD/DvIfGCnI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=h0ByLGsuwwKQlgyt7WYENDU2CZIIzmiRwVEMX84xpD9YGDXUFDtLtwzNR48k3w2ZA YlbNwODSgE3UnbmTHIfMCTHfY4U7Onx7PokW6NF9iNDpRhpYB+DDti80OIkSHLEZTT Jma4Yw5jUnLrrxTwcLawPhMrqVvom4xLcPVRpGpaBhC/VNrh55FjtFAX1xQMOh5XxE UN4Njabn48/1/F2wU7TcRpwKW+iIdUJPt+VdtpX3ifUPBl9WJQxfoz5pXI7yq6wMkI qVI8ms56ouLrOUIsK2PfWcBNZsSnmEWtJwG79DelAX5TGotoUom4nlHWffOVNrZLFf nlHfgwFrfqKcQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, mmaurer@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 3/7] rust: debugfs: support for binary large objects Date: Sat, 4 Oct 2025 00:26:40 +0200 Message-ID: <20251003222729.322059-4-dakr@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251003222729.322059-1-dakr@kernel.org> References: <20251003222729.322059-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Danilo Krummrich --- rust/kernel/debugfs.rs | 67 ++++++++++++++- rust/kernel/debugfs/file_ops.rs | 144 +++++++++++++++++++++++++++++++- rust/kernel/debugfs/traits.rs | 45 +++++++++- 3 files changed, 249 insertions(+), 7 deletions(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 381c23b3dd83..b1a3adca7fd4 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -21,12 +21,15 @@ use core::ops::Deref; =20 mod traits; -pub use traits::{Reader, Writer}; +pub use traits::{BinaryReader, BinaryWriter, Reader, Writer}; =20 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, ReadFil= e, ReadWriteFile, + WriteFile, +}; #[cfg(CONFIG_DEBUG_FS)] mod entry; #[cfg(CONFIG_DEBUG_FS)] @@ -150,6 +153,33 @@ pub fn read_only_file<'a, T, E: 'a>( self.create_file(name, data, file_ops) } =20 + /// 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 =3D Dir::new(c_str!("my_debugfs_dir")); + /// let file =3D KBox::pin_init(dir.read_binary_file(c_str!("foo"), [0= x1, 0x2]), GFP_KERNEL)?; + /// # Ok::<(), Error>(()) + /// ``` + pub fn read_binary_file<'a, T, E: 'a>( + &'a self, + name: &'a CStr, + data: impl PinInit + 'a, + ) -> impl PinInit, E> + 'a + where + T: BinaryWriter + Send + Sync + 'static, + { + let file_ops =3D &>::FILE_OPS; + self.create_file(name, data, file_ops) + } + /// Creates a read-only file in this directory, with contents from a c= allback. /// /// `f` must be a function item or a non-capturing closure. @@ -206,6 +236,22 @@ pub fn read_write_file<'a, T, E: 'a>( self.create_file(name, data, file_ops) } =20 + /// 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 + 'a, + ) -> impl PinInit, E> + 'a + where + T: BinaryWriter + BinaryReader + Send + Sync + 'static, + { + let file_ops =3D &>::FILE_OPS; + self.create_file(name, data, file_ops) + } + /// Creates a read-write file in this directory, with logic from callb= acks. /// /// Reading from the file is handled by `f`. Writing to the file is ha= ndled by `w`. @@ -248,6 +294,23 @@ pub fn write_only_file<'a, T, E: 'a>( self.create_file(name, data, &T::FILE_OPS) } =20 + /// Creates a write-only binary file in this directory. + /// + /// The file owns its backing data. Writing to the file uses the [`Bin= aryReader`] + /// 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 + 'a, + ) -> impl PinInit, 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..ef31cac4cd44 100644 --- a/rust/kernel/debugfs/file_ops.rs +++ b/rust/kernel/debugfs/file_ops.rs @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2025 Google LLC. =20 -use super::{Reader, Writer}; +use super::{BinaryReader, BinaryWriter, Reader, Writer}; use crate::debugfs::callback_adapters::Adapter; 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; =20 #[cfg(CONFIG_DEBUG_FS)] @@ -65,8 +65,8 @@ fn deref(&self) -> &Self::Target { =20 struct WriterAdapter(T); =20 -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 +245,139 @@ impl WriteFile for T { unsafe { FileOps::new(operations, 0o200) } }; } + +extern "C" fn blob_read( + 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` po= ints to a valid `T`. + let this =3D unsafe { &*((*file).private_data.cast::()) }; + + // SAFETY: `ppos` is a valid `loff_t` pointer. + let pos =3D unsafe { &mut *ppos }; + + let mut writer =3D UserSlice::new(UserPtr::from_ptr(buf.cast()), count= ).writer(); + + let ret =3D || -> Result { + let offset =3D (*pos).try_into()?; + + let written =3D this.write_to_slice(&mut writer, offset)?; + *pos +=3D bindings::loff_t::try_from(written)?; + + Ok(written.try_into()?) + }(); + + match ret { + Ok(n) =3D> n, + Err(e) =3D> e.to_errno() as isize, + } +} + +pub(crate) trait BinaryReadFile { + const FILE_OPS: FileOps; +} + +impl BinaryReadFile for T { + const FILE_OPS: FileOps =3D { + let operations =3D bindings::file_operations { + read: Some(blob_read::), + 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 poin= ter to a valid `T`. + // - `simple_open()` stores the `struct inode`'s private data in t= he 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 privat= e data. + unsafe { FileOps::new(operations, 0o400) } + }; +} + +extern "C" fn blob_write( + 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` po= ints to a valid `T`. + let this =3D unsafe { &*((*file).private_data.cast::()) }; + + // SAFETY: `ppos` is a valid `loff_t` pointer. + let pos =3D unsafe { &mut *ppos }; + + let mut reader =3D UserSlice::new(UserPtr::from_ptr(buf.cast_mut().cas= t()), count).reader(); + + let ret =3D || -> Result { + let offset =3D (*pos).try_into()?; + + let read =3D this.read_from_slice(&mut reader, offset)?; + *pos +=3D bindings::loff_t::try_from(read)?; + + Ok(read.try_into()?) + }(); + + match ret { + Ok(n) =3D> n, + Err(e) =3D> e.to_errno() as isize, + } +} + +pub(crate) trait BinaryWriteFile { + const FILE_OPS: FileOps; +} + +impl BinaryWriteFile for T { + const FILE_OPS: FileOps =3D { + let operations =3D bindings::file_operations { + write: Some(blob_write::), + 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 poin= ter to a valid `T`. + // - `simple_open()` stores the `struct inode`'s private data in t= he 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 privat= e data. + unsafe { FileOps::new(operations, 0o200) } + }; +} + +pub(crate) trait BinaryReadWriteFile { + const FILE_OPS: FileOps; +} + +impl BinaryReadWriteFile for T { + const FILE_OPS: FileOps =3D { + let operations =3D bindings::file_operations { + read: Some(blob_read::), + write: Some(blob_write::), + 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 poin= ter to a valid `T`. + // - `simple_open()` stores the `struct inode`'s private data in t= he 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 privat= e data. + unsafe { FileOps::new(operations, 0o600) } + }; +} diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs index ab009eb254b3..60a6ee6c6b58 100644 --- a/rust/kernel/debugfs/traits.rs +++ b/rust/kernel/debugfs/traits.rs @@ -5,7 +5,8 @@ =20 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 +40,30 @@ fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { } } =20 +/// 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: usize) = -> Result; +} + +impl BinaryWriter for T { + fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { + writer.write_slice_partial(self.as_bytes(), offset) + } +} + +impl BinaryWriter for Mutex { + fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { + let guard =3D 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 +91,24 @@ fn read_from_slice(&self, reader: &mut UserSliceReader) = -> Result { } } =20 +/// 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: usize)= -> Result; +} + +impl BinaryReader for Mutex { + fn read_from_slice(&self, reader: &mut UserSliceReader, offset: usize)= -> Result { + let mut this =3D self.lock(); + + reader.read_slice_partial(this.as_bytes_mut(), offset) + } +} + macro_rules! impl_reader_for_atomic { ($(($atomic_type:ty, $int_type:ty)),*) =3D> { $( --=20 2.51.0 From nobody Sat Feb 7 23:23:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF29C2EC099; Fri, 3 Oct 2025 22:27:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530474; cv=none; b=B0nmWJxK2wpoZfxPhEJGzPF1kIuUBDfuiJ7NhTH1KXbZF3MU3OaxpyIgRAUHnK0xDiR8SaVbOPE26qsCe5OLxfJ+7eThOpQsQoW1CrnX6BwQPScxvZDnW5XdgzYl1M1DwltaO4oNrucRAuakxv2DrZ0QRgN3grPeCTi1xZ58EuQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530474; c=relaxed/simple; bh=u53Uk/PsduccUptjZR9Ccs65J+jFhHu+M/uud08l/Fc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LwwNRy3t0cpwWguwlb9/CZIXqPuEjBALvrlTJWjKd5kNPh4rTirQzGKGGESS9lM9Sh0QdhOrJXDpdtn+9GQuzDh6rUgxyKal++aulxmMdIM9qyRUZgES3jxLg3XEc/rW22DOfdXfsusTMXDG72sgHuIEfsPDkRdhSDknfwxlcs8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nPIGjXCD; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nPIGjXCD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 37BD7C4CEFA; Fri, 3 Oct 2025 22:27:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759530474; bh=u53Uk/PsduccUptjZR9Ccs65J+jFhHu+M/uud08l/Fc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nPIGjXCD2b24WQW+CqGX9OzRI+NTfiO1boYYrR/tZJMHxfJ6txgE5AeXTNClZ2NQ4 loDnYoxQ9M4Rr8kBWxdKjXRPHUr3azREs/VOVxaUmdXM+zy5xCkVYVl8wUtLtaRVgl JP8JwOZzQkPf22nN+PaHfTpBFsiw2RVeOJtGvxRqPZmBEJVkdS7ebRLhTdRJw9VvL+ B5opazvKVW19aMrHgkLrB62cl32rEvqrH/DU5zbbK5r3j4ZvOlt82/41574ZCqKhdS 5w/2v8L4NCcK5FreWzTV2qA22wKksELLK4VmTyKP3yiakLjecFuQqH69xCrGgh2m2X SlOy5WpDpBLmQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, mmaurer@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 4/7] rust: debugfs: support blobs from smart pointers Date: Sat, 4 Oct 2025 00:26:41 +0200 Message-ID: <20251003222729.322059-5-dakr@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251003222729.322059-1-dakr@kernel.org> References: <20251003222729.322059-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend Rust debugfs binary support to allow exposing data stored in common smart pointers and heap-allocated collections. - Implement BinaryWriter for Box, Pin>, Arc, and Vec. - Introduce BinaryReaderMut for mutable binary access with outer locks. - Implement BinaryReaderMut for Box, Vec, and base types. - Update BinaryReader to delegate to BinaryReaderMut for Mutex, Box, Pin> and Arc. 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. Signed-off-by: Danilo Krummrich --- rust/kernel/debugfs.rs | 2 +- rust/kernel/debugfs/traits.rs | 145 +++++++++++++++++++++++++++++++++- 2 files changed, 144 insertions(+), 3 deletions(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index b1a3adca7fd4..3c3bbcc126ef 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -21,7 +21,7 @@ use core::ops::Deref; =20 mod traits; -pub use traits::{BinaryReader, BinaryWriter, Reader, Writer}; +pub use traits::{BinaryReader, BinaryReaderMut, BinaryWriter, Reader, Writ= er}; =20 mod callback_adapters; use callback_adapters::{FormatAdapter, NoWriter, WritableAdapter}; diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs index 60a6ee6c6b58..bcd0a9db3cc9 100644 --- a/rust/kernel/debugfs/traits.rs +++ b/rust/kernel/debugfs/traits.rs @@ -3,11 +3,14 @@ =20 //! Traits for rendering or updating values exported to DebugFS. =20 +use crate::alloc::Allocator; 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, Ato= micU32, AtomicU64, @@ -50,12 +53,14 @@ pub trait BinaryWriter { fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result; } =20 +// Base implementation for any `T: AsBytes`. impl BinaryWriter for T { fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { writer.write_slice_partial(self.as_bytes(), offset) } } =20 +// Delegate for `Mutex`: Support a `T` with an outer mutex. impl BinaryWriter for Mutex { fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { let guard =3D self.lock(); @@ -64,6 +69,56 @@ fn write_to_slice(&self, writer: &mut UserSliceWriter, o= ffset: usize) -> Result< } } =20 +// Delegate for `Box`: Support a `Box` with no lock or an inne= r lock. +impl BinaryWriter for Box +where + T: BinaryWriter, + A: Allocator, +{ + fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { + self.deref().write_to_slice(writer, offset) + } +} + +// Delegate for `Pin>`: Support a `Pin>` with no lock = or an inner lock. +impl BinaryWriter for Pin> +where + T: BinaryWriter, + A: Allocator, +{ + fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { + self.deref().write_to_slice(writer, offset) + } +} + +// Delegate for `Arc`: Support a `Arc` with no lock or an inner lock. +impl BinaryWriter for Arc +where + T: BinaryWriter, +{ + fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { + self.deref().write_to_slice(writer, offset) + } +} + +// Delegate for `Vec`. +impl BinaryWriter for Vec +where + T: AsBytes, + A: Allocator, +{ + fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: usize) = -> Result { + let slice =3D self.as_slice(); + + // SAFETY: `T: AsBytes` allows us to treat `&[T]` as `&[u8]`. + let buffer =3D unsafe { + core::slice::from_raw_parts(slice.as_ptr().cast(), core::mem::= size_of_val(slice)) + }; + + writer.write_slice_partial(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. @@ -92,6 +147,70 @@ fn read_from_slice(&self, reader: &mut UserSliceReader)= -> Result { } =20 /// 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 ref= erence. + /// + /// `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= : usize) + -> Result; +} + +// Base implementation for any `T: AsBytes + FromBytes`. +impl BinaryReaderMut for T { + fn read_from_slice_mut( + &mut self, + reader: &mut UserSliceReader, + offset: usize, + ) -> Result { + reader.read_slice_partial(self.as_bytes_mut(), offset) + } +} + +// Delegate for `Box`: Support a `Box` with an outer lock. +impl BinaryReaderMut for Box { + fn read_from_slice_mut( + &mut self, + reader: &mut UserSliceReader, + offset: usize, + ) -> Result { + self.deref_mut().read_from_slice_mut(reader, offset) + } +} + +// Delegate for `Vec`: Support a `Vec` with an outer lock. +impl BinaryReaderMut for Vec +where + T: AsBytes + FromBytes, + A: Allocator, +{ + fn read_from_slice_mut( + &mut self, + reader: &mut UserSliceReader, + offset: usize, + ) -> Result { + let slice =3D self.as_mut_slice(); + + // SAFETY: `T: AsBytes` allows us to treat `&[T]` as `&[u8]`. + let buffer =3D unsafe { + core::slice::from_raw_parts_mut( + slice.as_mut_ptr().cast(), + core::mem::size_of_val(slice), + ) + }; + + reader.read_slice_partial(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`. /// @@ -101,11 +220,33 @@ pub trait BinaryReader { fn read_from_slice(&self, reader: &mut UserSliceReader, offset: usize)= -> Result; } =20 -impl BinaryReader for Mutex { +// Delegate for `Mutex`: Support a `T` with an outer `Mutex`. +impl BinaryReader for Mutex { fn read_from_slice(&self, reader: &mut UserSliceReader, offset: usize)= -> Result { let mut this =3D self.lock(); =20 - reader.read_slice_partial(this.as_bytes_mut(), offset) + this.read_from_slice_mut(reader, offset) + } +} + +// Delegate for `Box`: Support a `Box` with an inner lock. +impl BinaryReader for Box { + fn read_from_slice(&self, reader: &mut UserSliceReader, offset: usize)= -> Result { + self.deref().read_from_slice(reader, offset) + } +} + +// Delegate for `Pin>`: Support a `Pin>` with an inner= lock. +impl BinaryReader for Pin> { + fn read_from_slice(&self, reader: &mut UserSliceReader, offset: usize)= -> Result { + self.deref().read_from_slice(reader, offset) + } +} + +// Delegate for `Arc`: Support an `Arc` with an inner lock. +impl BinaryReader for Arc { + fn read_from_slice(&self, reader: &mut UserSliceReader, offset: usize)= -> Result { + self.deref().read_from_slice(reader, offset) } } =20 --=20 2.51.0 From nobody Sat Feb 7 23:23:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2640E284896; Fri, 3 Oct 2025 22:27:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530478; cv=none; b=bVFwrt9FkLOzwmdzZnvyYjIEEMzRQf40XhbWoF0Du99olfvcaxI2pvkZTUd4l7FAhIu5P41Gb8ZTWU/qEE6fOHngPXvxofLG3G/HZwbNf/ouheqpbTNolWu6MPk9NEo0aZML13+lbtDE46qF0S/WfLdS+aYkRcsyci34hIYyp48= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530478; c=relaxed/simple; bh=VNb5eDcF8RARULTBHZCZEkai56X5jDRHIAV+rCYZit4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ajs8qyJv9DIetbw9wOLGdw4aSuHEoi1uzHc4Cun/+bHt69iYmqLbXkJWJbhqEZTWOVDNLeGmlpqyEUqIdZDPlj0UpzwEoG5E+abd5+up5RbuJ5C+MPsBIlCcKhCx+iahtSGWuUCA3sADWL8+1bjPRkU/cW7ni7iqj6eFfBI0cEg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=i9UubbHC; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="i9UubbHC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AB81FC4CEFB; Fri, 3 Oct 2025 22:27:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759530477; bh=VNb5eDcF8RARULTBHZCZEkai56X5jDRHIAV+rCYZit4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=i9UubbHCOsGYzO0fLDPWQtj83RCwmONyYz7iokKv7Rkf6R3fPhqc09DSqvfULIKnr ztT7uferkG+oyNlY8mzjALssn4vgUhTDRMaaiNnjx8AmMLSNutw/ZrRleHC44NGygq k7RQPH6OEoGQFJ2YO6TIGGMuk8fhFkyJKnDDqMAR3g1VtZ7hP30lylXV2t/r4gdDRV Dzoqn4unSXs7Nz2fL3yGCsziL/wctTdjc+EnibyjxZSK3Sp1Mzs71KrY4icBRQ9UE6 t4ZVkSn6d+WnMuGTNgvGLvQwh9E8lRm1oAV5k4mAZrN5ejLcMhk1q3LMYG+db+G0u6 fMpqslOX2Inig== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, mmaurer@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 5/7] samples: rust: debugfs: add example for blobs Date: Sat, 4 Oct 2025 00:26:42 +0200 Message-ID: <20251003222729.322059-6-dakr@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251003222729.322059-1-dakr@kernel.org> References: <20251003222729.322059-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- 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; =20 use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef}; @@ -62,6 +63,10 @@ struct RustDebugFs { counter: File, #[pin] inner: File>, + #[pin] + array_blob: File>, + #[pin] + vector_blob: File>>, } =20 #[derive(Debug)] @@ -143,6 +148,14 @@ fn new(pdev: &platform::Device) -> 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(), } --=20 2.51.0 From nobody Sat Feb 7 23:23:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F89B284896; Fri, 3 Oct 2025 22:28:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530481; cv=none; b=XCWEnAxisKJjMpzopWX7G/9WXkC8BTNGzlnLQ/wW0BwkI4Ify9YaglZSHeN++qFsGb8HiJ1bvRj4uwLsWrUW486fY1nBUWJmSTkRUMvNlwwKvhjMYV7zQoWdDe2W7PnlSVoyEWqRV1jPcoKqcqmfhYBXc3Q0O/CMVz+YfIEPLS8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530481; c=relaxed/simple; bh=Pa3T2gqcpn0BfO0PymfzEhzrhpkSorm3T1eSWoUkyH0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Zmmvs1ANAB1+FO2B/1ve4NksFMXnQTvKudXsmzVpV2qWU1Hx2j8Hj8U+UYnO1yElxCLaDc2+O1VfP1IS2NQZpV4AApTEEnghMLT1ZASRE28H3tmUtfGmp44dRm2jr/UfDAqj96Y/sWdZdF+fBbTjq1l56qXjlzQcxCqoYRpHYy4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XYDj+wTO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XYDj+wTO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2B039C4CEF5; Fri, 3 Oct 2025 22:27:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759530481; bh=Pa3T2gqcpn0BfO0PymfzEhzrhpkSorm3T1eSWoUkyH0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XYDj+wTODqHxaHbquId7LGMtxNt3goBHrAQ9vkcFhKnFu86t98L9ASjTBy+temGYe LGlRrqKOWIEUyZzoCe58MRv8+kHH17UDU/NeqS+aAyrsSL1krOzcO838w5jf0i1Rxq skBqyqClUr69XUO06ONTokhbuou8XbD4foQA/ZBALQT9psjGZvDOPiarmr31jJwKKD hcA9+ojKhOsGS5+K/w2Fgho0yu5ULXRATqow1Cr/clMPSMb+En2DX/EU3qz5s+8ysY ugKMVRk+BnsJbzOv+osFlzdwgLpjCTWbvrmYeWy73XRT9/FEmZDsRSJppusmCuqjP8 AIzvt+WLonTNg== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, mmaurer@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 6/7] rust: debugfs: support binary large objects for ScopedDir Date: Sat, 4 Oct 2025 00:26:43 +0200 Message-ID: <20251003222729.322059-7-dakr@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251003222729.322059-1-dakr@kernel.org> References: <20251003222729.322059-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Danilo Krummrich --- rust/kernel/debugfs.rs | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 3c3bbcc126ef..0eb1719e4953 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -531,6 +531,20 @@ pub fn read_only_file(&self, name: &CStr, dat self.create_file(name, data, &T::FILE_OPS) } =20 + /// 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 c= reated file is removed + /// when the [`Scope`] that this directory belongs to is dropped. + pub fn read_binary_file( + &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 c= allback. /// /// The file contents are generated by calling `f` with `data`. @@ -568,6 +582,22 @@ pub fn read_write_file( self.create_file(name, data, vtable) } =20 + /// 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 c= reated file is removed + /// when the [`Scope`] that this directory belongs to is dropped. + pub fn read_write_binary_file( + &self, + name: &CStr, + data: &'data T, + ) { + let vtable =3D &>::FILE_OPS; + self.create_file(name, data, vtable) + } + /// Creates a read-write file in this directory, with logic from callb= acks. /// /// Reading from the file is handled by `f`. Writing to the file is ha= ndled by `w`. @@ -607,6 +637,21 @@ pub fn write_only_file(&self, name: &CStr, da self.create_file(name, data, vtable) } =20 + /// Creates a write-only binary file in this directory. + /// + /// Writing to the file uses the [`BinaryReader`] implementation on `d= ata`. + /// + /// This function does not produce an owning handle to the file. The c= reated file is removed + /// when the [`Scope`] that this directory belongs to is dropped. + pub fn write_binary_file( + &self, + name: &CStr, + data: &'data T, + ) { + let vtable =3D &>::FILE_OPS; + self.create_file(name, data, vtable) + } + /// Creates a write-only file in this directory, with write logic from= a callback. /// /// Writing to the file is handled by `w`. --=20 2.51.0 From nobody Sat Feb 7 23:23:17 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C343E2882D3; Fri, 3 Oct 2025 22:28:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530484; cv=none; b=WPjq4B20E1HiyRWvHbBAnZNz49RYNPuwOQ89CuL1WxKie/L37LzQVMHGKvoGxAyI7qBUiRVKG6L4uiEuamL9amu720RiSMZnzBnrgqVcW5sFNNDWk8/0Em0AiDZMvhpnSDV8HrzLMg3AV9VTJRO1t3dPssXs2Yclfkhk74Jydwc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759530484; c=relaxed/simple; bh=aDaaWLZWxHoJ8yRtUHn3xfnO38OT1PRhYVazKvf9Jn8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SpMr4yQkahRxDSsb1X2nnDzNh+ceNUc9IxNJ3wfrjetI3Erf4dulWlz3dWapKkhZ5Lx8x02R7QFcUx8xjvj9Oz9sL5Q2CNSjG+SOKxH5OD4K0dJOatjD4v/2IWD+SPfSD2nFDBDkP8gkTbI8pna+lRAH/bicg7FDVlJmS5jOztk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PM2scPTp; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PM2scPTp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9E6D8C4CEF5; Fri, 3 Oct 2025 22:28:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759530484; bh=aDaaWLZWxHoJ8yRtUHn3xfnO38OT1PRhYVazKvf9Jn8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PM2scPTpX4mPaC4KOPuJqno8K3q8PjltayT6nBnwIv+jZa5NSAUp2/fEZHF/sImTo i76YsL0apNCONjEnGpISCH8Fzv9KoLk1u8jzATZS14e0U0gz8hiFJsVQCxWw9iXM5g tB5H8r5bLSDRBhAfpPnhhWNYhmAf2jeqYZsJXWyuh8VjW3RFTWFPlad+vgrVBjNSX2 A2STlFQqdr/RspvxUEIyl7ZVDI3zcsllBdxYoCfXs+b2m3vkXWZ8VjrHMWkvn4z1lc /76f9urGJ4kOh3GuiU1A0cq+TdQjXGuTJQDyUOZ5/bqx9x7soEEVpco0e2vJfTY2C2 7GTdMUST73oog== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, mmaurer@google.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 7/7] samples: rust: debugfs_scoped: add example for blobs Date: Sat, 4 Oct 2025 00:26:44 +0200 Message-ID: <20251003222729.322059-8-dakr@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251003222729.322059-1-dakr@kernel.org> References: <20251003222729.322059-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend the rust_debugfs_scoped sample to demonstrate how to export a large binary object through a ScopedDir. Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- 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_debugf= s_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}; =20 @@ -66,18 +67,22 @@ fn create_file_write( GFP_KERNEL, )?; } + let blob =3D KBox::pin_init(new_mutex!([0x42; SZ_4K]), GFP_KERNEL)?; =20 let scope =3D 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) =3D 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 { struct DeviceData { name: CString, nums: KVec, + blob: Pin>>, } =20 fn init_control(base_dir: &Dir, dyn_dirs: Dir) -> impl PinInit> + '_ { --=20 2.51.0