From b0af4f9142d046e6564479a3afb1b35479d81039 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:27 -0400 Subject: rust: alloc: use `kernel::fmt` Reduce coupling to implementation details of the formatting machinery by avoiding direct use for `core`'s formatting traits and macros. This backslid in commit 9def0d0a2a1c ("rust: alloc: add Vec::push_within_capacity"). Reviewed-by: Alice Ryhl Acked-by: Danilo Krummrich Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251018-cstr-core-v18-6-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/kvec/errors.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/alloc/kvec/errors.rs b/rust/kernel/alloc/kvec/errors.rs index 21a920a4b09b..e7de5049ee47 100644 --- a/rust/kernel/alloc/kvec/errors.rs +++ b/rust/kernel/alloc/kvec/errors.rs @@ -2,14 +2,14 @@ //! Errors for the [`Vec`] type. -use kernel::fmt::{self, Debug, Formatter}; +use kernel::fmt; use kernel::prelude::*; /// Error type for [`Vec::push_within_capacity`]. pub struct PushError(pub T); -impl Debug for PushError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl fmt::Debug for PushError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Not enough capacity") } } @@ -25,8 +25,8 @@ impl From> for Error { /// Error type for [`Vec::remove`]. pub struct RemoveError; -impl Debug for RemoveError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl fmt::Debug for RemoveError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Index out of bounds") } } @@ -45,8 +45,8 @@ pub enum InsertError { OutOfCapacity(T), } -impl Debug for InsertError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl fmt::Debug for InsertError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { InsertError::IndexOutOfBounds(_) => write!(f, "Index out of bounds"), InsertError::OutOfCapacity(_) => write!(f, "Not enough capacity"), -- cgit v1.2.3 From 3f0dd5fad9ac275648bd7407f032a8b7adaf204f Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:28 -0400 Subject: rust: debugfs: use `kernel::fmt` Reduce coupling to implementation details of the formatting machinery by avoiding direct use for `core`'s formatting traits and macros. This backslid in commit 40ecc49466c8 ("rust: debugfs: Add support for callback-based files") and commit 5e40b591cb46 ("rust: debugfs: Add support for read-only files"). Acked-by: Danilo Krummrich Reviewed-by: Matthew Maurer Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251018-cstr-core-v18-7-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/debugfs.rs | 2 +- rust/kernel/debugfs/callback_adapters.rs | 7 +++---- rust/kernel/debugfs/file_ops.rs | 6 +++--- rust/kernel/debugfs/traits.rs | 10 +++++----- 4 files changed, 12 insertions(+), 13 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 381c23b3dd83..8c35d032acfe 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -8,12 +8,12 @@ // When DebugFS is disabled, many parameters are dead. Linting for this isn't helpful. #![cfg_attr(not(CONFIG_DEBUG_FS), allow(unused_variables))] +use crate::fmt; use crate::prelude::*; use crate::str::CStr; #[cfg(CONFIG_DEBUG_FS)] use crate::sync::Arc; use crate::uaccess::UserSliceReader; -use core::fmt; use core::marker::PhantomData; use core::marker::PhantomPinned; #[cfg(CONFIG_DEBUG_FS)] diff --git a/rust/kernel/debugfs/callback_adapters.rs b/rust/kernel/debugfs/callback_adapters.rs index 6c024230f676..a260d8dee051 100644 --- a/rust/kernel/debugfs/callback_adapters.rs +++ b/rust/kernel/debugfs/callback_adapters.rs @@ -5,10 +5,9 @@ //! than a trait implementation. If provided, it will override the trait implementation. use super::{Reader, Writer}; +use crate::fmt; use crate::prelude::*; use crate::uaccess::UserSliceReader; -use core::fmt; -use core::fmt::Formatter; use core::marker::PhantomData; use core::ops::Deref; @@ -76,9 +75,9 @@ impl Deref for FormatAdapter { impl Writer for FormatAdapter where - F: Fn(&D, &mut Formatter<'_>) -> fmt::Result + 'static, + F: Fn(&D, &mut fmt::Formatter<'_>) -> fmt::Result + 'static, { - fn write(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + fn write(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { // SAFETY: FormatAdapter<_, F> can only be constructed if F is inhabited let f: &F = unsafe { materialize_zst() }; f(&self.inner, fmt) diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs index 50fead17b6f3..9ad5e3fa6f69 100644 --- a/rust/kernel/debugfs/file_ops.rs +++ b/rust/kernel/debugfs/file_ops.rs @@ -3,11 +3,11 @@ use super::{Reader, Writer}; use crate::debugfs::callback_adapters::Adapter; +use crate::fmt; use crate::prelude::*; use crate::seq_file::SeqFile; use crate::seq_print; use crate::uaccess::UserSlice; -use core::fmt::{Display, Formatter, Result}; use core::marker::PhantomData; #[cfg(CONFIG_DEBUG_FS)] @@ -65,8 +65,8 @@ impl Deref for FileOps { struct WriterAdapter(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) } } diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs index ab009eb254b3..ad33bfbc7669 100644 --- a/rust/kernel/debugfs/traits.rs +++ b/rust/kernel/debugfs/traits.rs @@ -3,10 +3,10 @@ //! Traits for rendering or updating values exported to DebugFS. +use crate::fmt; use crate::prelude::*; use crate::sync::Mutex; use crate::uaccess::UserSliceReader; -use core::fmt::{self, Debug, Formatter}; use core::str::FromStr; use core::sync::atomic::{ AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, @@ -24,17 +24,17 @@ use core::sync::atomic::{ /// explicitly instead. pub trait Writer { /// Formats the value using the given formatter. - fn write(&self, f: &mut Formatter<'_>) -> fmt::Result; + fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; } impl Writer for Mutex { - fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.lock().write(f) } } -impl Writer for T { - fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Writer for T { + fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{self:?}") } } -- cgit v1.2.3 From 0e947bc22b0bdac7f708a0c6856f5999baff7b5d Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:29 -0400 Subject: rust: pci: use `kernel::fmt` Reduce coupling to implementation details of the formatting machinery by avoiding direct use for `core`'s formatting traits and macros. This backslid in commit ed78a01887e2 ("rust: pci: provide access to PCI Class and Class-related items"). Acked-by: Danilo Krummrich Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251018-cstr-core-v18-8-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/pci/id.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/pci/id.rs b/rust/kernel/pci/id.rs index 7f2a7f57507f..5f5d59ff49fc 100644 --- a/rust/kernel/pci/id.rs +++ b/rust/kernel/pci/id.rs @@ -4,8 +4,7 @@ //! //! This module contains PCI class codes, Vendor IDs, and supporting types. -use crate::{bindings, error::code::EINVAL, error::Error, prelude::*}; -use core::fmt; +use crate::{bindings, error::code::EINVAL, error::Error, fmt, prelude::*}; /// PCI device class codes. /// -- cgit v1.2.3 From 5b60cde74bb77aaec72d47fc208e4b057f618336 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:30 -0400 Subject: rust: remove spurious `use core::fmt::Debug` We want folks to use `kernel::fmt` but this is only used for `derive` so can be removed entirely. This backslid in commit ea60cea07d8c ("rust: add `Alignment` type"). Reviewed-by: Alice Ryhl Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251018-cstr-core-v18-9-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/ptr.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'rust/kernel') diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs index 2e5e2a090480..e3893ed04049 100644 --- a/rust/kernel/ptr.rs +++ b/rust/kernel/ptr.rs @@ -2,7 +2,6 @@ //! Types and functions to work with pointers and addresses. -use core::fmt::Debug; use core::mem::align_of; use core::num::NonZero; -- cgit v1.2.3 From 965a39a9627bfaee5a4f7471097439da19008338 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:31 -0400 Subject: rust: opp: use `CStr::as_char_ptr` Replace the use of `as_ptr` which works through `::deref()` in preparation for replacing `kernel::str::CStr` with `core::ffi::CStr` as the latter does not implement `Deref`. Signed-off-by: Tamir Duberstein Acked-by: Viresh Kumar Link: https://patch.msgid.link/20251018-cstr-core-v18-10-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/opp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index 2c763fa9276d..9d6c58178a6f 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -13,7 +13,7 @@ use crate::{ cpumask::{Cpumask, CpumaskVar}, device::Device, error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR}, - ffi::c_ulong, + ffi::{c_char, c_ulong}, prelude::*, str::CString, sync::aref::{ARef, AlwaysRefCounted}, @@ -88,12 +88,12 @@ use core::{marker::PhantomData, ptr}; use macros::vtable; /// Creates a null-terminated slice of pointers to [`Cstring`]s. -fn to_c_str_array(names: &[CString]) -> Result> { +fn to_c_str_array(names: &[CString]) -> Result> { // Allocated a null-terminated vector of pointers. let mut list = KVec::with_capacity(names.len() + 1, GFP_KERNEL)?; for name in names.iter() { - list.push(name.as_ptr().cast(), GFP_KERNEL)?; + list.push(name.as_char_ptr(), GFP_KERNEL)?; } list.push(ptr::null(), GFP_KERNEL)?; -- cgit v1.2.3 From 3b46f65355c9627efd2dd8180c96b006a44d30f8 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:33 -0400 Subject: rust: configfs: use `CStr::as_char_ptr` Replace the use of `as_ptr` which works through `::deref()` in preparation for replacing `kernel::str::CStr` with `core::ffi::CStr` as the latter does not implement `Deref`. Signed-off-by: Tamir Duberstein Acked-by: Andreas Hindborg Link: https://patch.msgid.link/20251018-cstr-core-v18-12-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/configfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel') diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs index 10f1547ca9f1..466fb7f40762 100644 --- a/rust/kernel/configfs.rs +++ b/rust/kernel/configfs.rs @@ -157,7 +157,7 @@ impl Subsystem { unsafe { bindings::config_group_init_type_name( &mut (*place.get()).su_group, - name.as_ptr(), + name.as_char_ptr(), item_type.as_ptr(), ) }; -- cgit v1.2.3 From 9ce084e579bf550ee92b1ecbadf1c29a76c1062c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:34 -0400 Subject: rust: regulator: use `CStr::as_char_ptr` Replace the use of `as_ptr` which works through `::deref()` in preparation for replacing `kernel::str::CStr` with `core::ffi::CStr` as the latter does not implement `Deref`. Signed-off-by: Tamir Duberstein Acked-by: Mark Brown Reviewed-by: Daniel Almeida Link: https://patch.msgid.link/20251018-cstr-core-v18-13-9378a54385f8@gmail.com [ Move safety comment below to support older Clippy. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/regulator.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs index b55a201e5029..2c44827ad0b7 100644 --- a/rust/kernel/regulator.rs +++ b/rust/kernel/regulator.rs @@ -84,7 +84,7 @@ pub struct Error { pub fn devm_enable(dev: &Device, name: &CStr) -> Result { // SAFETY: `dev` is a valid and bound device, while `name` is a valid C // string. - to_result(unsafe { bindings::devm_regulator_get_enable(dev.as_raw(), name.as_ptr()) }) + to_result(unsafe { bindings::devm_regulator_get_enable(dev.as_raw(), name.as_char_ptr()) }) } /// Same as [`devm_enable`], but calls `devm_regulator_get_enable_optional` @@ -102,7 +102,9 @@ pub fn devm_enable(dev: &Device, name: &CStr) -> Result { pub fn devm_enable_optional(dev: &Device, name: &CStr) -> Result { // SAFETY: `dev` is a valid and bound device, while `name` is a valid C // string. - to_result(unsafe { bindings::devm_regulator_get_enable_optional(dev.as_raw(), name.as_ptr()) }) + to_result(unsafe { + bindings::devm_regulator_get_enable_optional(dev.as_raw(), name.as_char_ptr()) + }) } /// A `struct regulator` abstraction. @@ -266,9 +268,10 @@ impl Regulator { } fn get_internal(dev: &Device, name: &CStr) -> Result> { - // SAFETY: It is safe to call `regulator_get()`, on a device pointer - // received from the C code. - let inner = from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_ptr()) })?; + let inner = + // SAFETY: It is safe to call `regulator_get()`, on a device pointer + // received from the C code. + from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_char_ptr()) })?; // SAFETY: We can safely trust `inner` to be a pointer to a valid // regulator if `ERR_PTR` was not returned. -- cgit v1.2.3 From 1dcd763ba1f62c1305a03bc7d5bd1d44c20a4f5e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:35 -0400 Subject: rust: clk: use `CStr::as_char_ptr` Replace the use of `as_ptr` which works through `::deref()` in preparation for replacing `kernel::str::CStr` with `core::ffi::CStr` as the latter does not implement `Deref`. Signed-off-by: Tamir Duberstein Acked-by: Viresh Kumar Link: https://patch.msgid.link/20251018-cstr-core-v18-14-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/clk.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index 1e6c8c42fb3a..c1cfaeaa36a2 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -136,7 +136,7 @@ mod common_clk { /// /// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get pub fn get(dev: &Device, name: Option<&CStr>) -> Result { - let con_id = name.map_or(ptr::null(), |n| n.as_ptr()); + let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr()); // SAFETY: It is safe to call [`clk_get`] for a valid device pointer. // @@ -304,7 +304,7 @@ mod common_clk { /// [`clk_get_optional`]: /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional pub fn get(dev: &Device, name: Option<&CStr>) -> Result { - let con_id = name.map_or(ptr::null(), |n| n.as_ptr()); + let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr()); // SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer. // -- cgit v1.2.3 From c5cf01ba8dfe9c0f631ace6f64ec436303783000 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:36 -0400 Subject: rust: support formatting of foreign types Introduce a `fmt!` macro which wraps all arguments in `kernel::fmt::Adapter` and a `kernel::fmt::Display` trait. This enables formatting of foreign types (like `core::ffi::CStr`) that do not implement `core::fmt::Display` due to concerns around lossy conversions which do not apply in the kernel. Suggested-by: Alice Ryhl Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Custom.20formatting/with/516476467 Acked-by: Greg Kroah-Hartman Reviewed-by: Alice Ryhl Acked-by: Danilo Krummrich Reviewed-by: Benno Lossin Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251018-cstr-core-v18-15-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/fmt.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++- rust/kernel/prelude.rs | 3 +- 2 files changed, 87 insertions(+), 3 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/fmt.rs b/rust/kernel/fmt.rs index 0306e8388968..84d634201d90 100644 --- a/rust/kernel/fmt.rs +++ b/rust/kernel/fmt.rs @@ -4,4 +4,89 @@ //! //! This module is intended to be used in place of `core::fmt` in kernel code. -pub use core::fmt::{Arguments, Debug, Display, Error, Formatter, Result, Write}; +pub use core::fmt::{Arguments, Debug, Error, Formatter, Result, Write}; + +/// Internal adapter used to route allow implementations of formatting traits for foreign types. +/// +/// It is inserted automatically by the [`fmt!`] macro and is not meant to be used directly. +/// +/// [`fmt!`]: crate::prelude::fmt! +#[doc(hidden)] +pub struct Adapter(pub T); + +macro_rules! impl_fmt_adapter_forward { + ($($trait:ident),* $(,)?) => { + $( + impl $trait for Adapter { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let Self(t) = self; + $trait::fmt(t, f) + } + } + )* + }; +} + +use core::fmt::{Binary, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex}; +impl_fmt_adapter_forward!(Debug, LowerHex, UpperHex, Octal, Binary, Pointer, LowerExp, UpperExp); + +/// A copy of [`core::fmt::Display`] that allows us to implement it for foreign types. +/// +/// Types should implement this trait rather than [`core::fmt::Display`]. Together with the +/// [`Adapter`] type and [`fmt!`] macro, it allows for formatting foreign types (e.g. types from +/// core) which do not implement [`core::fmt::Display`] directly. +/// +/// [`fmt!`]: crate::prelude::fmt! +pub trait Display { + /// Same as [`core::fmt::Display::fmt`]. + fn fmt(&self, f: &mut Formatter<'_>) -> Result; +} + +impl Display for &T { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + Display::fmt(*self, f) + } +} + +impl core::fmt::Display for Adapter<&T> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let Self(t) = self; + Display::fmt(t, f) + } +} + +macro_rules! impl_display_forward { + ($( + $( { $($generics:tt)* } )? $ty:ty $( { where $($where:tt)* } )? + ),* $(,)?) => { + $( + impl$($($generics)*)? Display for $ty $(where $($where)*)? { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + core::fmt::Display::fmt(self, f) + } + } + )* + }; +} + +impl_display_forward!( + bool, + char, + core::panic::PanicInfo<'_>, + Arguments<'_>, + i128, + i16, + i32, + i64, + i8, + isize, + str, + u128, + u16, + u32, + u64, + u8, + usize, + {} crate::sync::Arc {where crate::sync::Arc: core::fmt::Display}, + {} crate::sync::UniqueArc {where crate::sync::UniqueArc: core::fmt::Display}, +); diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 198d09a31449..26424ad7e989 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -25,7 +25,7 @@ pub use ::ffi::{ pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec}; #[doc(no_inline)] -pub use macros::{export, kunit_tests, module, vtable}; +pub use macros::{export, fmt, kunit_tests, module, vtable}; pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable}; @@ -36,7 +36,6 @@ pub use super::{build_assert, build_error}; pub use super::dbg; pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn}; pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; -pub use core::format_args as fmt; pub use super::{try_init, try_pin_init}; -- cgit v1.2.3 From 3b83f5d5e78ac5cddd811a5e431af73959864390 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 18 Oct 2025 15:16:37 -0400 Subject: rust: replace `CStr` with `core::ffi::CStr` `kernel::ffi::CStr` was introduced in commit d126d2380131 ("rust: str: add `CStr` type") in November 2022 as an upstreaming of earlier work that was done in May 2021[0]. That earlier work, having predated the inclusion of `CStr` in `core`, largely duplicated the implementation of `std::ffi::CStr`. `std::ffi::CStr` was moved to `core::ffi::CStr` in Rust 1.64 in September 2022. Hence replace `kernel::str::CStr` with `core::ffi::CStr` to reduce our custom code footprint, and retain needed custom functionality through an extension trait. Add `CStr` to `ffi` and the kernel prelude. Link: https://github.com/Rust-for-Linux/linux/commit/faa3cbcca03d0dec8f8e43f1d8d5c0860d98a23f [0] Acked-by: Greg Kroah-Hartman Reviewed-by: Alice Ryhl Acked-by: Danilo Krummrich Reviewed-by: Benno Lossin Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251018-cstr-core-v18-16-9378a54385f8@gmail.com [ Removed assert that would now depend on the Rust version. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/debugfs/entry.rs | 2 +- rust/kernel/device.rs | 1 + rust/kernel/drm/ioctl.rs | 4 +- rust/kernel/error.rs | 2 + rust/kernel/firmware.rs | 9 +- rust/kernel/prelude.rs | 4 +- rust/kernel/seq_file.rs | 2 +- rust/kernel/str.rs | 395 +++++++++------------------------------- rust/kernel/sync/condvar.rs | 2 +- rust/kernel/sync/lock.rs | 2 +- rust/kernel/sync/lock/global.rs | 2 +- 11 files changed, 110 insertions(+), 315 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs index f99402cd3ba0..706cb7f73d6c 100644 --- a/rust/kernel/debugfs/entry.rs +++ b/rust/kernel/debugfs/entry.rs @@ -3,7 +3,7 @@ use crate::debugfs::file_ops::FileOps; use crate::ffi::c_void; -use crate::str::CStr; +use crate::str::{CStr, CStrExt as _}; use crate::sync::Arc; use core::marker::PhantomData; diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 1321e6f0b53c..0b13aa60b685 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -13,6 +13,7 @@ use core::{marker::PhantomData, ptr}; #[cfg(CONFIG_PRINTK)] use crate::c_str; +use crate::str::CStrExt as _; pub mod property; diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs index 69efbdb4c85a..cf328101dde4 100644 --- a/rust/kernel/drm/ioctl.rs +++ b/rust/kernel/drm/ioctl.rs @@ -156,7 +156,9 @@ macro_rules! declare_drm_ioctls { Some($cmd) }, flags: $flags, - name: $crate::c_str!(::core::stringify!($cmd)).as_char_ptr(), + name: $crate::str::as_char_ptr_in_const_context( + $crate::c_str!(::core::stringify!($cmd)), + ), } ),*]; ioctls diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 1c0e0e241daa..258b12afdcba 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -182,6 +182,8 @@ impl Error { if ptr.is_null() { None } else { + use crate::str::CStrExt as _; + // SAFETY: The string returned by `errname` is static and `NUL`-terminated. Some(unsafe { CStr::from_char_ptr(ptr) }) } diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs index 94e6bb88b903..376e7e77453f 100644 --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -4,7 +4,14 @@ //! //! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h) -use crate::{bindings, device::Device, error::Error, error::Result, ffi, str::CStr}; +use crate::{ + bindings, + device::Device, + error::Error, + error::Result, + ffi, + str::{CStr, CStrExt as _}, +}; use core::ptr::NonNull; /// # Invariants diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 26424ad7e989..33fa8404c5c6 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -19,7 +19,7 @@ pub use core::{ pub use ::ffi::{ c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, - c_ushort, c_void, + c_ushort, c_void, CStr, }; pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec}; @@ -43,7 +43,7 @@ pub use super::static_assert; pub use super::error::{code::*, Error, Result}; -pub use super::{str::CStr, ThisModule}; +pub use super::{str::CStrExt as _, ThisModule}; pub use super::init::InPlaceInit; diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs index 59fbfc2473f8..855e533813a6 100644 --- a/rust/kernel/seq_file.rs +++ b/rust/kernel/seq_file.rs @@ -4,7 +4,7 @@ //! //! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h) -use crate::{bindings, c_str, fmt, types::NotThreadSafe, types::Opaque}; +use crate::{bindings, c_str, fmt, str::CStrExt as _, types::NotThreadSafe, types::Opaque}; /// A utility for generating the contents of a seq file. #[repr(transparent)] diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 5c74e5f77601..7593d758fbb7 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -10,9 +10,11 @@ use crate::{ }; use core::{ marker::PhantomData, - ops::{self, Deref, DerefMut, Index}, + ops::{Deref, DerefMut, Index}, }; +pub use crate::prelude::CStr; + /// Byte string without UTF-8 validity guarantee. #[repr(transparent)] pub struct BStr([u8]); @@ -186,58 +188,17 @@ macro_rules! b_str { // - error[E0379]: functions in trait impls cannot be declared const #[inline] pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char { - c_str.0.as_ptr() + c_str.as_ptr().cast() } -/// Possible errors when using conversion functions in [`CStr`]. -#[derive(Debug, Clone, Copy)] -pub enum CStrConvertError { - /// Supplied bytes contain an interior `NUL`. - InteriorNul, - - /// Supplied bytes are not terminated by `NUL`. - NotNulTerminated, -} +mod private { + pub trait Sealed {} -impl From for Error { - #[inline] - fn from(_: CStrConvertError) -> Error { - EINVAL - } + impl Sealed for super::CStr {} } -/// A string that is guaranteed to have exactly one `NUL` byte, which is at the -/// end. -/// -/// Used for interoperability with kernel APIs that take C strings. -#[repr(transparent)] -pub struct CStr([u8]); - -impl CStr { - /// Returns the length of this string excluding `NUL`. - #[inline] - pub const fn len(&self) -> usize { - self.len_with_nul() - 1 - } - - /// Returns the length of this string with `NUL`. - #[inline] - pub const fn len_with_nul(&self) -> usize { - if self.0.is_empty() { - // SAFETY: This is one of the invariant of `CStr`. - // We add a `unreachable_unchecked` here to hint the optimizer that - // the value returned from this function is non-zero. - unsafe { core::hint::unreachable_unchecked() }; - } - self.0.len() - } - - /// Returns `true` if the string only includes `NUL`. - #[inline] - pub const fn is_empty(&self) -> bool { - self.len() == 0 - } - +/// Extensions to [`CStr`]. +pub trait CStrExt: private::Sealed { /// Wraps a raw C string pointer. /// /// # Safety @@ -245,54 +206,9 @@ impl CStr { /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` /// must not be mutated. - #[inline] - pub unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self { - // SAFETY: The safety precondition guarantees `ptr` is a valid pointer - // to a `NUL`-terminated C string. - let len = unsafe { bindings::strlen(ptr) } + 1; - // SAFETY: Lifetime guaranteed by the safety precondition. - let bytes = unsafe { core::slice::from_raw_parts(ptr.cast(), len) }; - // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. - // As we have added 1 to `len`, the last byte is known to be `NUL`. - unsafe { Self::from_bytes_with_nul_unchecked(bytes) } - } - - /// Creates a [`CStr`] from a `[u8]`. - /// - /// The provided slice must be `NUL`-terminated, does not contain any - /// interior `NUL` bytes. - pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { - if bytes.is_empty() { - return Err(CStrConvertError::NotNulTerminated); - } - if bytes[bytes.len() - 1] != 0 { - return Err(CStrConvertError::NotNulTerminated); - } - let mut i = 0; - // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, - // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. - while i + 1 < bytes.len() { - if bytes[i] == 0 { - return Err(CStrConvertError::InteriorNul); - } - i += 1; - } - // SAFETY: We just checked that all properties hold. - Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) - } - - /// Creates a [`CStr`] from a `[u8]` without performing any additional - /// checks. - /// - /// # Safety - /// - /// `bytes` *must* end with a `NUL` byte, and should only have a single - /// `NUL` byte (or the string will be truncated). - #[inline] - pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { - // SAFETY: Properties of `bytes` guaranteed by the safety precondition. - unsafe { core::mem::transmute(bytes) } - } + // This function exists to paper over the fact that `CStr::from_ptr` takes a `*const + // core::ffi::c_char` rather than a `*const crate::ffi::c_char`. + unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self; /// Creates a mutable [`CStr`] from a `[u8]` without performing any /// additional checks. @@ -301,99 +217,16 @@ impl CStr { /// /// `bytes` *must* end with a `NUL` byte, and should only have a single /// `NUL` byte (or the string will be truncated). - #[inline] - pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { - // SAFETY: Properties of `bytes` guaranteed by the safety precondition. - unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) } - } + unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut Self; /// Returns a C pointer to the string. - /// - /// Using this function in a const context is deprecated in favor of - /// [`as_char_ptr_in_const_context`] in preparation for replacing `CStr` with `core::ffi::CStr` - /// which does not have this method. - #[inline] - pub const fn as_char_ptr(&self) -> *const c_char { - as_char_ptr_in_const_context(self) - } - - /// Convert the string to a byte slice without the trailing `NUL` byte. - #[inline] - pub fn to_bytes(&self) -> &[u8] { - &self.0[..self.len()] - } - - /// Convert the string to a byte slice without the trailing `NUL` byte. - /// - /// This function is deprecated in favor of [`Self::to_bytes`] in preparation for replacing - /// `CStr` with `core::ffi::CStr` which does not have this method. - #[inline] - pub fn as_bytes(&self) -> &[u8] { - self.to_bytes() - } - - /// Convert the string to a byte slice containing the trailing `NUL` byte. - #[inline] - pub const fn to_bytes_with_nul(&self) -> &[u8] { - &self.0 - } - - /// Convert the string to a byte slice containing the trailing `NUL` byte. - /// - /// This function is deprecated in favor of [`Self::to_bytes_with_nul`] in preparation for - /// replacing `CStr` with `core::ffi::CStr` which does not have this method. - #[inline] - pub const fn as_bytes_with_nul(&self) -> &[u8] { - self.to_bytes_with_nul() - } - - /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. - /// - /// If the contents of the [`CStr`] are valid UTF-8 data, this - /// function will return the corresponding [`&str`] slice. Otherwise, - /// it will return an error with details of where UTF-8 validation failed. - /// - /// # Examples - /// - /// ``` - /// # use kernel::str::CStr; - /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?; - /// assert_eq!(cstr.to_str(), Ok("foo")); - /// # Ok::<(), kernel::error::Error>(()) - /// ``` - #[inline] - pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { - core::str::from_utf8(self.as_bytes()) - } - - /// Unsafely convert this [`CStr`] into a [`&str`], without checking for - /// valid UTF-8. - /// - /// # Safety - /// - /// The contents must be valid UTF-8. - /// - /// # Examples - /// - /// ``` - /// # use kernel::c_str; - /// # use kernel::str::CStr; - /// let bar = c_str!("ツ"); - /// // SAFETY: String literals are guaranteed to be valid UTF-8 - /// // by the Rust compiler. - /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); - /// ``` - #[inline] - pub unsafe fn as_str_unchecked(&self) -> &str { - // SAFETY: TODO. - unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } - } + // This function exists to paper over the fact that `CStr::as_ptr` returns a `*const + // core::ffi::c_char` rather than a `*const crate::ffi::c_char`. + fn as_char_ptr(&self) -> *const c_char; /// Convert this [`CStr`] into a [`CString`] by allocating memory and /// copying over the string data. - pub fn to_cstring(&self) -> Result { - CString::try_from(self) - } + fn to_cstring(&self) -> Result; /// Converts this [`CStr`] to its ASCII lower case equivalent in-place. /// @@ -404,11 +237,7 @@ impl CStr { /// [`to_ascii_lowercase()`]. /// /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase - pub fn make_ascii_lowercase(&mut self) { - // INVARIANT: This doesn't introduce or remove NUL bytes in the C - // string. - self.0.make_ascii_lowercase(); - } + fn make_ascii_lowercase(&mut self); /// Converts this [`CStr`] to its ASCII upper case equivalent in-place. /// @@ -419,11 +248,7 @@ impl CStr { /// [`to_ascii_uppercase()`]. /// /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase - pub fn make_ascii_uppercase(&mut self) { - // INVARIANT: This doesn't introduce or remove NUL bytes in the C - // string. - self.0.make_ascii_uppercase(); - } + fn make_ascii_uppercase(&mut self); /// Returns a copy of this [`CString`] where each character is mapped to its /// ASCII lower case equivalent. @@ -434,13 +259,7 @@ impl CStr { /// To lowercase the value in-place, use [`make_ascii_lowercase`]. /// /// [`make_ascii_lowercase`]: str::make_ascii_lowercase - pub fn to_ascii_lowercase(&self) -> Result { - let mut s = self.to_cstring()?; - - s.make_ascii_lowercase(); - - Ok(s) - } + fn to_ascii_lowercase(&self) -> Result; /// Returns a copy of this [`CString`] where each character is mapped to its /// ASCII upper case equivalent. @@ -451,13 +270,7 @@ impl CStr { /// To uppercase the value in-place, use [`make_ascii_uppercase`]. /// /// [`make_ascii_uppercase`]: str::make_ascii_uppercase - pub fn to_ascii_uppercase(&self) -> Result { - let mut s = self.to_cstring()?; - - s.make_ascii_uppercase(); - - Ok(s) - } + fn to_ascii_uppercase(&self) -> Result; } impl fmt::Display for CStr { @@ -490,98 +303,75 @@ impl fmt::Display for CStr { } } -impl fmt::Debug for CStr { - /// Formats printable ASCII characters with a double quote on either end, escaping the rest. - /// - /// ``` - /// # use kernel::c_str; - /// # use kernel::prelude::fmt; - /// # use kernel::str::CStr; - /// # use kernel::str::CString; - /// let penguin = c_str!("🐧"); - /// let s = CString::try_from_fmt(fmt!("{penguin:?}"))?; - /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); - /// - /// // Embedded double quotes are escaped. - /// let ascii = c_str!("so \"cool\""); - /// let s = CString::try_from_fmt(fmt!("{ascii:?}"))?; - /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); - /// # Ok::<(), kernel::error::Error>(()) - /// ``` - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("\"")?; - for &c in self.as_bytes() { - match c { - // Printable characters. - b'\"' => f.write_str("\\\"")?, - 0x20..=0x7e => f.write_char(c as char)?, - _ => write!(f, "\\x{c:02x}")?, - } - } - f.write_str("\"") - } +/// Converts a mutable C string to a mutable byte slice. +/// +/// # Safety +/// +/// The caller must ensure that the slice ends in a NUL byte and contains no other NUL bytes before +/// the borrow ends and the underlying [`CStr`] is used. +unsafe fn to_bytes_mut(s: &mut CStr) -> &mut [u8] { + // SAFETY: the cast from `&CStr` to `&[u8]` is safe since `CStr` has the same layout as `&[u8]` + // (this is technically not guaranteed, but we rely on it here). The pointer dereference is + // safe since it comes from a mutable reference which is guaranteed to be valid for writes. + unsafe { &mut *(core::ptr::from_mut(s) as *mut [u8]) } } -impl AsRef for CStr { +impl CStrExt for CStr { #[inline] - fn as_ref(&self) -> &BStr { - BStr::from_bytes(self.as_bytes()) + unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self { + // SAFETY: The safety preconditions are the same as for `CStr::from_ptr`. + unsafe { CStr::from_ptr(ptr.cast()) } } -} -impl Deref for CStr { - type Target = BStr; + #[inline] + unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut Self { + // SAFETY: the cast from `&[u8]` to `&CStr` is safe since the properties of `bytes` are + // guaranteed by the safety precondition and `CStr` has the same layout as `&[u8]` (this is + // technically not guaranteed, but we rely on it here). The pointer dereference is safe + // since it comes from a mutable reference which is guaranteed to be valid for writes. + unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) } + } #[inline] - fn deref(&self) -> &Self::Target { - self.as_ref() + fn as_char_ptr(&self) -> *const c_char { + self.as_ptr().cast() } -} -impl Index> for CStr { - type Output = CStr; + fn to_cstring(&self) -> Result { + CString::try_from(self) + } - #[inline] - fn index(&self, index: ops::RangeFrom) -> &Self::Output { - // Delegate bounds checking to slice. - // Assign to _ to mute clippy's unnecessary operation warning. - let _ = &self.as_bytes()[index.start..]; - // SAFETY: We just checked the bounds. - unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } + fn make_ascii_lowercase(&mut self) { + // SAFETY: This doesn't introduce or remove NUL bytes in the C string. + unsafe { to_bytes_mut(self) }.make_ascii_lowercase(); } -} -impl Index for CStr { - type Output = CStr; + fn make_ascii_uppercase(&mut self) { + // SAFETY: This doesn't introduce or remove NUL bytes in the C string. + unsafe { to_bytes_mut(self) }.make_ascii_uppercase(); + } - #[inline] - fn index(&self, _index: ops::RangeFull) -> &Self::Output { - self + fn to_ascii_lowercase(&self) -> Result { + let mut s = self.to_cstring()?; + + s.make_ascii_lowercase(); + + Ok(s) } -} -mod private { - use core::ops; + fn to_ascii_uppercase(&self) -> Result { + let mut s = self.to_cstring()?; - // Marker trait for index types that can be forward to `BStr`. - pub trait CStrIndex {} + s.make_ascii_uppercase(); - impl CStrIndex for usize {} - impl CStrIndex for ops::Range {} - impl CStrIndex for ops::RangeInclusive {} - impl CStrIndex for ops::RangeToInclusive {} + Ok(s) + } } -impl Index for CStr -where - Idx: private::CStrIndex, - BStr: Index, -{ - type Output = >::Output; - +impl AsRef for CStr { #[inline] - fn index(&self, index: Idx) -> &Self::Output { - &self.as_ref()[index] + fn as_ref(&self) -> &BStr { + BStr::from_bytes(self.to_bytes()) } } @@ -612,6 +402,13 @@ macro_rules! c_str { mod tests { use super::*; + impl From for Error { + #[inline] + fn from(_: core::ffi::FromBytesWithNulError) -> Error { + EINVAL + } + } + macro_rules! format { ($($f:tt)*) => ({ CString::try_from_fmt(fmt!($($f)*))?.to_str()? @@ -634,40 +431,28 @@ mod tests { #[test] fn test_cstr_to_str() -> Result { - let good_bytes = b"\xf0\x9f\xa6\x80\0"; - let checked_cstr = CStr::from_bytes_with_nul(good_bytes)?; - let checked_str = checked_cstr.to_str()?; + let cstr = c"\xf0\x9f\xa6\x80"; + let checked_str = cstr.to_str()?; assert_eq!(checked_str, "🦀"); Ok(()) } #[test] fn test_cstr_to_str_invalid_utf8() -> Result { - let bad_bytes = b"\xc3\x28\0"; - let checked_cstr = CStr::from_bytes_with_nul(bad_bytes)?; - assert!(checked_cstr.to_str().is_err()); - Ok(()) - } - - #[test] - fn test_cstr_as_str_unchecked() -> Result { - let good_bytes = b"\xf0\x9f\x90\xA7\0"; - let checked_cstr = CStr::from_bytes_with_nul(good_bytes)?; - // SAFETY: The contents come from a string literal which contains valid UTF-8. - let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; - assert_eq!(unchecked_str, "🐧"); + let cstr = c"\xc3\x28"; + assert!(cstr.to_str().is_err()); Ok(()) } #[test] fn test_cstr_display() -> Result { - let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0")?; + let hello_world = c"hello, world!"; assert_eq!(format!("{hello_world}"), "hello, world!"); - let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0")?; + let non_printables = c"\x01\x09\x0a"; assert_eq!(format!("{non_printables}"), "\\x01\\x09\\x0a"); - let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0")?; + let non_ascii = c"d\xe9j\xe0 vu"; assert_eq!(format!("{non_ascii}"), "d\\xe9j\\xe0 vu"); - let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0")?; + let good_bytes = c"\xf0\x9f\xa6\x80"; assert_eq!(format!("{good_bytes}"), "\\xf0\\x9f\\xa6\\x80"); Ok(()) } @@ -686,14 +471,12 @@ mod tests { #[test] fn test_cstr_debug() -> Result { - let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0")?; + let hello_world = c"hello, world!"; assert_eq!(format!("{hello_world:?}"), "\"hello, world!\""); - let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0")?; - assert_eq!(format!("{non_printables:?}"), "\"\\x01\\x09\\x0a\""); - let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0")?; + let non_printables = c"\x01\x09\x0a"; + assert_eq!(format!("{non_printables:?}"), "\"\\x01\\t\\n\""); + let non_ascii = c"d\xe9j\xe0 vu"; assert_eq!(format!("{non_ascii:?}"), "\"d\\xe9j\\xe0 vu\""); - let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0")?; - assert_eq!(format!("{good_bytes:?}"), "\"\\xf0\\x9f\\xa6\\x80\""); Ok(()) } diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index c6ec64295c9f..a24e25a690ee 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -8,7 +8,7 @@ use super::{lock::Backend, lock::Guard, LockClassKey}; use crate::{ ffi::{c_int, c_long}, - str::CStr, + str::{CStr, CStrExt as _}, task::{ MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE, }, diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 27202beef90c..5d7991e6d373 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -7,7 +7,7 @@ use super::LockClassKey; use crate::{ - str::CStr, + str::{CStr, CStrExt as _}, types::{NotThreadSafe, Opaque, ScopeGuard}, }; use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin}; diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global.rs index d65f94b5caf2..79d0ef7fda86 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -5,7 +5,7 @@ //! Support for defining statics containing locks. use crate::{ - str::CStr, + str::{CStr, CStrExt as _}, sync::lock::{Backend, Guard, Lock}, sync::{LockClassKey, LockedBy}, types::Opaque, -- cgit v1.2.3 From f56b131723826dfdbf829d014591d831d649ae4a Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Tue, 14 Oct 2025 14:33:39 +0200 Subject: rust: rbtree: add immutable cursor Sometimes we may need to iterate over, or find an element in a read only (or read mostly) red-black tree, and in that case we don't need a mutable reference to the tree, which we'll however have to take to be able to use the current (mutable) cursor implementation. This patch adds a simple immutable cursor implementation to RBTree, which enables us to use an immutable tree reference. The existing (fully featured) cursor implementation is renamed to CursorMut, while retaining its functionality. The only existing user of the [mutable] cursor for RBTrees (binder) is updated to match the changes. Signed-off-by: Vitaly Wool Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20251014123339.2492210-1-vitaly.wool@konsulko.se [ Applied `rustfmt`. Added intra-doc link. Fixed unclosed example. Fixed docs description. Fixed typo and other formatting nits. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/rbtree.rs | 244 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 197 insertions(+), 47 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs index b8fe6be6fcc4..4729eb56827a 100644 --- a/rust/kernel/rbtree.rs +++ b/rust/kernel/rbtree.rs @@ -243,34 +243,64 @@ impl RBTree { } /// Returns a cursor over the tree nodes, starting with the smallest key. - pub fn cursor_front(&mut self) -> Option> { + pub fn cursor_front_mut(&mut self) -> Option> { let root = addr_of_mut!(self.root); - // SAFETY: `self.root` is always a valid root node + // SAFETY: `self.root` is always a valid root node. let current = unsafe { bindings::rb_first(root) }; NonNull::new(current).map(|current| { // INVARIANT: // - `current` is a valid node in the [`RBTree`] pointed to by `self`. - Cursor { + CursorMut { current, tree: self, } }) } + /// Returns an immutable cursor over the tree nodes, starting with the smallest key. + pub fn cursor_front(&self) -> Option> { + let root = &raw const self.root; + // SAFETY: `self.root` is always a valid root node. + let current = unsafe { bindings::rb_first(root) }; + NonNull::new(current).map(|current| { + // INVARIANT: + // - `current` is a valid node in the [`RBTree`] pointed to by `self`. + Cursor { + current, + _tree: PhantomData, + } + }) + } + /// Returns a cursor over the tree nodes, starting with the largest key. - pub fn cursor_back(&mut self) -> Option> { + pub fn cursor_back_mut(&mut self) -> Option> { let root = addr_of_mut!(self.root); - // SAFETY: `self.root` is always a valid root node + // SAFETY: `self.root` is always a valid root node. let current = unsafe { bindings::rb_last(root) }; NonNull::new(current).map(|current| { // INVARIANT: // - `current` is a valid node in the [`RBTree`] pointed to by `self`. - Cursor { + CursorMut { current, tree: self, } }) } + + /// Returns a cursor over the tree nodes, starting with the largest key. + pub fn cursor_back(&self) -> Option> { + let root = &raw const self.root; + // SAFETY: `self.root` is always a valid root node. + let current = unsafe { bindings::rb_last(root) }; + NonNull::new(current).map(|current| { + // INVARIANT: + // - `current` is a valid node in the [`RBTree`] pointed to by `self`. + Cursor { + current, + _tree: PhantomData, + } + }) + } } impl RBTree @@ -421,12 +451,47 @@ where /// If the given key exists, the cursor starts there. /// Otherwise it starts with the first larger key in sort order. /// If there is no larger key, it returns [`None`]. - pub fn cursor_lower_bound(&mut self, key: &K) -> Option> + pub fn cursor_lower_bound_mut(&mut self, key: &K) -> Option> + where + K: Ord, + { + let best = self.find_best_match(key)?; + + NonNull::new(best.as_ptr()).map(|current| { + // INVARIANT: + // - `current` is a valid node in the [`RBTree`] pointed to by `self`. + CursorMut { + current, + tree: self, + } + }) + } + + /// Returns a cursor over the tree nodes based on the given key. + /// + /// If the given key exists, the cursor starts there. + /// Otherwise it starts with the first larger key in sort order. + /// If there is no larger key, it returns [`None`]. + pub fn cursor_lower_bound(&self, key: &K) -> Option> where K: Ord, { + let best = self.find_best_match(key)?; + + NonNull::new(best.as_ptr()).map(|current| { + // INVARIANT: + // - `current` is a valid node in the [`RBTree`] pointed to by `self`. + Cursor { + current, + _tree: PhantomData, + } + }) + } + + fn find_best_match(&self, key: &K) -> Option> { let mut node = self.root.rb_node; - let mut best_match: Option>> = None; + let mut best_key: Option<&K> = None; + let mut best_links: Option> = None; while !node.is_null() { // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self` // point to the links field of `Node` objects. @@ -439,42 +504,28 @@ where let right_child = unsafe { (*node).rb_right }; match key.cmp(this_key) { Ordering::Equal => { - best_match = NonNull::new(this); + // SAFETY: `this` is a non-null node so it is valid by the type invariants. + best_links = Some(unsafe { NonNull::new_unchecked(&mut (*this).links) }); break; } Ordering::Greater => { node = right_child; } Ordering::Less => { - let is_better_match = match best_match { + let is_better_match = match best_key { None => true, - Some(best) => { - // SAFETY: `best` is a non-null node so it is valid by the type invariants. - let best_key = unsafe { &(*best.as_ptr()).key }; - best_key > this_key - } + Some(best) => best > this_key, }; if is_better_match { - best_match = NonNull::new(this); + best_key = Some(this_key); + // SAFETY: `this` is a non-null node so it is valid by the type invariants. + best_links = Some(unsafe { NonNull::new_unchecked(&mut (*this).links) }); } node = left_child; } }; } - - let best = best_match?; - - // SAFETY: `best` is a non-null node so it is valid by the type invariants. - let links = unsafe { addr_of_mut!((*best.as_ptr()).links) }; - - NonNull::new(links).map(|current| { - // INVARIANT: - // - `current` is a valid node in the [`RBTree`] pointed to by `self`. - Cursor { - current, - tree: self, - } - }) + best_links } } @@ -507,7 +558,7 @@ impl Drop for RBTree { } } -/// A bidirectional cursor over the tree nodes, sorted by key. +/// A bidirectional mutable cursor over the tree nodes, sorted by key. /// /// # Examples /// @@ -526,7 +577,7 @@ impl Drop for RBTree { /// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?; /// /// // Get a cursor to the first element. -/// let mut cursor = tree.cursor_front().unwrap(); +/// let mut cursor = tree.cursor_front_mut().unwrap(); /// let mut current = cursor.current(); /// assert_eq!(current, (&10, &100)); /// @@ -564,7 +615,7 @@ impl Drop for RBTree { /// tree.try_create_and_insert(20, 200, flags::GFP_KERNEL)?; /// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?; /// -/// let mut cursor = tree.cursor_back().unwrap(); +/// let mut cursor = tree.cursor_back_mut().unwrap(); /// let current = cursor.current(); /// assert_eq!(current, (&30, &300)); /// @@ -577,7 +628,7 @@ impl Drop for RBTree { /// use kernel::rbtree::RBTree; /// /// let mut tree: RBTree = RBTree::new(); -/// assert!(tree.cursor_front().is_none()); +/// assert!(tree.cursor_front_mut().is_none()); /// /// # Ok::<(), Error>(()) /// ``` @@ -628,7 +679,7 @@ impl Drop for RBTree { /// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?; /// /// // Retrieve a cursor. -/// let mut cursor = tree.cursor_front().unwrap(); +/// let mut cursor = tree.cursor_front_mut().unwrap(); /// /// // Get a mutable reference to the current value. /// let (k, v) = cursor.current_mut(); @@ -655,7 +706,7 @@ impl Drop for RBTree { /// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?; /// /// // Remove the first element. -/// let mut cursor = tree.cursor_front().unwrap(); +/// let mut cursor = tree.cursor_front_mut().unwrap(); /// let mut current = cursor.current(); /// assert_eq!(current, (&10, &100)); /// cursor = cursor.remove_current().0.unwrap(); @@ -665,7 +716,7 @@ impl Drop for RBTree { /// assert_eq!(current, (&20, &200)); /// /// // Get a cursor to the last element, and remove it. -/// cursor = tree.cursor_back().unwrap(); +/// cursor = tree.cursor_back_mut().unwrap(); /// current = cursor.current(); /// assert_eq!(current, (&30, &300)); /// @@ -694,7 +745,7 @@ impl Drop for RBTree { /// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?; /// /// // Get a cursor to the first element. -/// let mut cursor = tree.cursor_front().unwrap(); +/// let mut cursor = tree.cursor_front_mut().unwrap(); /// let mut current = cursor.current(); /// assert_eq!(current, (&10, &100)); /// @@ -702,7 +753,7 @@ impl Drop for RBTree { /// assert!(cursor.remove_prev().is_none()); /// /// // Get a cursor to the last element. -/// cursor = tree.cursor_back().unwrap(); +/// cursor = tree.cursor_back_mut().unwrap(); /// current = cursor.current(); /// assert_eq!(current, (&30, &300)); /// @@ -726,18 +777,48 @@ impl Drop for RBTree { /// /// # Invariants /// - `current` points to a node that is in the same [`RBTree`] as `tree`. -pub struct Cursor<'a, K, V> { +pub struct CursorMut<'a, K, V> { tree: &'a mut RBTree, current: NonNull, } -// SAFETY: The [`Cursor`] has exclusive access to both `K` and `V`, so it is sufficient to require them to be `Send`. -// The cursor only gives out immutable references to the keys, but since it has excusive access to those same -// keys, `Send` is sufficient. `Sync` would be okay, but it is more restrictive to the user. -unsafe impl<'a, K: Send, V: Send> Send for Cursor<'a, K, V> {} +/// A bidirectional immutable cursor over the tree nodes, sorted by key. This is a simpler +/// variant of [`CursorMut`] that is basically providing read only access. +/// +/// # Examples +/// +/// In the following example, we obtain a cursor to the first element in the tree. +/// The cursor allows us to iterate bidirectionally over key/value pairs in the tree. +/// +/// ``` +/// use kernel::{alloc::flags, rbtree::RBTree}; +/// +/// // Create a new tree. +/// let mut tree = RBTree::new(); +/// +/// // Insert three elements. +/// tree.try_create_and_insert(10, 100, flags::GFP_KERNEL)?; +/// tree.try_create_and_insert(20, 200, flags::GFP_KERNEL)?; +/// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?; +/// +/// // Get a cursor to the first element. +/// let cursor = tree.cursor_front().unwrap(); +/// let current = cursor.current(); +/// assert_eq!(current, (&10, &100)); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub struct Cursor<'a, K, V> { + _tree: PhantomData<&'a RBTree>, + current: NonNull, +} -// SAFETY: The [`Cursor`] gives out immutable references to K and mutable references to V, -// so it has the same thread safety requirements as mutable references. +// SAFETY: The immutable cursor gives out shared access to `K` and `V` so if `K` and `V` can be +// shared across threads, then it's safe to share the cursor. +unsafe impl<'a, K: Sync, V: Sync> Send for Cursor<'a, K, V> {} + +// SAFETY: The immutable cursor gives out shared access to `K` and `V` so if `K` and `V` can be +// shared across threads, then it's safe to share the cursor. unsafe impl<'a, K: Sync, V: Sync> Sync for Cursor<'a, K, V> {} impl<'a, K, V> Cursor<'a, K, V> { @@ -749,6 +830,75 @@ impl<'a, K, V> Cursor<'a, K, V> { unsafe { Self::to_key_value(self.current) } } + /// # Safety + /// + /// - `node` must be a valid pointer to a node in an [`RBTree`]. + /// - The caller has immutable access to `node` for the duration of `'b`. + unsafe fn to_key_value<'b>(node: NonNull) -> (&'b K, &'b V) { + // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self` + // point to the links field of `Node` objects. + let this = unsafe { container_of!(node.as_ptr(), Node, links) }; + // SAFETY: The passed `node` is the current node or a non-null neighbor, + // thus `this` is valid by the type invariants. + let k = unsafe { &(*this).key }; + // SAFETY: The passed `node` is the current node or a non-null neighbor, + // thus `this` is valid by the type invariants. + let v = unsafe { &(*this).value }; + (k, v) + } + + /// Access the previous node without moving the cursor. + pub fn peek_prev(&self) -> Option<(&K, &V)> { + self.peek(Direction::Prev) + } + + /// Access the next node without moving the cursor. + pub fn peek_next(&self) -> Option<(&K, &V)> { + self.peek(Direction::Next) + } + + fn peek(&self, direction: Direction) -> Option<(&K, &V)> { + self.get_neighbor_raw(direction).map(|neighbor| { + // SAFETY: + // - `neighbor` is a valid tree node. + // - By the function signature, we have an immutable reference to `self`. + unsafe { Self::to_key_value(neighbor) } + }) + } + + fn get_neighbor_raw(&self, direction: Direction) -> Option> { + // SAFETY: `self.current` is valid by the type invariants. + let neighbor = unsafe { + match direction { + Direction::Prev => bindings::rb_prev(self.current.as_ptr()), + Direction::Next => bindings::rb_next(self.current.as_ptr()), + } + }; + + NonNull::new(neighbor) + } +} + +// SAFETY: The [`CursorMut`] has exclusive access to both `K` and `V`, so it is sufficient to +// require them to be `Send`. +// The cursor only gives out immutable references to the keys, but since it has exclusive access to +// those same keys, `Send` is sufficient. `Sync` would be okay, but it is more restrictive to the +// user. +unsafe impl<'a, K: Send, V: Send> Send for CursorMut<'a, K, V> {} + +// SAFETY: The [`CursorMut`] gives out immutable references to `K` and mutable references to `V`, +// so it has the same thread safety requirements as mutable references. +unsafe impl<'a, K: Sync, V: Sync> Sync for CursorMut<'a, K, V> {} + +impl<'a, K, V> CursorMut<'a, K, V> { + /// The current node. + pub fn current(&self) -> (&K, &V) { + // SAFETY: + // - `self.current` is a valid node by the type invariants. + // - We have an immutable reference by the function signature. + unsafe { Self::to_key_value(self.current) } + } + /// The current node, with a mutable value pub fn current_mut(&mut self) -> (&K, &mut V) { // SAFETY: @@ -920,7 +1070,7 @@ impl<'a, K, V> Cursor<'a, K, V> { } } -/// Direction for [`Cursor`] operations. +/// Direction for [`Cursor`] and [`CursorMut`] operations. enum Direction { /// the node immediately before, in sort order Prev, -- cgit v1.2.3 From 305b795730684796f3f4bbb1aa8f04d52cd2005d Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 13 Nov 2025 17:58:24 -0500 Subject: rust: firmware: replace `kernel::c_str!` with C-Strings C-String literals were added in Rust 1.77. Replace instances of `kernel::c_str!` with C-String literals where possible. Acked-by: Greg Kroah-Hartman Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Acked-by: Danilo Krummrich Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251113-core-cstr-cstrings-v3-1-411b34002774@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/firmware.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs index 376e7e77453f..71168d8004e2 100644 --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -51,13 +51,13 @@ impl FwFunc { /// # Examples /// /// ```no_run -/// # use kernel::{c_str, device::Device, firmware::Firmware}; +/// # use kernel::{device::Device, firmware::Firmware}; /// /// # fn no_run() -> Result<(), Error> { /// # // SAFETY: *NOT* safe, just for the example to get an `ARef` instance /// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) }; /// -/// let fw = Firmware::request(c_str!("path/to/firmware.bin"), &dev)?; +/// let fw = Firmware::request(c"path/to/firmware.bin", &dev)?; /// let blob = fw.data(); /// /// # Ok(()) @@ -204,7 +204,7 @@ macro_rules! module_firmware { ($($builder:tt)*) => { const _: () = { const __MODULE_FIRMWARE_PREFIX: &'static $crate::str::CStr = if cfg!(MODULE) { - $crate::c_str!("") + c"" } else { ::NAME }; -- cgit v1.2.3 From ab8a6c7b34513e48eb4fa766daaa81e75e4306ed Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 13 Nov 2025 17:58:26 -0500 Subject: rust: str: replace `kernel::c_str!` with C-Strings C-String literals were added in Rust 1.77. Replace instances of `kernel::c_str!` with C-String literals where possible. Acked-by: Greg Kroah-Hartman Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251113-core-cstr-cstrings-v3-3-411b34002774@gmail.com [ Removed unused `c_str` import in doctest. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/str.rs | 59 +++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 7593d758fbb7..6fcc9d47f12e 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -277,15 +277,14 @@ impl fmt::Display for CStr { /// Formats printable ASCII characters, escaping the rest. /// /// ``` - /// # use kernel::c_str; /// # use kernel::prelude::fmt; /// # use kernel::str::CStr; /// # use kernel::str::CString; - /// let penguin = c_str!("🐧"); + /// let penguin = c"🐧"; /// let s = CString::try_from_fmt(fmt!("{penguin}"))?; /// assert_eq!(s.to_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); /// - /// let ascii = c_str!("so \"cool\""); + /// let ascii = c"so \"cool\""; /// let s = CString::try_from_fmt(fmt!("{ascii}"))?; /// assert_eq!(s.to_bytes_with_nul(), "so \"cool\"\0".as_bytes()); /// # Ok::<(), kernel::error::Error>(()) @@ -724,43 +723,43 @@ unsafe fn kstrtobool_raw(string: *const u8) -> Result { /// # Examples /// /// ``` -/// # use kernel::{c_str, str::kstrtobool}; +/// # use kernel::str::kstrtobool; /// /// // Lowercase -/// assert_eq!(kstrtobool(c_str!("true")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("tr")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("t")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("twrong")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("false")), Ok(false)); -/// assert_eq!(kstrtobool(c_str!("f")), Ok(false)); -/// assert_eq!(kstrtobool(c_str!("yes")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("no")), Ok(false)); -/// assert_eq!(kstrtobool(c_str!("on")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("off")), Ok(false)); +/// assert_eq!(kstrtobool(c"true"), Ok(true)); +/// assert_eq!(kstrtobool(c"tr"), Ok(true)); +/// assert_eq!(kstrtobool(c"t"), Ok(true)); +/// assert_eq!(kstrtobool(c"twrong"), Ok(true)); +/// assert_eq!(kstrtobool(c"false"), Ok(false)); +/// assert_eq!(kstrtobool(c"f"), Ok(false)); +/// assert_eq!(kstrtobool(c"yes"), Ok(true)); +/// assert_eq!(kstrtobool(c"no"), Ok(false)); +/// assert_eq!(kstrtobool(c"on"), Ok(true)); +/// assert_eq!(kstrtobool(c"off"), Ok(false)); /// /// // Camel case -/// assert_eq!(kstrtobool(c_str!("True")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("False")), Ok(false)); -/// assert_eq!(kstrtobool(c_str!("Yes")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("No")), Ok(false)); -/// assert_eq!(kstrtobool(c_str!("On")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("Off")), Ok(false)); +/// assert_eq!(kstrtobool(c"True"), Ok(true)); +/// assert_eq!(kstrtobool(c"False"), Ok(false)); +/// assert_eq!(kstrtobool(c"Yes"), Ok(true)); +/// assert_eq!(kstrtobool(c"No"), Ok(false)); +/// assert_eq!(kstrtobool(c"On"), Ok(true)); +/// assert_eq!(kstrtobool(c"Off"), Ok(false)); /// /// // All caps -/// assert_eq!(kstrtobool(c_str!("TRUE")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("FALSE")), Ok(false)); -/// assert_eq!(kstrtobool(c_str!("YES")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("NO")), Ok(false)); -/// assert_eq!(kstrtobool(c_str!("ON")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("OFF")), Ok(false)); +/// assert_eq!(kstrtobool(c"TRUE"), Ok(true)); +/// assert_eq!(kstrtobool(c"FALSE"), Ok(false)); +/// assert_eq!(kstrtobool(c"YES"), Ok(true)); +/// assert_eq!(kstrtobool(c"NO"), Ok(false)); +/// assert_eq!(kstrtobool(c"ON"), Ok(true)); +/// assert_eq!(kstrtobool(c"OFF"), Ok(false)); /// /// // Numeric -/// assert_eq!(kstrtobool(c_str!("1")), Ok(true)); -/// assert_eq!(kstrtobool(c_str!("0")), Ok(false)); +/// assert_eq!(kstrtobool(c"1"), Ok(true)); +/// assert_eq!(kstrtobool(c"0"), Ok(false)); /// /// // Invalid input -/// assert_eq!(kstrtobool(c_str!("invalid")), Err(EINVAL)); -/// assert_eq!(kstrtobool(c_str!("2")), Err(EINVAL)); +/// assert_eq!(kstrtobool(c"invalid"), Err(EINVAL)); +/// assert_eq!(kstrtobool(c"2"), Err(EINVAL)); /// ``` pub fn kstrtobool(string: &CStr) -> Result { // SAFETY: -- cgit v1.2.3 From ab844cf32058d6ba9bd98a921afa2256085e21fc Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 10 Nov 2025 12:35:27 +0100 Subject: rust: allow `unreachable_pub` for doctests Examples (i.e. doctests) may want to show public items such as structs, thus the `unreachable_pub` warning is not very helpful. Thus allow it for all doctests. In addition, remove it from the existing `expect`s we have in a couple doctests. Suggested-by: Alice Ryhl Link: https://lore.kernel.org/rust-for-linux/aRG9VjsaCjsvAwUn@google.com/ Reviewed-by: David Gow Acked-by: Benno Lossin Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20251110113528.1658238-1-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/init.rs | 2 +- rust/kernel/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 4949047af8d7..e476d81c1a27 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -67,7 +67,7 @@ //! ``` //! //! ```rust -//! # #![expect(unreachable_pub, clippy::disallowed_names)] +//! # #![expect(clippy::disallowed_names)] //! use kernel::{prelude::*, types::Opaque}; //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; //! # mod bindings { diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index dc0a02f5c3cf..835824788506 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -289,7 +289,7 @@ impl Drop for ScopeGuard { /// # Examples /// /// ``` -/// # #![expect(unreachable_pub, clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// use kernel::types::Opaque; /// # // Emulate a C struct binding which is from C, maybe uninitialized or not, only the C side /// # // knows. -- cgit v1.2.3 From e5d330e13f67d574f683c052c9a342814fd8fa39 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 17 Nov 2025 09:07:13 +0100 Subject: rust: allow `clippy::disallowed_names` for doctests Examples (i.e. doctests) may want to use names such as `foo`, thus the `clippy::disallowed_names` lint [1] gets in the way. Thus allow it for all doctests. In addition, remove it from the existing `expect`s we have in a few doctests. This does not mean that we should stop trying to find good names for our examples, though. Link: https://rust-lang.github.io/rust-clippy/stable/index.html#disallowed_names [1] Suggested-by: Alice Ryhl Link: https://lore.kernel.org/rust-for-linux/aRHSLChi5HYXW4-9@google.com/ Reviewed-by: Alice Ryhl Acked-by: Benno Lossin Link: https://patch.msgid.link/20251117080714.876978-1-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/init.rs | 3 +-- rust/kernel/types.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index e476d81c1a27..899b9a962762 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -30,7 +30,7 @@ //! ## General Examples //! //! ```rust -//! # #![expect(clippy::disallowed_names, clippy::undocumented_unsafe_blocks)] +//! # #![expect(clippy::undocumented_unsafe_blocks)] //! use kernel::types::Opaque; //! use pin_init::pin_init_from_closure; //! @@ -67,7 +67,6 @@ //! ``` //! //! ```rust -//! # #![expect(clippy::disallowed_names)] //! use kernel::{prelude::*, types::Opaque}; //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; //! # mod bindings { diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 835824788506..9c5e7dbf1632 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -289,7 +289,6 @@ impl Drop for ScopeGuard { /// # Examples /// /// ``` -/// # #![expect(clippy::disallowed_names)] /// use kernel::types::Opaque; /// # // Emulate a C struct binding which is from C, maybe uninitialized or not, only the C side /// # // knows. -- cgit v1.2.3 From 90f3df4fdfb682e2394ee3f97dfe91a402d5c46a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sat, 8 Nov 2025 11:23:47 +0900 Subject: rust: add num module and Integer trait Introduce the `num` module, which will provide numerical extensions and utilities for the kernel. For now, introduce the `Integer` trait, which is implemented for all primitive integer types to provides their core properties to generic code. Signed-off-by: Alexandre Courbot Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20251108-bounded_ints-v4-1-c9342ac7ebd1@nvidia.com Signed-off-by: Miguel Ojeda --- rust/kernel/lib.rs | 1 + rust/kernel/num.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 rust/kernel/num.rs (limited to 'rust/kernel') diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3dd7bebe7888..235d0d8b1eff 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -109,6 +109,7 @@ pub mod miscdevice; pub mod mm; #[cfg(CONFIG_NET)] pub mod net; +pub mod num; pub mod of; #[cfg(CONFIG_PM_OPP)] pub mod opp; diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs new file mode 100644 index 000000000000..c8c91cb9e682 --- /dev/null +++ b/rust/kernel/num.rs @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Additional numerical features for the kernel. + +use core::ops; + +/// Designates unsigned primitive types. +pub enum Unsigned {} + +/// Designates signed primitive types. +pub enum Signed {} + +/// Describes core properties of integer types. +pub trait Integer: + Sized + + Copy + + Clone + + PartialEq + + Eq + + PartialOrd + + Ord + + ops::Add + + ops::AddAssign + + ops::Sub + + ops::SubAssign + + ops::Mul + + ops::MulAssign + + ops::Div + + ops::DivAssign + + ops::Rem + + ops::RemAssign + + ops::BitAnd + + ops::BitAndAssign + + ops::BitOr + + ops::BitOrAssign + + ops::BitXor + + ops::BitXorAssign + + ops::Shl + + ops::ShlAssign + + ops::Shr + + ops::ShrAssign + + ops::Not +{ + /// Whether this type is [`Signed`] or [`Unsigned`]. + type Signedness; + + /// Number of bits used for value representation. + const BITS: u32; +} + +macro_rules! impl_integer { + ($($type:ty: $signedness:ty), *) => { + $( + impl Integer for $type { + type Signedness = $signedness; + + const BITS: u32 = <$type>::BITS; + } + )* + }; +} + +impl_integer!( + u8: Unsigned, + u16: Unsigned, + u32: Unsigned, + u64: Unsigned, + u128: Unsigned, + usize: Unsigned, + i8: Signed, + i16: Signed, + i32: Signed, + i64: Signed, + i128: Signed, + isize: Signed +); -- cgit v1.2.3 From 01e345e82ec3a5a7edeb9fa0dcb7fd4b0e5c534e Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sat, 8 Nov 2025 11:23:48 +0900 Subject: rust: num: add Bounded integer wrapping type Add the `Bounded` integer wrapper type, which restricts the number of bits allowed to represent of value. This is useful to e.g. enforce guarantees when working with bitfields that have an arbitrary number of bits. Alongside this type, provide many `From` and `TryFrom` implementations are to reduce friction when using with regular integer types. Proxy implementations of common integer operations are also provided. Signed-off-by: Alexandre Courbot Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20251108-bounded_ints-v4-2-c9342ac7ebd1@nvidia.com [ Added intra-doc link. Fixed a few other nits. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/num.rs | 3 + rust/kernel/num/bounded.rs | 1056 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1059 insertions(+) create mode 100644 rust/kernel/num/bounded.rs (limited to 'rust/kernel') diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs index c8c91cb9e682..8532b511384c 100644 --- a/rust/kernel/num.rs +++ b/rust/kernel/num.rs @@ -4,6 +4,9 @@ use core::ops; +pub mod bounded; +pub use bounded::*; + /// Designates unsigned primitive types. pub enum Unsigned {} diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs new file mode 100644 index 000000000000..18e45bf6f84b --- /dev/null +++ b/rust/kernel/num/bounded.rs @@ -0,0 +1,1056 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Implementation of [`Bounded`], a wrapper around integer types limiting the number of bits +//! usable for value representation. + +use core::{ + cmp, + fmt, + ops::{ + self, + Deref, // + }, //, +}; + +use kernel::{ + num::Integer, + prelude::*, // +}; + +/// Evaluates to `true` if `$value` can be represented using at most `$n` bits in a `$type`. +/// +/// `expr` must be of type `type`, or the result will be incorrect. +/// +/// Can be used in const context. +macro_rules! fits_within { + ($value:expr, $type:ty, $n:expr) => {{ + let shift: u32 = <$type>::BITS - $n; + + // `value` fits within `$n` bits if shifting it left by the number of unused bits, then + // right by the same number, doesn't change it. + // + // This method has the benefit of working for both unsigned and signed values. + ($value << shift) >> shift == $value + }}; +} + +/// Returns `true` if `value` can be represented with at most `N` bits in a `T`. +fn fits_within(value: T, num_bits: u32) -> bool { + fits_within!(value, T, num_bits) +} + +/// An integer value that requires only the `N` less significant bits of the wrapped type to be +/// encoded. +/// +/// This limits the number of usable bits in the wrapped integer type, and thus the stored value to +/// a narrower range, which provides guarantees that can be useful when working with in e.g. +/// bitfields. +/// +/// # Invariants +/// +/// - `N` is greater than `0`. +/// - `N` is less than or equal to `T::BITS`. +/// - Stored values can be represented with at most `N` bits. +/// +/// # Examples +/// +/// The preferred way to create values is through constants and the [`Bounded::new`] family of +/// constructors, as they trigger a build error if the type invariants cannot be withheld. +/// +/// ``` +/// use kernel::num::Bounded; +/// +/// // An unsigned 8-bit integer, of which only the 4 LSBs are used. +/// // The value `15` is statically validated to fit that constraint at build time. +/// let v = Bounded::::new::<15>(); +/// assert_eq!(v.get(), 15); +/// +/// // Same using signed values. +/// let v = Bounded::::new::<-8>(); +/// assert_eq!(v.get(), -8); +/// +/// // This doesn't build: a `u8` is smaller than the requested 9 bits. +/// // let _ = Bounded::::new::<10>(); +/// +/// // This also doesn't build: the requested value doesn't fit within 4 signed bits. +/// // let _ = Bounded::::new::<8>(); +/// ``` +/// +/// Values can also be validated at runtime with [`Bounded::try_new`]. +/// +/// ``` +/// use kernel::num::Bounded; +/// +/// // This succeeds because `15` can be represented with 4 unsigned bits. +/// assert!(Bounded::::try_new(15).is_some()); +/// +/// // This fails because `16` cannot be represented with 4 unsigned bits. +/// assert!(Bounded::::try_new(16).is_none()); +/// ``` +/// +/// Non-constant expressions can be validated at build-time thanks to compiler optimizations. This +/// should be used with caution, on simple expressions only. +/// +/// ``` +/// use kernel::num::Bounded; +/// # fn some_number() -> u32 { 0xffffffff } +/// +/// // Here the compiler can infer from the mask that the type invariants are not violated, even +/// // though the value returned by `some_number` is not statically known. +/// let v = Bounded::::from_expr(some_number() & 0xf); +/// ``` +/// +/// Comparison and arithmetic operations are supported on [`Bounded`]s with a compatible backing +/// type, regardless of their number of valid bits. +/// +/// ``` +/// use kernel::num::Bounded; +/// +/// let v1 = Bounded::::new::<4>(); +/// let v2 = Bounded::::new::<15>(); +/// +/// assert!(v1 != v2); +/// assert!(v1 < v2); +/// assert_eq!(v1 + v2, 19); +/// assert_eq!(v2 % v1, 3); +/// ``` +/// +/// These operations are also supported between a [`Bounded`] and its backing type. +/// +/// ``` +/// use kernel::num::Bounded; +/// +/// let v = Bounded::::new::<15>(); +/// +/// assert!(v == 15); +/// assert!(v > 12); +/// assert_eq!(v + 5, 20); +/// assert_eq!(v / 3, 5); +/// ``` +/// +/// A change of backing types is possible using [`Bounded::cast`], and the number of valid bits can +/// be extended or reduced with [`Bounded::extend`] and [`Bounded::try_shrink`]. +/// +/// ``` +/// use kernel::num::Bounded; +/// +/// let v = Bounded::::new::<127>(); +/// +/// // Changes backing type from `u32` to `u16`. +/// let _: Bounded = v.cast(); +/// +/// // This does not build, as `u8` is smaller than 12 bits. +/// // let _: Bounded = v.cast(); +/// +/// // We can safely extend the number of bits... +/// let _ = v.extend::<15>(); +/// +/// // ... to the limits of the backing type. This doesn't build as a `u32` cannot contain 33 bits. +/// // let _ = v.extend::<33>(); +/// +/// // Reducing the number of bits is validated at runtime. This works because `127` can be +/// // represented with 8 bits. +/// assert!(v.try_shrink::<8>().is_some()); +/// +/// // ... but not with 6, so this fails. +/// assert!(v.try_shrink::<6>().is_none()); +/// ``` +/// +/// Infallible conversions from a primitive integer to a large-enough [`Bounded`] are supported. +/// +/// ``` +/// use kernel::num::Bounded; +/// +/// // This unsigned `Bounded` has 8 bits, so it can represent any `u8`. +/// let v = Bounded::::from(128u8); +/// assert_eq!(v.get(), 128); +/// +/// // This signed `Bounded` has 8 bits, so it can represent any `i8`. +/// let v = Bounded::::from(-128i8); +/// assert_eq!(v.get(), -128); +/// +/// // This doesn't build, as this 6-bit `Bounded` does not have enough capacity to represent a +/// // `u8` (regardless of the passed value). +/// // let _ = Bounded::::from(10u8); +/// +/// // Booleans can be converted into single-bit `Bounded`s. +/// +/// let v = Bounded::::from(false); +/// assert_eq!(v.get(), 0); +/// +/// let v = Bounded::::from(true); +/// assert_eq!(v.get(), 1); +/// ``` +/// +/// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and +/// dependent on the number of bits used for value representation, not on the backing type. +/// +/// ``` +/// use kernel::num::Bounded; +/// +/// // Even though its backing type is `u32`, this `Bounded` only uses 6 bits and thus can safely +/// // be converted to a `u8`. +/// let v = Bounded::::new::<63>(); +/// assert_eq!(u8::from(v), 63); +/// +/// // Same using signed values. +/// let v = Bounded::::new::<-128>(); +/// assert_eq!(i8::from(v), -128); +/// +/// // This however does not build, as 10 bits won't fit into a `u8` (regardless of the actually +/// // contained value). +/// let _v = Bounded::::new::<10>(); +/// // assert_eq!(u8::from(_v), 10); +/// +/// // Single-bit `Bounded`s can be converted into a boolean. +/// let v = Bounded::::new::<1>(); +/// assert_eq!(bool::from(v), true); +/// +/// let v = Bounded::::new::<0>(); +/// assert_eq!(bool::from(v), false); +/// ``` +/// +/// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the +/// [`TryIntoBounded`] trait. +/// +/// ``` +/// use kernel::num::{Bounded, TryIntoBounded}; +/// +/// // Succeeds because `128` fits into 8 bits. +/// let v: Option> = 128u32.try_into_bitint(); +/// assert_eq!(v.as_deref().copied(), Some(128)); +/// +/// // Fails because `128` doesn't fits into 6 bits. +/// let v: Option> = 128u32.try_into_bitint(); +/// assert_eq!(v, None); +/// ``` +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Default, Hash)] +pub struct Bounded(T); + +/// Validating the value as a const expression cannot be done as a regular method, as the +/// arithmetic operations we rely on to check the bounds are not const. Thus, implement +/// [`Bounded::new`] using a macro. +macro_rules! impl_const_new { + ($($type:ty)*) => { + $( + impl Bounded<$type, N> { + /// Creates a [`Bounded`] for the constant `VALUE`. + /// + /// Fails at build time if `VALUE` cannot be represented with `N` bits. + /// + /// This method should be preferred to [`Self::from_expr`] whenever possible. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + #[doc = ::core::concat!( + "let v = Bounded::<", + ::core::stringify!($type), + ", 4>::new::<7>();")] + /// assert_eq!(v.get(), 7); + /// ``` + pub const fn new() -> Self { + // Statically assert that `VALUE` fits within the set number of bits. + const { + assert!(fits_within!(VALUE, $type, N)); + } + + // INVARIANT: `fits_within` confirmed that `VALUE` can be represented within + // `N` bits. + Self::__new(VALUE) + } + } + )* + }; +} + +impl_const_new!( + u8 u16 u32 u64 usize + i8 i16 i32 i64 isize +); + +impl Bounded +where + T: Integer, +{ + /// Private constructor enforcing the type invariants. + /// + /// All instances of [`Bounded`] must be created through this method as it enforces most of the + /// type invariants. + /// + /// The caller remains responsible for checking, either statically or dynamically, that `value` + /// can be represented as a `T` using at most `N` bits. + const fn __new(value: T) -> Self { + // Enforce the type invariants. + const { + // `N` cannot be zero. + assert!(N != 0); + // The backing type is at least as large as `N` bits. + assert!(N <= T::BITS); + } + + Self(value) + } + + /// Attempts to turn `value` into a `Bounded` using `N` bits. + /// + /// Returns [`None`] if `value` doesn't fit within `N` bits. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// let v = Bounded::::try_new(1); + /// assert_eq!(v.as_deref().copied(), Some(1)); + /// + /// let v = Bounded::::try_new(-2); + /// assert_eq!(v.as_deref().copied(), Some(-2)); + /// + /// // `0x1ff` doesn't fit into 8 unsigned bits. + /// let v = Bounded::::try_new(0x1ff); + /// assert_eq!(v, None); + /// + /// // The range of values representable with 4 bits is `[-8..=7]`. The following tests these + /// // limits. + /// let v = Bounded::::try_new(-8); + /// assert_eq!(v.map(Bounded::get), Some(-8)); + /// let v = Bounded::::try_new(-9); + /// assert_eq!(v, None); + /// let v = Bounded::::try_new(7); + /// assert_eq!(v.map(Bounded::get), Some(7)); + /// let v = Bounded::::try_new(8); + /// assert_eq!(v, None); + /// ``` + pub fn try_new(value: T) -> Option { + fits_within(value, N).then(|| { + // INVARIANT: `fits_within` confirmed that `value` can be represented within `N` bits. + Self::__new(value) + }) + } + + /// Checks that `expr` is valid for this type at compile-time and build a new value. + /// + /// This relies on [`build_assert!`] and guaranteed optimization to perform validation at + /// compile-time. If `expr` cannot be proved to be within the requested bounds at compile-time, + /// use the fallible [`Self::try_new`] instead. + /// + /// Limit this to simple, easily provable expressions, and prefer one of the [`Self::new`] + /// constructors whenever possible as they statically validate the value instead of relying on + /// compiler optimizations. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// # fn some_number() -> u32 { 0xffffffff } + /// + /// // Some undefined number. + /// let v: u32 = some_number(); + /// + /// // Triggers a build error as `v` cannot be asserted to fit within 4 bits... + /// // let _ = Bounded::::from_expr(v); + /// + /// // ... but this works as the compiler can assert the range from the mask. + /// let _ = Bounded::::from_expr(v & 0xf); + /// + /// // These expressions are simple enough to be proven correct, but since they are static the + /// // `new` constructor should be preferred. + /// assert_eq!(Bounded::::from_expr(1).get(), 1); + /// assert_eq!(Bounded::::from_expr(0xff).get(), 0xff); + /// ``` + pub fn from_expr(expr: T) -> Self { + crate::build_assert!( + fits_within(expr, N), + "Requested value larger than maximal representable value." + ); + + // INVARIANT: `fits_within` confirmed that `expr` can be represented within `N` bits. + Self::__new(expr) + } + + /// Returns the wrapped value as the backing type. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// let v = Bounded::::new::<7>(); + /// assert_eq!(v.get(), 7u32); + /// ``` + pub fn get(self) -> T { + *self.deref() + } + + /// Increases the number of bits usable for `self`. + /// + /// This operation cannot fail. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// let v = Bounded::::new::<7>(); + /// let larger_v = v.extend::<12>(); + /// // The contained values are equal even though `larger_v` has a bigger capacity. + /// assert_eq!(larger_v, v); + /// ``` + pub const fn extend(self) -> Bounded { + const { + assert!( + M >= N, + "Requested number of bits is less than the current representation." + ); + } + + // INVARIANT: The value did fit within `N` bits, so it will all the more fit within + // the larger `M` bits. + Bounded::__new(self.0) + } + + /// Attempts to shrink the number of bits usable for `self`. + /// + /// Returns [`None`] if the value of `self` cannot be represented within `M` bits. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// let v = Bounded::::new::<7>(); + /// + /// // `7` can be represented using 3 unsigned bits... + /// let smaller_v = v.try_shrink::<3>(); + /// assert_eq!(smaller_v.as_deref().copied(), Some(7)); + /// + /// // ... but doesn't fit within `2` bits. + /// assert_eq!(v.try_shrink::<2>(), None); + /// ``` + pub fn try_shrink(self) -> Option> { + Bounded::::try_new(self.get()) + } + + /// Casts `self` into a [`Bounded`] backed by a different storage type, but using the same + /// number of valid bits. + /// + /// Both `T` and `U` must be of same signedness, and `U` must be at least as large as + /// `N` bits, or a build error will occur. + /// + /// # Examples + /// + /// ``` + /// use kernel::num::Bounded; + /// + /// let v = Bounded::::new::<127>(); + /// + /// let u16_v: Bounded = v.cast(); + /// assert_eq!(u16_v.get(), 127); + /// + /// // This won't build: a `u8` is smaller than the required 12 bits. + /// // let _: Bounded = v.cast(); + /// ``` + pub fn cast(self) -> Bounded + where + U: TryFrom + Integer, + T: Integer, + U: Integer, + { + // SAFETY: The converted value is represented using `N` bits, `U` can contain `N` bits, and + // `U` and `T` have the same sign, hence this conversion cannot fail. + let value = unsafe { U::try_from(self.get()).unwrap_unchecked() }; + + // INVARIANT: Although the backing type has changed, the value is still represented within + // `N` bits, and with the same signedness. + Bounded::__new(value) + } +} + +impl Deref for Bounded +where + T: Integer, +{ + type Target = T; + + fn deref(&self) -> &Self::Target { + // Enforce the invariant to inform the compiler of the bounds of the value. + if !fits_within(self.0, N) { + // SAFETY: Per the `Bounded` invariants, `fits_within` can never return `false` on the + // value of a valid instance. + unsafe { core::hint::unreachable_unchecked() } + } + + &self.0 + } +} + +/// Trait similar to [`TryInto`] but for [`Bounded`], to avoid conflicting implementations. +/// +/// # Examples +/// +/// ``` +/// use kernel::num::{Bounded, TryIntoBounded}; +/// +/// // Succeeds because `128` fits into 8 bits. +/// let v: Option> = 128u32.try_into_bitint(); +/// assert_eq!(v.as_deref().copied(), Some(128)); +/// +/// // Fails because `128` doesn't fits into 6 bits. +/// let v: Option> = 128u32.try_into_bitint(); +/// assert_eq!(v, None); +/// ``` +pub trait TryIntoBounded { + /// Attempts to convert `self` into a [`Bounded`] using `N` bits. + /// + /// Returns [`None`] if `self` does not fit into the target type. + fn try_into_bitint(self) -> Option>; +} + +/// Any integer value can be attempted to be converted into a [`Bounded`] of any size. +impl TryIntoBounded for U +where + T: Integer, + U: TryInto, +{ + fn try_into_bitint(self) -> Option> { + self.try_into().ok().and_then(Bounded::try_new) + } +} + +// Comparisons between `Bounded`s. + +impl PartialEq> for Bounded +where + T: Integer, + U: Integer, + T: PartialEq, +{ + fn eq(&self, other: &Bounded) -> bool { + self.get() == other.get() + } +} + +impl Eq for Bounded where T: Integer {} + +impl PartialOrd> for Bounded +where + T: Integer, + U: Integer, + T: PartialOrd, +{ + fn partial_cmp(&self, other: &Bounded) -> Option { + self.get().partial_cmp(&other.get()) + } +} + +impl Ord for Bounded +where + T: Integer, + T: Ord, +{ + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.get().cmp(&other.get()) + } +} + +// Comparisons between a `Bounded` and its backing type. + +impl PartialEq for Bounded +where + T: Integer, + T: PartialEq, +{ + fn eq(&self, other: &T) -> bool { + self.get() == *other + } +} + +impl PartialOrd for Bounded +where + T: Integer, + T: PartialOrd, +{ + fn partial_cmp(&self, other: &T) -> Option { + self.get().partial_cmp(other) + } +} + +// Implementations of `core::ops` for two `Bounded` with the same backing type. + +impl ops::Add> for Bounded +where + T: Integer, + T: ops::Add, +{ + type Output = T; + + fn add(self, rhs: Bounded) -> Self::Output { + self.get() + rhs.get() + } +} + +impl ops::BitAnd> for Bounded +where + T: Integer, + T: ops::BitAnd, +{ + type Output = T; + + fn bitand(self, rhs: Bounded) -> Self::Output { + self.get() & rhs.get() + } +} + +impl ops::BitOr> for Bounded +where + T: Integer, + T: ops::BitOr, +{ + type Output = T; + + fn bitor(self, rhs: Bounded) -> Self::Output { + self.get() | rhs.get() + } +} + +impl ops::BitXor> for Bounded +where + T: Integer, + T: ops::BitXor, +{ + type Output = T; + + fn bitxor(self, rhs: Bounded) -> Self::Output { + self.get() ^ rhs.get() + } +} + +impl ops::Div> for Bounded +where + T: Integer, + T: ops::Div, +{ + type Output = T; + + fn div(self, rhs: Bounded) -> Self::Output { + self.get() / rhs.get() + } +} + +impl ops::Mul> for Bounded +where + T: Integer, + T: ops::Mul, +{ + type Output = T; + + fn mul(self, rhs: Bounded) -> Self::Output { + self.get() * rhs.get() + } +} + +impl ops::Rem> for Bounded +where + T: Integer, + T: ops::Rem, +{ + type Output = T; + + fn rem(self, rhs: Bounded) -> Self::Output { + self.get() % rhs.get() + } +} + +impl ops::Sub> for Bounded +where + T: Integer, + T: ops::Sub, +{ + type Output = T; + + fn sub(self, rhs: Bounded) -> Self::Output { + self.get() - rhs.get() + } +} + +// Implementations of `core::ops` between a `Bounded` and its backing type. + +impl ops::Add for Bounded +where + T: Integer, + T: ops::Add, +{ + type Output = T; + + fn add(self, rhs: T) -> Self::Output { + self.get() + rhs + } +} + +impl ops::BitAnd for Bounded +where + T: Integer, + T: ops::BitAnd, +{ + type Output = T; + + fn bitand(self, rhs: T) -> Self::Output { + self.get() & rhs + } +} + +impl ops::BitOr for Bounded +where + T: Integer, + T: ops::BitOr, +{ + type Output = T; + + fn bitor(self, rhs: T) -> Self::Output { + self.get() | rhs + } +} + +impl ops::BitXor for Bounded +where + T: Integer, + T: ops::BitXor, +{ + type Output = T; + + fn bitxor(self, rhs: T) -> Self::Output { + self.get() ^ rhs + } +} + +impl ops::Div for Bounded +where + T: Integer, + T: ops::Div, +{ + type Output = T; + + fn div(self, rhs: T) -> Self::Output { + self.get() / rhs + } +} + +impl ops::Mul for Bounded +where + T: Integer, + T: ops::Mul, +{ + type Output = T; + + fn mul(self, rhs: T) -> Self::Output { + self.get() * rhs + } +} + +impl ops::Neg for Bounded +where + T: Integer, + T: ops::Neg, +{ + type Output = T; + + fn neg(self) -> Self::Output { + -self.get() + } +} + +impl ops::Not for Bounded +where + T: Integer, + T: ops::Not, +{ + type Output = T; + + fn not(self) -> Self::Output { + !self.get() + } +} + +impl ops::Rem for Bounded +where + T: Integer, + T: ops::Rem, +{ + type Output = T; + + fn rem(self, rhs: T) -> Self::Output { + self.get() % rhs + } +} + +impl ops::Sub for Bounded +where + T: Integer, + T: ops::Sub, +{ + type Output = T; + + fn sub(self, rhs: T) -> Self::Output { + self.get() - rhs + } +} + +// Proxy implementations of `core::fmt`. + +impl fmt::Display for Bounded +where + T: Integer, + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +impl fmt::Binary for Bounded +where + T: Integer, + T: fmt::Binary, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +impl fmt::LowerExp for Bounded +where + T: Integer, + T: fmt::LowerExp, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +impl fmt::LowerHex for Bounded +where + T: Integer, + T: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +impl fmt::Octal for Bounded +where + T: Integer, + T: fmt::Octal, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +impl fmt::UpperExp for Bounded +where + T: Integer, + T: fmt::UpperExp, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +impl fmt::UpperHex for Bounded +where + T: Integer, + T: fmt::UpperHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +/// Implements `$trait` for all [`Bounded`] types represented using `$num_bits`. +/// +/// This is used to declare size properties as traits that we can constrain against in impl blocks. +macro_rules! impl_size_rule { + ($trait:ty, $($num_bits:literal)*) => { + $( + impl $trait for Bounded where T: Integer {} + )* + }; +} + +/// Local trait expressing the fact that a given [`Bounded`] has at least `N` bits used for value +/// representation. +trait AtLeastXBits {} + +/// Implementations for infallibly converting a primitive type into a [`Bounded`] that can contain +/// it. +/// +/// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent +/// module. +mod atleast_impls { + use super::*; + + // Number of bits at least as large as 64. + impl_size_rule!(AtLeastXBits<64>, 64); + + // Anything 64 bits or more is also larger than 32. + impl AtLeastXBits<32> for T where T: AtLeastXBits<64> {} + // Other numbers of bits at least as large as 32. + impl_size_rule!(AtLeastXBits<32>, + 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + ); + + // Anything 32 bits or more is also larger than 16. + impl AtLeastXBits<16> for T where T: AtLeastXBits<32> {} + // Other numbers of bits at least as large as 16. + impl_size_rule!(AtLeastXBits<16>, + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30 31 + ); + + // Anything 16 bits or more is also larger than 8. + impl AtLeastXBits<8> for T where T: AtLeastXBits<16> {} + // Other numbers of bits at least as large as 8. + impl_size_rule!(AtLeastXBits<8>, 8 9 10 11 12 13 14 15); +} + +/// Generates `From` implementations from a primitive type into a [`Bounded`] with +/// enough bits to store any value of that type. +/// +/// Note: The only reason for having this macro is that if we pass `$type` as a generic +/// parameter, we cannot use it in the const context of [`AtLeastXBits`]'s generic parameter. This +/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a +/// regular `impl` block. +macro_rules! impl_from_primitive { + ($($type:ty)*) => { + $( + #[doc = ::core::concat!( + "Conversion from a [`", + ::core::stringify!($type), + "`] into a [`Bounded`] of same signedness with enough bits to store it.")] + impl From<$type> for Bounded + where + $type: Integer, + T: Integer::Signedness> + From<$type>, + Self: AtLeastXBits<{ <$type as Integer>::BITS as usize }>, + { + fn from(value: $type) -> Self { + // INVARIANT: The trait bound on `Self` guarantees that `N` bits is + // enough to hold any value of the source type. + Self::__new(T::from(value)) + } + } + )* + } +} + +impl_from_primitive!( + u8 u16 u32 u64 usize + i8 i16 i32 i64 isize +); + +/// Local trait expressing the fact that a given [`Bounded`] fits into a primitive type of `N` bits, +/// provided they have the same signedness. +trait FitsInXBits {} + +/// Implementations for infallibly converting a [`Bounded`] into a primitive type that can contain +/// it. +/// +/// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent +/// module. +mod fits_impls { + use super::*; + + // Number of bits that fit into a 8-bits primitive. + impl_size_rule!(FitsInXBits<8>, 1 2 3 4 5 6 7 8); + + // Anything that fits into 8 bits also fits into 16. + impl FitsInXBits<16> for T where T: FitsInXBits<8> {} + // Other number of bits that fit into a 16-bits primitive. + impl_size_rule!(FitsInXBits<16>, 9 10 11 12 13 14 15 16); + + // Anything that fits into 16 bits also fits into 32. + impl FitsInXBits<32> for T where T: FitsInXBits<16> {} + // Other number of bits that fit into a 32-bits primitive. + impl_size_rule!(FitsInXBits<32>, + 17 18 19 20 21 22 23 24 + 25 26 27 28 29 30 31 32 + ); + + // Anything that fits into 32 bits also fits into 64. + impl FitsInXBits<64> for T where T: FitsInXBits<32> {} + // Other number of bits that fit into a 64-bits primitive. + impl_size_rule!(FitsInXBits<64>, + 33 34 35 36 37 38 39 40 + 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 + 57 58 59 60 61 62 63 64 + ); +} + +/// Generates [`From`] implementations from a [`Bounded`] into a primitive type that is +/// guaranteed to contain it. +/// +/// Note: The only reason for having this macro is that if we pass `$type` as a generic +/// parameter, we cannot use it in the const context of `AtLeastXBits`'s generic parameter. This +/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a +/// regular `impl` block. +macro_rules! impl_into_primitive { + ($($type:ty)*) => { + $( + #[doc = ::core::concat!( + "Conversion from a [`Bounded`] with no more bits than a [`", + ::core::stringify!($type), + "`] and of same signedness into [`", + ::core::stringify!($type), + "`]")] + impl From> for $type + where + $type: Integer + TryFrom, + T: Integer::Signedness>, + Bounded: FitsInXBits<{ <$type as Integer>::BITS as usize }>, + { + fn from(value: Bounded) -> $type { + // SAFETY: The trait bound on `Bounded` ensures that any value it holds (which + // is constrained to `N` bits) can fit into the destination type, so this + // conversion cannot fail. + unsafe { <$type>::try_from(value.get()).unwrap_unchecked() } + } + } + )* + } +} + +impl_into_primitive!( + u8 u16 u32 u64 usize + i8 i16 i32 i64 isize +); + +// Single-bit `Bounded`s can be converted from/to a boolean. + +impl From> for bool +where + T: Integer + Zeroable, +{ + fn from(value: Bounded) -> Self { + value.get() != Zeroable::zeroed() + } +} + +impl From for Bounded +where + T: Integer + From, +{ + fn from(value: bool) -> Self { + // INVARIANT: A boolean can be represented using a single bit, and thus fits within any + // integer type for any `N` > 0. + Self::__new(T::from(value)) + } +} -- cgit v1.2.3 From 494de8f67b1e586b0190eb7f835e97c97f6b81b1 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 17 Nov 2025 11:38:07 -0500 Subject: rust: sync: replace `kernel::c_str!` with C-Strings C-String literals were added in Rust 1.77. Replace instances of `kernel::c_str!` with C-String literals where possible. Acked-by: Greg Kroah-Hartman Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Signed-off-by: Tamir Duberstein Link: https://patch.msgid.link/20251117-core-cstr-cstrings-v4-1-924886ad9f75@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/sync.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index cf5b638a097d..c94753d6413e 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -48,7 +48,6 @@ impl LockClassKey { /// /// # Examples /// ``` - /// # use kernel::c_str; /// # use kernel::alloc::KBox; /// # use kernel::types::ForeignOwnable; /// # use kernel::sync::{LockClassKey, SpinLock}; @@ -60,7 +59,7 @@ impl LockClassKey { /// { /// stack_pin_init!(let num: SpinLock = SpinLock::new( /// 0, - /// c_str!("my_spinlock"), + /// c"my_spinlock", /// // SAFETY: `key_ptr` is returned by the above `into_foreign()`, whose /// // `from_foreign()` has not yet been called. /// unsafe { > as ForeignOwnable>::borrow(key_ptr) } -- cgit v1.2.3 From bc197e24a3acd13dd0b7b07c1448c5c225946546 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sat, 22 Nov 2025 13:00:49 +0900 Subject: rust: num: bounded: Always inline fits_within and from_expr `from_expr` relies on `build_assert` to infer that the passed expression fits the type's boundaries at build time. That inference can only be successful its code (and that of `fits_within`, which performs the check) is inlined, as a dedicated function would need to work with a variable and cannot verify that property. While inlining happens as expected in most cases, it is not guaranteed. In particular, kernel options that optimize for size like `CONFIG_CC_OPTIMIZE_FOR_SIZE` can result in `from_expr` not being inlined. Add `#[inline(always)]` attributes to both `fits_within` and `from_expr` to make the compiler inline these functions more aggressively, as it does not make sense to use them non-inlined anyway. [ For reference, the errors look like: ld.lld: error: undefined symbol: rust_build_error >>> referenced by build_assert.rs:83 (rust/kernel/build_assert.rs:83) >>> rust/doctests_kernel_generated.o:(>::from_expr) in archive vmlinux.a - Miguel ] Fixes: 01e345e82ec3 ("rust: num: add Bounded integer wrapping type") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202511210055.RUsFNku1-lkp@intel.com/ Suggested-by: Gary Guo Signed-off-by: Alexandre Courbot Link: https://patch.msgid.link/20251122-bounded_ints_fix-v1-1-1e07589d4955@nvidia.com Signed-off-by: Miguel Ojeda --- rust/kernel/num/bounded.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index 18e45bf6f84b..92c41b2eb760 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -35,6 +35,7 @@ macro_rules! fits_within { } /// Returns `true` if `value` can be represented with at most `N` bits in a `T`. +#[inline(always)] fn fits_within(value: T, num_bits: u32) -> bool { fits_within!(value, T, num_bits) } @@ -362,6 +363,7 @@ where /// assert_eq!(Bounded::::from_expr(1).get(), 1); /// assert_eq!(Bounded::::from_expr(0xff).get(), 0xff); /// ``` + #[inline(always)] pub fn from_expr(expr: T) -> Self { crate::build_assert!( fits_within(expr, N), -- cgit v1.2.3 From 841f31d298693e82aaa9e7ac09f5fa9c8dcfdbc3 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Mon, 24 Nov 2025 22:50:02 +0900 Subject: rust: num: bounded: rename `try_into_bitint` to `try_into_bounded` This is a remnant from when `Bounded` was called `BitInt` which I didn't rename. Fix this. Fixes: 01e345e82ec3 ("rust: num: add Bounded integer wrapping type") Signed-off-by: Alexandre Courbot Link: https://patch.msgid.link/20251124-bounded_fix-v1-1-d8e34e1c727f@nvidia.com Signed-off-by: Miguel Ojeda --- rust/kernel/num/bounded.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index 92c41b2eb760..f870080af8ac 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -218,11 +218,11 @@ fn fits_within(value: T, num_bits: u32) -> bool { /// use kernel::num::{Bounded, TryIntoBounded}; /// /// // Succeeds because `128` fits into 8 bits. -/// let v: Option> = 128u32.try_into_bitint(); +/// let v: Option> = 128u32.try_into_bounded(); /// assert_eq!(v.as_deref().copied(), Some(128)); /// /// // Fails because `128` doesn't fits into 6 bits. -/// let v: Option> = 128u32.try_into_bitint(); +/// let v: Option> = 128u32.try_into_bounded(); /// assert_eq!(v, None); /// ``` #[repr(transparent)] @@ -498,18 +498,18 @@ where /// use kernel::num::{Bounded, TryIntoBounded}; /// /// // Succeeds because `128` fits into 8 bits. -/// let v: Option> = 128u32.try_into_bitint(); +/// let v: Option> = 128u32.try_into_bounded(); /// assert_eq!(v.as_deref().copied(), Some(128)); /// /// // Fails because `128` doesn't fits into 6 bits. -/// let v: Option> = 128u32.try_into_bitint(); +/// let v: Option> = 128u32.try_into_bounded(); /// assert_eq!(v, None); /// ``` pub trait TryIntoBounded { /// Attempts to convert `self` into a [`Bounded`] using `N` bits. /// /// Returns [`None`] if `self` does not fit into the target type. - fn try_into_bitint(self) -> Option>; + fn try_into_bounded(self) -> Option>; } /// Any integer value can be attempted to be converted into a [`Bounded`] of any size. @@ -518,7 +518,7 @@ where T: Integer, U: TryInto, { - fn try_into_bitint(self) -> Option> { + fn try_into_bounded(self) -> Option> { self.try_into().ok().and_then(Bounded::try_new) } } -- cgit v1.2.3