From 1a933719e70787f462d6126230a403c15f95598e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 3 Feb 2026 13:06:26 +0000 Subject: rust: task: use `as_char_ptr` instead of `as_ptr().cast()` `as_char_ptr` would provide the correct (unsigned char) type without needing to convert to an intermediate type and cast the pointer. The `as_ptr()` function is going to be disallowed by clippy warning, so fix this usage. This is used only if CONFIG_DEBUG_ATOMIC_SLEEP=y. Instead of conditionally importing `CStrExt`, import it via prelude instead, and remove other imports that are already available via the prelude. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202601221157.89t3Sqbl-lkp@intel.com/ Signed-off-by: Gary Guo Link: https://patch.msgid.link/20260203130745.868762-1-gary@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/task.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index cc907fb531bc..049c8a4d45d8 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -6,16 +6,15 @@ use crate::{ bindings, - ffi::{c_int, c_long, c_uint}, mm::MmWithUser, pid_namespace::PidNamespace, + prelude::*, sync::aref::ARef, types::{NotThreadSafe, Opaque}, }; use core::{ - cmp::{Eq, PartialEq}, ops::Deref, - ptr, + ptr, // }; /// A sentinel value used for infinite timeouts. @@ -419,7 +418,7 @@ pub fn might_sleep() { let file = kernel::file_from_location(loc); // SAFETY: `file.as_ptr()` is valid for reading and guaranteed to be nul-terminated. - unsafe { crate::bindings::__might_sleep(file.as_ptr().cast(), loc.line() as i32) } + unsafe { crate::bindings::__might_sleep(file.as_char_ptr(), loc.line() as i32) } } // SAFETY: Always safe to call. -- cgit v1.2.3 From b3d161f22ba9b2dc16bb82aa2b8515d98c99624f Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 3 Feb 2026 13:06:27 +0000 Subject: rust: disallow use of `CStr::as_ptr` and `CStr::from_ptr` As kernel always use unsigned char and not the platform ABI's default, an user should always use `as_char_ptr` provided via `CStrExt` instead. Therefore configure `disallow-methods` feature of clippy to catch incorrect usage. Similarly, the dual `from_ptr` is also disallowed. [ As an example, without the previous commit, we would get a warning like: warning: use of a disallowed method `core::ffi::CStr::as_ptr` --> rust/kernel/task.rs:422:54 | 422 | unsafe { crate::bindings::__might_sleep(file.as_ptr().cast(), loc.line() as i32) } | ^^^^^^ help: kernel's `char` is always unsigned, use `as_char_ptr` instead: `kernel::prelude::CStrExt::as_char_ptr` | = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.94.0/index.html#disallowed_methods = note: `-W clippy::disallowed-methods` implied by `-W clippy::all` = help: to override `-W clippy::all` add `#[allow(clippy::disallowed_methods)]` - Miguel ] Signed-off-by: Gary Guo Reviewed-by: Tamir Duberstein Link: https://patch.msgid.link/20260203130745.868762-2-gary@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/str.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index fa87779d2253..97bf9427af59 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -189,6 +189,7 @@ macro_rules! b_str { // // - error[E0379]: functions in trait impls cannot be declared const #[inline] +#[expect(clippy::disallowed_methods, reason = "internal implementation")] pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char { c_str.as_ptr().cast() } @@ -319,6 +320,7 @@ unsafe fn to_bytes_mut(s: &mut CStr) -> &mut [u8] { impl CStrExt for CStr { #[inline] + #[expect(clippy::disallowed_methods, reason = "internal implementation")] 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()) } @@ -334,6 +336,7 @@ impl CStrExt for CStr { } #[inline] + #[expect(clippy::disallowed_methods, reason = "internal implementation")] fn as_char_ptr(&self) -> *const c_char { self.as_ptr().cast() } -- cgit v1.2.3 From 1353b8f32c49235d5c66bad3e197025c26d1684e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 9 Mar 2026 13:01:57 -0400 Subject: rust: str: update `c_str!` documentation Now that all literals are C-Strings, update the documentation to explain that use of this macro should be limited to non-literal strings. Link: https://github.com/Rust-for-Linux/linux/issues/1075 Acked-by: Greg Kroah-Hartman Reviewed-by: Alice Ryhl Signed-off-by: Tamir Duberstein Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260309-cstr-rename-macro-v2-1-25f7de75944e@kernel.org [ Apply sentence case to comment. Reword title. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/str.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 97bf9427af59..9f547ba068bb 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -379,19 +379,32 @@ impl AsRef for CStr { } } -/// Creates a new [`CStr`] from a string literal. +/// Creates a new [`CStr`] at compile time. /// -/// The string literal should not contain any `NUL` bytes. +/// Rust supports C string literals since Rust 1.77, and they should be used instead of this macro +/// where possible. This macro exists to allow static *non-literal* C strings to be created at +/// compile time. This is most often used in other macros. +/// +/// # Panics +/// +/// This macro panics if the operand contains an interior `NUL` byte. /// /// # Examples /// /// ``` /// # use kernel::c_str; /// # use kernel::str::CStr; -/// const MY_CSTR: &CStr = c_str!("My awesome CStr!"); +/// // This is allowed, but `c"literal"` should be preferred for literals. +/// const BAD: &CStr = c_str!("literal"); +/// +/// // `c_str!` is still needed for static non-literal C strings. +/// const GOOD: &CStr = c_str!(concat!(file!(), ":", line!(), ": My CStr!")); /// ``` #[macro_export] macro_rules! c_str { + // NB: We could write `($str:lit) => compile_error!("use a C string literal instead");` here but + // that would trigger when the literal is at the top of several macro expansions. That would be + // too limiting to macro authors. ($str:expr) => {{ const S: &str = concat!($str, "\0"); const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) { -- cgit v1.2.3 From dfce283387274446ef5755de7c59baad1da0b93e Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Sat, 3 Jan 2026 01:57:12 +0530 Subject: rust: i2c: Update ARef and AlwaysRefCounted imports to use sync::aref Update call sites in `i2c.rs` to import `ARef` and `AlwaysRefCounted` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Acked-by: Igor Korotin Link: https://patch.msgid.link/20260102202714.184223-3-shankari.ak0208@gmail.com [ Move `ARef` import into the `kernel` `use` tree above. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/i2c.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index bb5b830f48c3..7b908f0c5a58 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -16,10 +16,11 @@ use crate::{ error::*, of, prelude::*, - types::{ - AlwaysRefCounted, - Opaque, // - }, // + sync::aref::{ + ARef, + AlwaysRefCounted, // + }, + types::Opaque, // }; use core::{ @@ -31,8 +32,6 @@ use core::{ }, // }; -use kernel::types::ARef; - /// An I2C device id table. #[repr(transparent)] #[derive(Clone, Copy)] @@ -416,7 +415,7 @@ kernel::impl_device_context_deref!(unsafe { I2cAdapter }); kernel::impl_device_context_into_aref!(I2cAdapter); // SAFETY: Instances of `I2cAdapter` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for I2cAdapter { +unsafe impl AlwaysRefCounted for I2cAdapter { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. unsafe { bindings::i2c_get_adapter(self.index()) }; -- cgit v1.2.3 From ebbed9d02ece592c3e693db72197afad8de70af8 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Sat, 3 Jan 2026 01:57:13 +0530 Subject: rust: usb: Update AlwaysRefCounted imports to use sync::aref Update call sites in `usb.rs` to import `AlwaysRefCounted` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Link: https://patch.msgid.link/20260102202714.184223-4-shankari.ak0208@gmail.com [ Rebase. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/usb.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 0e1b9a88f4f1..9c17a672cd27 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -18,10 +18,8 @@ use crate::{ to_result, // }, prelude::*, - types::{ - AlwaysRefCounted, - Opaque, // - }, + sync::aref::AlwaysRefCounted, + types::Opaque, ThisModule, // }; use core::{ -- cgit v1.2.3 From 79e25710e7227228902d672417b552dd1d7e5d3b Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Sat, 3 Jan 2026 01:57:14 +0530 Subject: rust: types: remove temporary re-exports of ARef and AlwaysRefCounted Remove the temporary re-exports of `ARef` and `AlwaysRefCounted` from `types.rs` now that all in-tree users have been updated to import them directly from `sync::aref`. These re-exports were originally added to avoid breaking the kernel build during the transition period while call sites were incrementally migrated. With all users updated, they are no longer needed. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Link: https://patch.msgid.link/20260102202714.184223-5-shankari.ak0208@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/types.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9c5e7dbf1632..4329d3c2c2e5 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -11,8 +11,6 @@ use core::{ }; use pin_init::{PinInit, Wrapper, Zeroable}; -pub use crate::sync::aref::{ARef, AlwaysRefCounted}; - /// Used to transfer ownership to and from foreign (non-Rust) languages. /// /// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and -- cgit v1.2.3 From bf074eb6891be799174ff42e0051492681fdc045 Mon Sep 17 00:00:00 2001 From: Nakamura Shuta Date: Mon, 19 Jan 2026 15:29:25 +0900 Subject: rust: str: improve safety comment for CString::try_from_fmt Improve the safety comment for the `inc_len()` call in `CString::try_from_fmt()` to clarify why `bytes_written()` is guaranteed not to exceed the buffer capacity. The current comment states that bytes written is bounded by size, but does not explain that this invariant is maintained because: 1. The `Formatter` is created with `size` as its capacity limit 2. The `?` operators on `write_fmt` and `write_str` ensure early return if writing exceeds this limit Suggested-by: Gary Guo Link: https://lore.kernel.org/rust-for-linux/20221114145329.0f47a3ab@GaryWorkstation/ Link: https://github.com/Rust-for-Linux/linux/issues/936 Signed-off-by: Nakamura Shuta Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20260119062925.1647-1-nakamura.shuta@gmail.com [ Updated tags: it was a suggestion from Gary from the mailing list (the linked issue is mostly about adding a `debug_assert_eq!`). - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/str.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'rust/kernel') diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 9f547ba068bb..9b89564ae6d8 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -844,7 +844,10 @@ impl CString { f.write_str("\0")?; // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is - // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`. + // `buf`'s capacity. The `Formatter` is created with `size` as its limit, and the `?` + // operators on `write_fmt` and `write_str` above ensure that if writing exceeds this + // limit, an error is returned early. The contents of the buffer have been initialised + // by writes to `f`. unsafe { buf.inc_len(f.bytes_written()) }; // Check that there are no `NUL` bytes before the end. -- cgit v1.2.3 From c51866f65b8ac37b8883a2e80ada13c8cd4d2f7b Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 14 Nov 2025 13:42:06 -0500 Subject: rust/time: Add Delta::from_nanos() Since rvkms is going to need to create its own Delta instances, and we already have functions for creating Delta with every other unit of time. Signed-off-by: Lyude Paul Reviewed-by: Alice Ryhl Link: https://msgid.link/20251114184207.459335-1-lyude@redhat.com Signed-off-by: Andreas Hindborg --- rust/kernel/time.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs index 6ea98dfcd027..2b096e5a61cd 100644 --- a/rust/kernel/time.rs +++ b/rust/kernel/time.rs @@ -363,6 +363,12 @@ impl Delta { /// A span of time equal to zero. pub const ZERO: Self = Self { nanos: 0 }; + /// Create a new [`Delta`] from a number of nanoseconds. + #[inline] + pub const fn from_nanos(nanos: i64) -> Self { + Self { nanos } + } + /// Create a new [`Delta`] from a number of microseconds. /// /// The `micros` can range from -9_223_372_036_854_775 to 9_223_372_036_854_775. -- cgit v1.2.3 From 67b598db7ef107d80091c4c957694b9a2feffa4c Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 30 Jun 2025 22:10:11 +0900 Subject: rust: time: make ClockSource unsafe trait Mark the ClockSource trait as unsafe and document its safety requirements. Specifically, implementers must guarantee that their `ktime_get()` implementation returns a value in the inclusive range [0, KTIME_MAX]. Update all existing implementations to use `unsafe impl` with corresponding safety comments. Note that there could be potential users of a customized clock source [1] so we don't seal the trait. Link: https://lore.kernel.org/rust-for-linux/Z9xb1r1x5tOzAIZT@boqun-archlinux/ [1] Suggested-by: Boqun Feng Signed-off-by: FUJITA Tomonori Reviewed-by: Alice Ryhl Link: https://msgid.link/20250630131011.405219-1-fujita.tomonori@gmail.com [ Change range expressions in docs. - Andreas ] Signed-off-by: Andreas Hindborg --- rust/kernel/time.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs index 2b096e5a61cd..363e93cbb139 100644 --- a/rust/kernel/time.rs +++ b/rust/kernel/time.rs @@ -60,7 +60,13 @@ pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies { /// cases the user of the clock has to decide which clock is best suited for the /// purpose. In most scenarios clock [`Monotonic`] is the best choice as it /// provides a accurate monotonic notion of time (leap second smearing ignored). -pub trait ClockSource { +/// +/// # Safety +/// +/// Implementers must ensure that `ktime_get()` returns a value in the inclusive range +/// `0..=KTIME_MAX` (i.e., greater than or equal to 0 and less than or equal to +/// `KTIME_MAX`, where `KTIME_MAX` equals `i64::MAX`). +pub unsafe trait ClockSource { /// The kernel clock ID associated with this clock source. /// /// This constant corresponds to the C side `clockid_t` value. @@ -68,7 +74,7 @@ pub trait ClockSource { /// Get the current time from the clock source. /// - /// The function must return a value in the range from 0 to `KTIME_MAX`. + /// The function must return a value in the range `0..=KTIME_MAX`. fn ktime_get() -> bindings::ktime_t; } @@ -85,7 +91,9 @@ pub trait ClockSource { /// count time that the system is suspended. pub struct Monotonic; -impl ClockSource for Monotonic { +// SAFETY: The kernel's `ktime_get()` is guaranteed to return a value +// in `0..=KTIME_MAX`. +unsafe impl ClockSource for Monotonic { const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t; fn ktime_get() -> bindings::ktime_t { @@ -110,7 +118,9 @@ impl ClockSource for Monotonic { /// the clock will experience discontinuity around leap second adjustment. pub struct RealTime; -impl ClockSource for RealTime { +// SAFETY: The kernel's `ktime_get_real()` is guaranteed to return a value +// in `0..=KTIME_MAX`. +unsafe impl ClockSource for RealTime { const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t; fn ktime_get() -> bindings::ktime_t { @@ -128,7 +138,9 @@ impl ClockSource for RealTime { /// discontinuities if the time is changed using settimeofday(2) or similar. pub struct BootTime; -impl ClockSource for BootTime { +// SAFETY: The kernel's `ktime_get_boottime()` is guaranteed to return a value +// in `0..=KTIME_MAX`. +unsafe impl ClockSource for BootTime { const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t; fn ktime_get() -> bindings::ktime_t { @@ -150,7 +162,9 @@ impl ClockSource for BootTime { /// The acronym TAI refers to International Atomic Time. pub struct Tai; -impl ClockSource for Tai { +// SAFETY: The kernel's `ktime_get_clocktai()` is guaranteed to return a value +// in `0..=KTIME_MAX`. +unsafe impl ClockSource for Tai { const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t; fn ktime_get() -> bindings::ktime_t { -- cgit v1.2.3 From ddb1444d3335129ae87d9796ab1debf41c0ee51b Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Thu, 19 Feb 2026 12:57:45 +0100 Subject: hrtimer: add usage examples to documentation Add documentation examples showing various ways to use hrtimers: - Box-allocated timers with shared state in Arc. - Arc-allocated timers. - Stack-based timers for scoped usage. - Mutable stack-based timers with shared state. Tested-by: Daniel Almeida Reviewed-by: Daniel Almeida Reviewed-by: Alice Ryhl Link: https://msgid.link/20260219-hrtimer-examples-v6-19-rc1-v2-1-810cc06ca9f6@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 336 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index 856d2d929a00..2d7f1131a813 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -66,6 +66,342 @@ //! //! A `restart` operation on a timer in the **stopped** state is equivalent to a //! `start` operation. +//! +//! When a type implements both `HrTimerPointer` and `Clone`, it is possible to +//! issue the `start` operation while the timer is in the **started** state. In +//! this case the `start` operation is equivalent to the `restart` operation. +//! +//! # Examples +//! +//! ## Using an intrusive timer living in a [`Box`] +//! +//! ``` +//! # use kernel::{ +//! # alloc::flags, +//! # impl_has_hr_timer, +//! # prelude::*, +//! # sync::{ +//! # atomic::{ordering, Atomic}, +//! # completion::Completion, +//! # Arc, +//! # }, +//! # time::{ +//! # hrtimer::{ +//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer, +//! # HrTimerRestart, HrTimerCallbackContext +//! # }, +//! # Delta, Monotonic, +//! # }, +//! # }; +//! +//! #[pin_data] +//! struct Shared { +//! #[pin] +//! flag: Atomic, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl Shared { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! flag <- Atomic::new(0), +//! cond <- Completion::new(), +//! }) +//! } +//! } +//! +//! #[pin_data] +//! struct BoxIntrusiveHrTimer { +//! #[pin] +//! timer: HrTimer, +//! shared: Arc, +//! } +//! +//! impl BoxIntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! try_pin_init!(Self { +//! timer <- HrTimer::new(), +//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?, +//! }) +//! } +//! } +//! +//! impl HrTimerCallback for BoxIntrusiveHrTimer { +//! type Pointer<'a> = Pin>; +//! +//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart { +//! pr_info!("Timer called\n"); +//! +//! let flag = this.shared.flag.fetch_add(1, ordering::Full); +//! this.shared.cond.complete_all(); +//! +//! if flag == 4 { +//! HrTimerRestart::NoRestart +//! } else { +//! HrTimerRestart::Restart +//! } +//! } +//! } +//! +//! impl_has_hr_timer! { +//! impl HasHrTimer for BoxIntrusiveHrTimer { +//! mode: RelativeMode, field: self.timer +//! } +//! } +//! +//! let has_timer = Box::pin_init(BoxIntrusiveHrTimer::new(), GFP_KERNEL)?; +//! let shared = has_timer.shared.clone(); +//! let _handle = has_timer.start(Delta::from_micros(200)); +//! +//! while shared.flag.load(ordering::Relaxed) != 5 { +//! shared.cond.wait_for_completion(); +//! } +//! +//! pr_info!("Counted to 5\n"); +//! # Ok::<(), kernel::error::Error>(()) +//! ``` +//! +//! ## Using an intrusive timer in an [`Arc`] +//! +//! ``` +//! # use kernel::{ +//! # alloc::flags, +//! # impl_has_hr_timer, +//! # prelude::*, +//! # sync::{ +//! # atomic::{ordering, Atomic}, +//! # completion::Completion, +//! # Arc, ArcBorrow, +//! # }, +//! # time::{ +//! # hrtimer::{ +//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart, +//! # HasHrTimer, HrTimerCallbackContext +//! # }, +//! # Delta, Monotonic, +//! # }, +//! # }; +//! +//! #[pin_data] +//! struct ArcIntrusiveHrTimer { +//! #[pin] +//! timer: HrTimer, +//! #[pin] +//! flag: Atomic, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl ArcIntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! timer <- HrTimer::new(), +//! flag <- Atomic::new(0), +//! cond <- Completion::new(), +//! }) +//! } +//! } +//! +//! impl HrTimerCallback for ArcIntrusiveHrTimer { +//! type Pointer<'a> = Arc; +//! +//! fn run( +//! this: ArcBorrow<'_, Self>, +//! _ctx: HrTimerCallbackContext<'_, Self>, +//! ) -> HrTimerRestart { +//! pr_info!("Timer called\n"); +//! +//! let flag = this.flag.fetch_add(1, ordering::Full); +//! this.cond.complete_all(); +//! +//! if flag == 4 { +//! HrTimerRestart::NoRestart +//! } else { +//! HrTimerRestart::Restart +//! } +//! } +//! } +//! +//! impl_has_hr_timer! { +//! impl HasHrTimer for ArcIntrusiveHrTimer { +//! mode: RelativeMode, field: self.timer +//! } +//! } +//! +//! let has_timer = Arc::pin_init(ArcIntrusiveHrTimer::new(), GFP_KERNEL)?; +//! let _handle = has_timer.clone().start(Delta::from_micros(200)); +//! +//! while has_timer.flag.load(ordering::Relaxed) != 5 { +//! has_timer.cond.wait_for_completion(); +//! } +//! +//! pr_info!("Counted to 5\n"); +//! # Ok::<(), kernel::error::Error>(()) +//! ``` +//! +//! ## Using a stack-based timer +//! +//! ``` +//! # use kernel::{ +//! # impl_has_hr_timer, +//! # prelude::*, +//! # sync::{ +//! # atomic::{ordering, Atomic}, +//! # completion::Completion, +//! # }, +//! # time::{ +//! # hrtimer::{ +//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart, +//! # HasHrTimer, RelativeMode, HrTimerCallbackContext +//! # }, +//! # Delta, Monotonic, +//! # }, +//! # }; +//! # use pin_init::stack_pin_init; +//! +//! #[pin_data] +//! struct IntrusiveHrTimer { +//! #[pin] +//! timer: HrTimer, +//! #[pin] +//! flag: Atomic, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl IntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! timer <- HrTimer::new(), +//! flag <- Atomic::new(0), +//! cond <- Completion::new(), +//! }) +//! } +//! } +//! +//! impl HrTimerCallback for IntrusiveHrTimer { +//! type Pointer<'a> = Pin<&'a Self>; +//! +//! fn run(this: Pin<&Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart { +//! pr_info!("Timer called\n"); +//! +//! this.flag.store(1, ordering::Release); +//! this.cond.complete_all(); +//! +//! HrTimerRestart::NoRestart +//! } +//! } +//! +//! impl_has_hr_timer! { +//! impl HasHrTimer for IntrusiveHrTimer { +//! mode: RelativeMode, field: self.timer +//! } +//! } +//! +//! stack_pin_init!( let has_timer = IntrusiveHrTimer::new() ); +//! has_timer.as_ref().start_scoped(Delta::from_micros(200), || { +//! while has_timer.flag.load(ordering::Relaxed) != 1 { +//! has_timer.cond.wait_for_completion(); +//! } +//! }); +//! +//! pr_info!("Flag raised\n"); +//! # Ok::<(), kernel::error::Error>(()) +//! ``` +//! +//! ## Using a mutable stack-based timer +//! +//! ``` +//! # use kernel::{ +//! # alloc::flags, +//! # impl_has_hr_timer, +//! # prelude::*, +//! # sync::{ +//! # atomic::{ordering, Atomic}, +//! # completion::Completion, +//! # Arc, +//! # }, +//! # time::{ +//! # hrtimer::{ +//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart, +//! # HasHrTimer, RelativeMode, HrTimerCallbackContext +//! # }, +//! # Delta, Monotonic, +//! # }, +//! # }; +//! # use pin_init::stack_try_pin_init; +//! +//! #[pin_data] +//! struct Shared { +//! #[pin] +//! flag: Atomic, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl Shared { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! flag <- Atomic::new(0), +//! cond <- Completion::new(), +//! }) +//! } +//! } +//! +//! #[pin_data] +//! struct IntrusiveHrTimer { +//! #[pin] +//! timer: HrTimer, +//! shared: Arc, +//! } +//! +//! impl IntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! try_pin_init!(Self { +//! timer <- HrTimer::new(), +//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?, +//! }) +//! } +//! } +//! +//! impl HrTimerCallback for IntrusiveHrTimer { +//! type Pointer<'a> = Pin<&'a mut Self>; +//! +//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart { +//! pr_info!("Timer called\n"); +//! +//! let flag = this.shared.flag.fetch_add(1, ordering::Full); +//! this.shared.cond.complete_all(); +//! +//! if flag == 4 { +//! HrTimerRestart::NoRestart +//! } else { +//! HrTimerRestart::Restart +//! } +//! } +//! } +//! +//! impl_has_hr_timer! { +//! impl HasHrTimer for IntrusiveHrTimer { +//! mode: RelativeMode, field: self.timer +//! } +//! } +//! +//! stack_try_pin_init!( let has_timer =? IntrusiveHrTimer::new() ); +//! let shared = has_timer.shared.clone(); +//! +//! has_timer.as_mut().start_scoped(Delta::from_micros(200), || { +//! while shared.flag.load(ordering::Relaxed) != 5 { +//! shared.cond.wait_for_completion(); +//! } +//! }); +//! +//! pr_info!("Counted to 5\n"); +//! # Ok::<(), kernel::error::Error>(()) +//! ``` +//! +//! [`Arc`]: kernel::sync::Arc use super::{ClockSource, Delta, Instant}; use crate::{prelude::*, types::Opaque}; -- cgit v1.2.3 From d58f0f146a6e3fe3c6fcf6db1e0d385414bc8713 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 12 Mar 2026 17:46:59 +0000 Subject: rust: list: hide macros from top-level kernel doc Due to Rust macro scoping rules, all macros defined in a crate using `#[macro_export]` end up in the top-level. For the list macros, we re-export them inside the list module, and expect users to use `kernel::list::macro_name!()`. Use `#[doc(hidden)]` on the macro definition, and use `#[doc(inline)]` on the re-export to make the macro appear to be defined at module-level inside documentation. The other exported types are already automatically `#[doc(inline)]` because they are defined in a non-public module, so there is no need to split the macro re-exports out. Signed-off-by: Gary Guo Link: https://patch.msgid.link/20260312174700.4016015-1-gary@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/list.rs | 22 +++++++++++++++++++--- rust/kernel/list/arc.rs | 1 + rust/kernel/list/arc_field.rs | 1 + rust/kernel/list/impl_list_item_mod.rs | 3 +++ 4 files changed, 24 insertions(+), 3 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs index 8349ff32fc37..406e3a028c55 100644 --- a/rust/kernel/list.rs +++ b/rust/kernel/list.rs @@ -12,15 +12,31 @@ use core::ptr; use pin_init::PinInit; mod impl_list_item_mod; +#[doc(inline)] pub use self::impl_list_item_mod::{ - impl_has_list_links, impl_has_list_links_self_ptr, impl_list_item, HasListLinks, HasSelfPtr, + impl_has_list_links, + impl_has_list_links_self_ptr, + impl_list_item, + HasListLinks, + HasSelfPtr, // }; mod arc; -pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc}; +#[doc(inline)] +pub use self::arc::{ + impl_list_arc_safe, + AtomicTracker, + ListArc, + ListArcSafe, + TryNewListArc, // +}; mod arc_field; -pub use self::arc_field::{define_list_arc_field_getter, ListArcField}; +#[doc(inline)] +pub use self::arc_field::{ + define_list_arc_field_getter, + ListArcField, // +}; /// A linked list. /// diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs index 2282f33913ee..e1082423909c 100644 --- a/rust/kernel/list/arc.rs +++ b/rust/kernel/list/arc.rs @@ -82,6 +82,7 @@ pub unsafe trait TryNewListArc: ListArcSafe { /// [`AtomicTracker`]. However, it is also possible to defer the tracking to another struct /// using also using this macro. #[macro_export] +#[doc(hidden)] macro_rules! impl_list_arc_safe { (impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => { impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t { diff --git a/rust/kernel/list/arc_field.rs b/rust/kernel/list/arc_field.rs index c4b9dd503982..2ad8aea55993 100644 --- a/rust/kernel/list/arc_field.rs +++ b/rust/kernel/list/arc_field.rs @@ -66,6 +66,7 @@ impl ListArcField { /// Defines getters for a [`ListArcField`]. #[macro_export] +#[doc(hidden)] macro_rules! define_list_arc_field_getter { ($pub:vis fn $name:ident(&self $(<$id:tt>)?) -> &$typ:ty { $field:ident } $($rest:tt)* diff --git a/rust/kernel/list/impl_list_item_mod.rs b/rust/kernel/list/impl_list_item_mod.rs index ee53d0387e63..5a3eac9f3cf0 100644 --- a/rust/kernel/list/impl_list_item_mod.rs +++ b/rust/kernel/list/impl_list_item_mod.rs @@ -29,6 +29,7 @@ pub unsafe trait HasListLinks { /// Implements the [`HasListLinks`] trait for the given type. #[macro_export] +#[doc(hidden)] macro_rules! impl_has_list_links { ($(impl$({$($generics:tt)*})? HasListLinks$(<$id:tt>)? @@ -74,6 +75,7 @@ where /// Implements the [`HasListLinks`] and [`HasSelfPtr`] traits for the given type. #[macro_export] +#[doc(hidden)] macro_rules! impl_has_list_links_self_ptr { ($(impl$({$($generics:tt)*})? HasSelfPtr<$item_type:ty $(, $id:tt)?> @@ -181,6 +183,7 @@ pub use impl_has_list_links_self_ptr; /// } /// ``` #[macro_export] +#[doc(hidden)] macro_rules! impl_list_item { ( $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty { -- cgit v1.2.3 From 4f13c93497e366cd8e41561a8e30ad4da887cb82 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 26 Mar 2026 12:04:06 +1000 Subject: rust: kernel: mark as `#[inline]` all `From::from()`s for `Error` There was a recent request [1] to mark as `#[inline]` the simple `From::from()` functions implemented for `Error`. Thus mark all of the existing impl From<...> for Error { fn from(err: ...) -> Self { ... } } functions in the `kernel` crate as `#[inline]`. Suggested-by: Gary Guo Link: https://lore.kernel.org/all/8403c8b7a832b5274743816eb77abfa4@garyguo.net/ [1] Signed-off-by: Alistair Francis Acked-by: Danilo Krummrich Acked-by: Andreas Hindborg Link: https://patch.msgid.link/20260326020406.1438210-1-alistair.francis@wdc.com [ Dropped `projection.rs` since it is in another tree and already marked as `inline(always)` and reworded accordingly. Changed Link tag to Gary's original message and added Suggested-by. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/kvec/errors.rs | 3 +++ rust/kernel/error.rs | 6 ++++++ rust/kernel/xarray.rs | 1 + 3 files changed, 10 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/alloc/kvec/errors.rs b/rust/kernel/alloc/kvec/errors.rs index e7de5049ee47..985c5f2c3962 100644 --- a/rust/kernel/alloc/kvec/errors.rs +++ b/rust/kernel/alloc/kvec/errors.rs @@ -15,6 +15,7 @@ impl fmt::Debug for PushError { } impl From> for Error { + #[inline] fn from(_: PushError) -> Error { // Returning ENOMEM isn't appropriate because the system is not out of memory. The vector // is just full and we are refusing to resize it. @@ -32,6 +33,7 @@ impl fmt::Debug for RemoveError { } impl From for Error { + #[inline] fn from(_: RemoveError) -> Error { EINVAL } @@ -55,6 +57,7 @@ impl fmt::Debug for InsertError { } impl From> for Error { + #[inline] fn from(_: InsertError) -> Error { EINVAL } diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 258b12afdcba..935787c2a91c 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -216,36 +216,42 @@ impl fmt::Debug for Error { } impl From for Error { + #[inline] fn from(_: AllocError) -> Error { code::ENOMEM } } impl From for Error { + #[inline] fn from(_: TryFromIntError) -> Error { code::EINVAL } } impl From for Error { + #[inline] fn from(_: Utf8Error) -> Error { code::EINVAL } } impl From for Error { + #[inline] fn from(_: LayoutError) -> Error { code::ENOMEM } } impl From for Error { + #[inline] fn from(_: fmt::Error) -> Error { code::EINVAL } } impl From for Error { + #[inline] fn from(e: core::convert::Infallible) -> Error { match e {} } diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index a49d6db28845..46e5f43223fe 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -172,6 +172,7 @@ pub struct StoreError { } impl From> for Error { + #[inline] fn from(value: StoreError) -> Self { value.error } -- cgit v1.2.3 From abfe5ee9971249b91020b5053afcaad43837336a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 19 Mar 2026 12:16:45 +0000 Subject: rust: move `static_assert` into `build_assert` Conceptually, `static_assert` is also a build-time assertion that occurs earlier in the pipeline. Consolidate the implementation so that we can use this as the canonical place to add more useful build-time assertions. Reviewed-by: Yury Norov Signed-off-by: Gary Guo Reviewed-by: Alice Ryhl Reviewed-by: Danilo Krummrich Link: https://patch.msgid.link/20260319121653.2975748-2-gary@kernel.org [ Used kernel vertical style. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/build_assert.rs | 40 +++++++++++++++++++++++++++++++++++++--- rust/kernel/lib.rs | 1 - rust/kernel/prelude.rs | 8 +++++--- rust/kernel/static_assert.rs | 39 --------------------------------------- 4 files changed, 42 insertions(+), 46 deletions(-) delete mode 100644 rust/kernel/static_assert.rs (limited to 'rust/kernel') diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs index f8124dbc663f..d464494d430a 100644 --- a/rust/kernel/build_assert.rs +++ b/rust/kernel/build_assert.rs @@ -1,10 +1,46 @@ // SPDX-License-Identifier: GPL-2.0 -//! Build-time assert. +//! Various assertions that happen during build-time. #[doc(hidden)] pub use build_error::build_error; +/// Static assert (i.e. compile-time assert). +/// +/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`]. +/// +/// An optional panic message can be supplied after the expression. +/// Currently only a string literal without formatting is supported +/// due to constness limitations of the [`assert!`] macro. +/// +/// The feature may be added to Rust in the future: see [RFC 2790]. +/// +/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert +/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert +/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790 +/// +/// # Examples +/// +/// ``` +/// static_assert!(42 > 24); +/// static_assert!(core::mem::size_of::() == 1); +/// +/// const X: &[u8] = b"bar"; +/// static_assert!(X[1] == b'a'); +/// +/// const fn f(x: i32) -> i32 { +/// x + 2 +/// } +/// static_assert!(f(40) == 42); +/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input."); +/// ``` +#[macro_export] +macro_rules! static_assert { + ($condition:expr $(,$arg:literal)?) => { + const _: () = ::core::assert!($condition $(,$arg)?); + }; +} + /// Fails the build if the code path calling `build_error!` can possibly be executed. /// /// If the macro is executed in const context, `build_error!` will panic. @@ -74,8 +110,6 @@ macro_rules! build_error { /// assert!(n > 1); // Run-time check /// } /// ``` -/// -/// [`static_assert!`]: crate::static_assert! #[macro_export] macro_rules! build_assert { ($cond:expr $(,)?) => {{ diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3da92f18f4ee..410703c4e07c 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -144,7 +144,6 @@ pub mod sizes; pub mod slice; #[cfg(CONFIG_SOC_BUS)] pub mod soc; -mod static_assert; #[doc(hidden)] pub mod std_vendor; pub mod str; diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 2877e3f7b6d3..2e9454472818 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -29,7 +29,11 @@ pub use macros::{export, fmt, kunit_tests, module, vtable}; pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable}; -pub use super::{build_assert, build_error}; +pub use super::{ + build_assert, + build_error, + static_assert, // +}; // `super::std_vendor` is hidden, which makes the macro inline for some reason. #[doc(no_inline)] @@ -39,8 +43,6 @@ pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notic pub use super::{try_init, try_pin_init}; -pub use super::static_assert; - pub use super::error::{code::*, Error, Result}; pub use super::{str::CStrExt as _, ThisModule}; diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs deleted file mode 100644 index a57ba14315a0..000000000000 --- a/rust/kernel/static_assert.rs +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Static assert. - -/// Static assert (i.e. compile-time assert). -/// -/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`]. -/// -/// An optional panic message can be supplied after the expression. -/// Currently only a string literal without formatting is supported -/// due to constness limitations of the [`assert!`] macro. -/// -/// The feature may be added to Rust in the future: see [RFC 2790]. -/// -/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert -/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert -/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790 -/// -/// # Examples -/// -/// ``` -/// static_assert!(42 > 24); -/// static_assert!(core::mem::size_of::() == 1); -/// -/// const X: &[u8] = b"bar"; -/// static_assert!(X[1] == b'a'); -/// -/// const fn f(x: i32) -> i32 { -/// x + 2 -/// } -/// static_assert!(f(40) == 42); -/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input."); -/// ``` -#[macro_export] -macro_rules! static_assert { - ($condition:expr $(,$arg:literal)?) => { - const _: () = ::core::assert!($condition $(,$arg)?); - }; -} -- cgit v1.2.3 From 560a7a9b9267fbe31a68270ca0ad22b6a4db44a5 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 19 Mar 2026 12:16:46 +0000 Subject: rust: add `const_assert!` macro The macro is a more powerful version of `static_assert!` for use inside function contexts. This is powered by inline consts, so enable the feature for old compiler versions that does not have it stably. While it is possible already to write `const { assert!(...) }`, this provides a short hand that is more uniform with other assertions. It also formats nicer with rustfmt where it will not be formatted into multiple lines. Two users that would route via the Rust tree are converted. Reviewed-by: Yury Norov Signed-off-by: Gary Guo Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Reviewed-by: Danilo Krummrich Link: https://patch.msgid.link/20260319121653.2975748-3-gary@kernel.org [ Rebased. Fixed period typo. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/build_assert.rs | 24 ++++++++++++++++++++++++ rust/kernel/num/bounded.rs | 24 +++++++++--------------- rust/kernel/prelude.rs | 1 + rust/kernel/ptr.rs | 12 ++++++------ 4 files changed, 40 insertions(+), 21 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs index d464494d430a..50b0fc0a80fc 100644 --- a/rust/kernel/build_assert.rs +++ b/rust/kernel/build_assert.rs @@ -41,6 +41,30 @@ macro_rules! static_assert { }; } +/// Assertion during constant evaluation. +/// +/// This is a more powerful version of [`static_assert!`] that can refer to generics inside +/// functions or implementation blocks. However, it also has a limitation where it can only appear +/// in places where statements can appear; for example, you cannot use it as an item in the module. +/// +/// # Examples +/// +/// ``` +/// fn foo() { +/// const_assert!(N > 1); +/// } +/// +/// fn bar() { +/// const_assert!(size_of::() > 0, "T cannot be ZST"); +/// } +/// ``` +#[macro_export] +macro_rules! const_assert { + ($condition:expr $(,$arg:literal)?) => { + const { ::core::assert!($condition $(,$arg)?) }; + }; +} + /// Fails the build if the code path calling `build_error!` can possibly be executed. /// /// If the macro is executed in const context, `build_error!` will panic. diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index fa81acbdc8c2..54d0ce3ba595 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -255,9 +255,7 @@ macro_rules! impl_const_new { /// ``` pub const fn new() -> Self { // Statically assert that `VALUE` fits within the set number of bits. - const { - assert!(fits_within!(VALUE, $type, N)); - } + const_assert!(fits_within!(VALUE, $type, N)); // SAFETY: `fits_within` confirmed that `VALUE` can be represented within // `N` bits. @@ -287,12 +285,10 @@ where /// The caller must ensure that `value` can be represented within `N` bits. const unsafe 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); - } + // `N` cannot be zero. + const_assert!(N != 0); + // The backing type is at least as large as `N` bits. + const_assert!(N <= T::BITS); // INVARIANT: The caller ensures `value` fits within `N` bits. Self(value) @@ -406,12 +402,10 @@ where /// 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." - ); - } + const_assert!( + M >= N, + "Requested number of bits is less than the current representation." + ); // SAFETY: The value did fit within `N` bits, so it will all the more fit within // the larger `M` bits. diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 2e9454472818..6a54597fa0a2 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -32,6 +32,7 @@ pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, Pi pub use super::{ build_assert, build_error, + const_assert, static_assert, // }; diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs index 5b6a382637fe..512e2eabe3ad 100644 --- a/rust/kernel/ptr.rs +++ b/rust/kernel/ptr.rs @@ -5,6 +5,8 @@ use core::mem::align_of; use core::num::NonZero; +use crate::const_assert; + /// Type representing an alignment, which is always a power of two. /// /// It is used to validate that a given value is a valid alignment, and to perform masking and @@ -38,12 +40,10 @@ impl Alignment { /// ``` #[inline(always)] pub const fn new() -> Self { - const { - assert!( - ALIGN.is_power_of_two(), - "Provided alignment is not a power of two." - ); - } + const_assert!( + ALIGN.is_power_of_two(), + "Provided alignment is not a power of two." + ); // INVARIANT: `align` is a power of two. // SAFETY: `align` is a power of two, and thus non-zero. -- cgit v1.2.3 From 889c8c934d175f55a3415abe5472c88a5612e89d Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 19 Mar 2026 12:16:47 +0000 Subject: rust: rework `build_assert!` documentation Add a detailed comparison and recommendation of the three types of build-time assertion macro as module documentation (and un-hide the module to render them). The documentation on the macro themselves are simplified to only cover the scenarios where they should be used; links to the module documentation is added instead. Reviewed-by: Yury Norov Signed-off-by: Gary Guo Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Reviewed-by: Danilo Krummrich Link: https://patch.msgid.link/20260319121653.2975748-4-gary@kernel.org [ Added periods on comments. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/build_assert.rs | 119 ++++++++++++++++++++++++++++++++++---------- rust/kernel/lib.rs | 1 - 2 files changed, 92 insertions(+), 28 deletions(-) (limited to 'rust/kernel') diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs index 50b0fc0a80fc..2ea2154ec30c 100644 --- a/rust/kernel/build_assert.rs +++ b/rust/kernel/build_assert.rs @@ -1,6 +1,72 @@ // SPDX-License-Identifier: GPL-2.0 //! Various assertions that happen during build-time. +//! +//! There are three types of build-time assertions that you can use: +//! - [`static_assert!`] +//! - [`const_assert!`] +//! - [`build_assert!`] +//! +//! The ones towards the bottom of the list are more expressive, while the ones towards the top of +//! the list are more robust and trigger earlier in the compilation pipeline. Therefore, you should +//! prefer the ones towards the top of the list wherever possible. +//! +//! # Choosing the correct assertion +//! +//! If you're asserting outside any bodies (e.g. initializers or function bodies), you should use +//! [`static_assert!`] as it is the only assertion that can be used in that context. +//! +//! Inside bodies, if your assertion condition does not depend on any variable or generics, you +//! should use [`static_assert!`]. If the condition depends on generics, but not variables +//! (including function arguments), you should use [`const_assert!`]. Otherwise, use +//! [`build_assert!`]. The same is true regardless if the function is `const fn`. +//! +//! ``` +//! // Outside any bodies. +//! static_assert!(core::mem::size_of::() == 1); +//! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile. +//! +//! #[inline(always)] +//! fn foo(v: usize) { +//! static_assert!(core::mem::size_of::() == 1); // Preferred. +//! const_assert!(core::mem::size_of::() == 1); // Discouraged. +//! build_assert!(core::mem::size_of::() == 1); // Discouraged. +//! +//! // `static_assert!(N > 1);` is not allowed. +//! const_assert!(N > 1); // Preferred. +//! build_assert!(N > 1); // Discouraged. +//! +//! // `static_assert!(v > 1);` is not allowed. +//! // `const_assert!(v > 1);` is not allowed. +//! build_assert!(v > 1); // Works. +//! } +//! ``` +//! +//! # Detailed behavior +//! +//! `static_assert!()` is equivalent to `static_assert` in C. It requires `expr` to be a constant +//! expression. This expression cannot refer to any generics. A `static_assert!(expr)` in a program +//! is always evaluated, regardless if the function it appears in is used or not. This is also the +//! only usable assertion outside a body. +//! +//! `const_assert!()` has no direct C equivalence. It is a more powerful version of +//! `static_assert!()`, where it may refer to generics in a function. Note that due to the ability +//! to refer to generics, the assertion is tied to a specific instance of a function. So if it is +//! used in a generic function that is not instantiated, the assertion will not be checked. For this +//! reason, `static_assert!()` is preferred wherever possible. +//! +//! `build_assert!()` is equivalent to `BUILD_BUG_ON`. It is even more powerful than +//! `const_assert!()` because it can be used to check tautologies that depend on runtime value (this +//! is the same as `BUILD_BUG_ON`). However, the assertion failure mechanism can possibly be +//! undefined symbols and linker errors, it is not developer friendly to debug, so it is recommended +//! to avoid it and prefer other two assertions where possible. + +pub use crate::{ + build_assert, + build_error, + const_assert, + static_assert, // +}; #[doc(hidden)] pub use build_error::build_error; @@ -15,6 +81,10 @@ pub use build_error::build_error; /// /// The feature may be added to Rust in the future: see [RFC 2790]. /// +/// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to +/// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See +/// the [module documentation](self). +/// /// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert /// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert /// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790 @@ -47,6 +117,10 @@ macro_rules! static_assert { /// functions or implementation blocks. However, it also has a limitation where it can only appear /// in places where statements can appear; for example, you cannot use it as an item in the module. /// +/// [`static_assert!`] should be preferred if no generics are referred to in the condition. You +/// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the +/// capability, use [`build_assert!`]. See the [module documentation](self). +/// /// # Examples /// /// ``` @@ -98,41 +172,32 @@ macro_rules! build_error { /// will panic. If the compiler or optimizer cannot guarantee the condition will /// be evaluated to `true`, a build error will be triggered. /// -/// [`static_assert!`] should be preferred to `build_assert!` whenever possible. +/// When a condition depends on a function argument, the function must be annotated with +/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the +/// function, preventing it from optimizing out the error path. +/// +/// If the assertion condition does not depend on any variables or generics, you should use +/// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on +/// generics, you should use [`const_assert!`]. See the [module documentation](self). /// /// # Examples /// -/// These examples show that different types of [`assert!`] will trigger errors -/// at different stage of compilation. It is preferred to err as early as -/// possible, so [`static_assert!`] should be used whenever possible. -/// ```ignore -/// fn foo() { -/// static_assert!(1 > 1); // Compile-time error -/// build_assert!(1 > 1); // Build-time error -/// assert!(1 > 1); // Run-time error -/// } /// ``` +/// #[inline(always)] // Important. +/// fn bar(n: usize) { +/// build_assert!(n > 1); +/// } /// -/// When the condition refers to generic parameters or parameters of an inline function, -/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario. -/// ``` -/// fn foo() { -/// // `static_assert!(N > 1);` is not allowed -/// build_assert!(N > 1); // Build-time check -/// assert!(N > 1); // Run-time check +/// fn foo() { +/// bar(2); /// } -/// ``` /// -/// When a condition depends on a function argument, the function must be annotated with -/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the -/// function, preventing it from optimizing out the error path. -/// ``` -/// #[inline(always)] -/// fn bar(n: usize) { -/// // `static_assert!(n > 1);` is not allowed -/// build_assert!(n > 1); // Build-time check -/// assert!(n > 1); // Run-time check +/// #[inline(always)] // Important. +/// const fn const_bar(n: usize) { +/// build_assert!(n > 1); /// } +/// +/// const _: () = const_bar(2); /// ``` #[macro_export] macro_rules! build_assert { diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 410703c4e07c..138d846f798d 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -73,7 +73,6 @@ pub mod bits; #[cfg(CONFIG_BLOCK)] pub mod block; pub mod bug; -#[doc(hidden)] pub mod build_assert; pub mod clk; #[cfg(CONFIG_CONFIGFS_FS)] -- cgit v1.2.3 From 7ccef29b5d93d6e235dc8ace27cfbbfbbede9908 Mon Sep 17 00:00:00 2001 From: Mirko Adzic Date: Sun, 29 Mar 2026 12:41:10 +0200 Subject: rust: error: clarify that `from_err_ptr` can return `Ok(NULL)` Improve the doc comment of `from_err_ptr` by explicitly stating that it will return `Ok(NULL)` when passed a null pointer, as it isn't an error value. Add a doctest case that tests the behavior described above, as well as other scenarios (non-null/non-error pointer, error value). Suggested-by: Miguel Ojeda Link: https://lore.kernel.org/rust-for-linux/20260322193830.89324-1-ojeda@kernel.org/ Link: https://github.com/Rust-for-Linux/linux/issues/1231 Signed-off-by: Mirko Adzic Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20260329104319.131057-1-adzicmirko97@gmail.com [ - Added `expect` for `clippy::missing_safety_doc`. - Simplified and removed unsafe block using `Error::to_ptr()`. - Added intra-doc link. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/error.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 935787c2a91c..decceb6ae855 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -452,6 +452,9 @@ pub fn to_result(err: crate::ffi::c_int) -> Result { /// for errors. This function performs the check and converts the "error pointer" /// to a normal pointer in an idiomatic fashion. /// +/// Note that a `NULL` pointer is not considered an error pointer, and is returned +/// as-is, wrapped in [`Ok`]. +/// /// # Examples /// /// ```ignore @@ -466,6 +469,34 @@ pub fn to_result(err: crate::ffi::c_int) -> Result { /// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) }) /// } /// ``` +/// +/// ``` +/// # use kernel::error::from_err_ptr; +/// # mod bindings { +/// # #![expect(clippy::missing_safety_doc)] +/// # use kernel::prelude::*; +/// # pub(super) unsafe fn einval_err_ptr() -> *mut kernel::ffi::c_void { +/// # EINVAL.to_ptr() +/// # } +/// # pub(super) unsafe fn null_ptr() -> *mut kernel::ffi::c_void { +/// # core::ptr::null_mut() +/// # } +/// # pub(super) unsafe fn non_null_ptr() -> *mut kernel::ffi::c_void { +/// # 0x1234 as *mut kernel::ffi::c_void +/// # } +/// # } +/// // SAFETY: ... +/// let einval_err = from_err_ptr(unsafe { bindings::einval_err_ptr() }); +/// assert_eq!(einval_err, Err(EINVAL)); +/// +/// // SAFETY: ... +/// let null_ok = from_err_ptr(unsafe { bindings::null_ptr() }); +/// assert_eq!(null_ok, Ok(core::ptr::null_mut())); +/// +/// // SAFETY: ... +/// let non_null = from_err_ptr(unsafe { bindings::non_null_ptr() }).unwrap(); +/// assert_ne!(non_null, core::ptr::null_mut()); +/// ``` pub fn from_err_ptr(ptr: *mut T) -> Result<*mut T> { // CAST: Casting a pointer to `*const crate::ffi::c_void` is always valid. let const_ptr: *const crate::ffi::c_void = ptr.cast(); -- cgit v1.2.3 From 0a51b384e0decfe9dfe65d721a5e9cd39cabc152 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Wed, 25 Mar 2026 18:38:47 -0700 Subject: rust: ptr: add const_align_up() Add const_align_up() to kernel::ptr as the const-compatible equivalent of Alignable::align_up(). Suggested-by: Danilo Krummrich Suggested-by: Gary Guo Suggested-by: Miguel Ojeda Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: John Hubbard Reviewed-by: Alexandre Courbot Link: https://patch.msgid.link/20260326013902.588242-17-jhubbard@nvidia.com [ Adjusted imports style. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/ptr.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs index 512e2eabe3ad..c7788656a162 100644 --- a/rust/kernel/ptr.rs +++ b/rust/kernel/ptr.rs @@ -225,3 +225,32 @@ macro_rules! impl_alignable_uint { } impl_alignable_uint!(u8, u16, u32, u64, usize); + +/// Aligns `value` up to `align`. +/// +/// This is the const-compatible equivalent of [`Alignable::align_up`]. +/// +/// Returns [`None`] on overflow. +/// +/// # Examples +/// +/// ``` +/// use kernel::{ +/// ptr::{ +/// const_align_up, +/// Alignment, // +/// }, +/// sizes::SZ_4K, // +/// }; +/// +/// assert_eq!(const_align_up(0x4f, Alignment::new::<16>()), Some(0x50)); +/// assert_eq!(const_align_up(0x40, Alignment::new::<16>()), Some(0x40)); +/// assert_eq!(const_align_up(1, Alignment::new::()), Some(SZ_4K)); +/// ``` +#[inline(always)] +pub const fn const_align_up(value: usize, align: Alignment) -> Option { + match value.checked_add(align.as_usize() - 1) { + Some(v) => Some(v & align.mask()), + None => None, + } +} -- cgit v1.2.3 From 0c0695a9d8c97f63d71dc890faa6999eef728f57 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 23 Feb 2026 10:08:25 +0000 Subject: rust: clk: implement Send and Sync These traits are required for drivers to embed the Clk type in their own data structures because driver data structures are usually required to be Send. Since the Clk type is thread-safe, implement the relevant traits. Reviewed-by: Daniel Almeida Reviewed-by: Danilo Krummrich Acked-by: Viresh Kumar Reviewed-by: Boqun Feng Reviewed-by: Gary Guo Signed-off-by: Alice Ryhl Acked-by: Brian Masney # Active contributor to clk Link: https://patch.msgid.link/20260223-clk-send-sync-v5-1-181bf2f35652@google.com Signed-off-by: Miguel Ojeda --- rust/kernel/clk.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index 4059aff34d09..7abbd0767d8c 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -128,6 +128,13 @@ mod common_clk { #[repr(transparent)] pub struct Clk(*mut bindings::clk); + // SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called. + unsafe impl Send for Clk {} + + // SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the + // methods are synchronized internally. + unsafe impl Sync for Clk {} + impl Clk { /// Gets [`Clk`] corresponding to a [`Device`] and a connection id. /// -- cgit v1.2.3 From 36f5a2b09e650b82d7b2a106e3b93af48c2010d9 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 8 Feb 2026 23:46:58 +0100 Subject: rust: prelude: use the "kernel vertical" imports style Format the Rust prelude to use the "kernel vertical" imports style [1]. No functional changes intended. Link: https://docs.kernel.org/rust/coding-guidelines.html#imports [1] Link: https://patch.msgid.link/20260208224659.18406-2-ojeda@kernel.org