summaryrefslogtreecommitdiff
path: root/rust/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-10 11:53:01 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-10 11:53:01 -0800
commita9aabb3b839aba094ed80861054993785c61462c (patch)
tree4fde2eb2606fe9fc6aa8b598bafb63a3a71c36e4 /rust/kernel
parentf144367d012929326f15a399394a9a8be4f98acb (diff)
parentb8d687c7eeb52d0353ac27c4f71594a2e6aa365f (diff)
Merge tag 'rust-6.20-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Add '__rust_helper' annotation to the C helpers This is needed to inline these helpers into Rust code - Remove imports available via the prelude, treewide This was possible thanks to a new lint in Klint that Gary has implemented -- more Klint-related changes, including initial upstream support, are coming - Deduplicate pin-init flags 'kernel' crate: - Add support for calling a function exactly once with the new 'do_once_lite!' macro (and 'OnceLite' type) Based on this, add 'pr_*_once!' macros to print only once - Add 'impl_flags!' macro for defining common bitflags operations: impl_flags!( /// Represents multiple permissions. #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)] pub struct Permissions(u32); /// Represents a single permission. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Permission { /// Read permission. Read = 1 << 0, /// Write permission. Write = 1 << 1, /// Execute permission. Execute = 1 << 2, } ); let mut f: Permissions = Permission::Read | Permission::Write; assert!(f.contains(Permission::Read)); assert!(!f.contains(Permission::Execute)); f |= Permission::Execute; assert!(f.contains(Permission::Execute)); let f2: Permissions = Permission::Write | Permission::Execute; assert!((f ^ f2).contains(Permission::Read)); assert!(!(f ^ f2).contains(Permission::Write)); - 'bug' module: support 'CONFIG_DEBUG_BUGVERBOSE_DETAILED' in the 'warn_on!' macro in order to show the evaluated condition alongside the file path: ------------[ cut here ]------------ WARNING: [val == 1] linux/samples/rust/rust_minimal.rs:27 at ... Modules linked in: rust_minimal(+) - Add safety module with 'unsafe_precondition_assert!' macro, currently a wrapper for 'debug_assert!', intended to mark the validation of safety preconditions where possible: /// # Safety /// /// The caller must ensure that `index` is less than `N`. unsafe fn set_unchecked(&mut self, index: usize, value: T) { unsafe_precondition_assert!( index < N, "set_unchecked() requires index ({index}) < N ({N})" ); ... } - Add instructions to 'build_assert!' documentation requesting to always inline functions when used with function arguments - 'ptr' module: replace 'build_assert!' with a 'const' one - 'rbtree' module: reduce unsafe blocks on pointer derefs - 'transmute' module: implement 'FromBytes' and 'AsBytes' for inhabited ZSTs, and use it in Nova - More treewide replacements of 'c_str!' with C string literals 'macros' crate: - Rewrite most procedural macros ('module!', 'concat_idents!', '#[export]', '#[vtable]', '#[kunit_tests]') to use the 'syn' parsing library which we introduced last cycle, with better diagnostics This also allows to support '#[cfg]' properly in the '#[vtable]' macro, to support arbitrary types in 'module!' macro (not just an identifier) and to remove several custom parsing helpers we had - Use 'quote!' from the recently vendored 'quote' library and remove our custom one The vendored one also allows us to avoid quoting '"' and '{}' inside the template anymore and editors can now highlight it. In addition, it improves robustness as it eliminates the need for string quoting and escaping - Use 'pin_init::zeroed()' to simplify KUnit code 'pin-init' crate: - Rewrite all procedural macros ('[pin_]init!', '#[pin_data]', '#[pinned_drop]', 'derive([Maybe]Zeroable)') to use the 'syn' parsing library which we introduced last cycle, with better diagnostics - Implement 'InPlaceWrite' for '&'static mut MaybeUninit<T>'. This enables users to use external allocation mechanisms such as 'static_cell' - Support tuple structs in 'derive([Maybe]Zeroable)' - Support attributes on fields in '[pin_]init!' (such as '#[cfg(...)]') - Add a '#[default_error(<type>)]' attribute to '[pin_]init!' to override the default error (when no '? Error' is specified) - Support packed structs in '[pin_]init!' with '#[disable_initialized_field_access]' - Remove 'try_[pin_]init!' in favor of merging their feature with '[pin_]init!'. Update the kernel's own 'try_[pin_]init!' macros to use the 'default_error' attribute - Correct 'T: Sized' bounds to 'T: ?Sized' in the generated 'PinnedDrop' check by '#[pin_data]' Documentation: - Conclude the Rust experiment MAINTAINERS: - Add "RUST [RUST-ANALYZER]" entry for the rust-analyzer support. Tamir and Jesung will take care of it. They have both been active around it for a while. The new tree will flow through the Rust one - Add Gary as maintainer for "RUST [PIN-INIT]" - Update Boqun and Tamir emails to their kernel.org accounts And a few other cleanups and improvements" * tag 'rust-6.20-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (59 commits) rust: safety: introduce `unsafe_precondition_assert!` macro rust: add `impl_flags!` macro for defining common bitflag operations rust: print: Add pr_*_once macros rust: bug: Support DEBUG_BUGVERBOSE_DETAILED option rust: print: Add support for calling a function exactly once rust: kbuild: deduplicate pin-init flags gpu: nova-core: remove imports available via prelude rust: clk: replace `kernel::c_str!` with C-Strings MAINTAINERS: Update my email address to @kernel.org rust: macros: support `#[cfg]` properly in `#[vtable]` macro. rust: kunit: use `pin_init::zeroed` instead of custom null value rust: macros: rearrange `#[doc(hidden)]` in `module!` macro rust: macros: allow arbitrary types to be used in `module!` macro rust: macros: convert `#[kunit_tests]` macro to use `syn` rust: macros: convert `concat_idents!` to use `syn` rust: macros: convert `#[export]` to use `syn` rust: macros: use `quote!` for `module!` macro rust: macros: use `syn` to parse `module!` macro rust: macros: convert `#[vtable]` macro to use `syn` rust: macros: use `quote!` from vendored crate ...
Diffstat (limited to 'rust/kernel')
-rw-r--r--rust/kernel/bug.rs20
-rw-r--r--rust/kernel/build_assert.rs7
-rw-r--r--rust/kernel/clk.rs8
-rw-r--r--rust/kernel/debugfs/entry.rs2
-rw-r--r--rust/kernel/i2c.rs8
-rw-r--r--rust/kernel/impl_flags.rs272
-rw-r--r--rust/kernel/init.rs40
-rw-r--r--rust/kernel/kunit.rs39
-rw-r--r--rust/kernel/lib.rs3
-rw-r--r--rust/kernel/print.rs153
-rw-r--r--rust/kernel/ptr.rs12
-rw-r--r--rust/kernel/rbtree.rs27
-rw-r--r--rust/kernel/safety.rs53
-rw-r--r--rust/kernel/transmute.rs8
14 files changed, 555 insertions, 97 deletions
diff --git a/rust/kernel/bug.rs b/rust/kernel/bug.rs
index 36aef43e5ebe..ed943960f851 100644
--- a/rust/kernel/bug.rs
+++ b/rust/kernel/bug.rs
@@ -11,9 +11,9 @@
#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
#[cfg(CONFIG_DEBUG_BUGVERBOSE)]
macro_rules! warn_flags {
- ($flags:expr) => {
+ ($file:expr, $flags:expr) => {
const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
- const _FILE: &[u8] = file!().as_bytes();
+ const _FILE: &[u8] = $file.as_bytes();
// Plus one for null-terminator.
static FILE: [u8; _FILE.len() + 1] = {
let mut bytes = [0; _FILE.len() + 1];
@@ -50,7 +50,7 @@ macro_rules! warn_flags {
#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
#[cfg(not(CONFIG_DEBUG_BUGVERBOSE))]
macro_rules! warn_flags {
- ($flags:expr) => {
+ ($file:expr, $flags:expr) => {
const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
// SAFETY:
@@ -75,7 +75,7 @@ macro_rules! warn_flags {
#[doc(hidden)]
#[cfg(all(CONFIG_BUG, CONFIG_UML))]
macro_rules! warn_flags {
- ($flags:expr) => {
+ ($file:expr, $flags:expr) => {
// SAFETY: It is always safe to call `warn_slowpath_fmt()`
// with a valid null-terminated string.
unsafe {
@@ -93,7 +93,7 @@ macro_rules! warn_flags {
#[doc(hidden)]
#[cfg(all(CONFIG_BUG, any(CONFIG_LOONGARCH, CONFIG_ARM)))]
macro_rules! warn_flags {
- ($flags:expr) => {
+ ($file:expr, $flags:expr) => {
// SAFETY: It is always safe to call `WARN_ON()`.
unsafe { $crate::bindings::WARN_ON(true) }
};
@@ -103,7 +103,7 @@ macro_rules! warn_flags {
#[doc(hidden)]
#[cfg(not(CONFIG_BUG))]
macro_rules! warn_flags {
- ($flags:expr) => {};
+ ($file:expr, $flags:expr) => {};
}
#[doc(hidden)]
@@ -116,10 +116,16 @@ pub const fn bugflag_taint(value: u32) -> u32 {
macro_rules! warn_on {
($cond:expr) => {{
let cond = $cond;
+
+ #[cfg(CONFIG_DEBUG_BUGVERBOSE_DETAILED)]
+ const _COND_STR: &str = concat!("[", stringify!($cond), "] ", file!());
+ #[cfg(not(CONFIG_DEBUG_BUGVERBOSE_DETAILED))]
+ const _COND_STR: &str = file!();
+
if cond {
const WARN_ON_FLAGS: u32 = $crate::bug::bugflag_taint($crate::bindings::TAINT_WARN);
- $crate::warn_flags!(WARN_ON_FLAGS);
+ $crate::warn_flags!(_COND_STR, WARN_ON_FLAGS);
}
cond
}};
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
index 6331b15d7c4d..f8124dbc663f 100644
--- a/rust/kernel/build_assert.rs
+++ b/rust/kernel/build_assert.rs
@@ -61,8 +61,13 @@ macro_rules! build_error {
/// build_assert!(N > 1); // Build-time check
/// assert!(N > 1); // Run-time check
/// }
+/// ```
///
-/// #[inline]
+/// 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
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index c1cfaeaa36a2..4059aff34d09 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -94,7 +94,7 @@ mod common_clk {
/// # Invariants
///
/// A [`Clk`] instance holds either a pointer to a valid [`struct clk`] created by the C
- /// portion of the kernel or a NULL pointer.
+ /// portion of the kernel or a `NULL` pointer.
///
/// Instances of this type are reference-counted. Calling [`Clk::get`] ensures that the
/// allocation remains valid for the lifetime of the [`Clk`].
@@ -104,13 +104,12 @@ mod common_clk {
/// The following example demonstrates how to obtain and configure a clock for a device.
///
/// ```
- /// use kernel::c_str;
/// use kernel::clk::{Clk, Hertz};
/// use kernel::device::Device;
/// use kernel::error::Result;
///
/// fn configure_clk(dev: &Device) -> Result {
- /// let clk = Clk::get(dev, Some(c_str!("apb_clk")))?;
+ /// let clk = Clk::get(dev, Some(c"apb_clk"))?;
///
/// clk.prepare_enable()?;
///
@@ -272,13 +271,12 @@ mod common_clk {
/// device. The code functions correctly whether or not the clock is available.
///
/// ```
- /// use kernel::c_str;
/// use kernel::clk::{OptionalClk, Hertz};
/// use kernel::device::Device;
/// use kernel::error::Result;
///
/// fn configure_clk(dev: &Device) -> Result {
- /// let clk = OptionalClk::get(dev, Some(c_str!("apb_clk")))?;
+ /// let clk = OptionalClk::get(dev, Some(c"apb_clk"))?;
///
/// clk.prepare_enable()?;
///
diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs
index 706cb7f73d6c..a30bf8f29679 100644
--- a/rust/kernel/debugfs/entry.rs
+++ b/rust/kernel/debugfs/entry.rs
@@ -148,7 +148,7 @@ impl Entry<'_> {
/// # Guarantees
///
/// Due to the type invariant, the value returned from this function will always be an error
- /// code, NULL, or a live DebugFS directory. If it is live, it will remain live at least as
+ /// code, `NULL`, or a live DebugFS directory. If it is live, it will remain live at least as
/// long as this entry lives.
pub(crate) fn as_ptr(&self) -> *mut bindings::dentry {
self.entry
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 39b0a9a207fd..bb5b830f48c3 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -262,7 +262,7 @@ macro_rules! module_i2c_driver {
/// # Example
///
///```
-/// # use kernel::{acpi, bindings, c_str, device::Core, i2c, of};
+/// # use kernel::{acpi, bindings, device::Core, i2c, of};
///
/// struct MyDriver;
///
@@ -271,7 +271,7 @@ macro_rules! module_i2c_driver {
/// MODULE_ACPI_TABLE,
/// <MyDriver as i2c::Driver>::IdInfo,
/// [
-/// (acpi::DeviceId::new(c_str!("LNUXBEEF")), ())
+/// (acpi::DeviceId::new(c"LNUXBEEF"), ())
/// ]
/// );
///
@@ -280,7 +280,7 @@ macro_rules! module_i2c_driver {
/// MODULE_I2C_TABLE,
/// <MyDriver as i2c::Driver>::IdInfo,
/// [
-/// (i2c::DeviceId::new(c_str!("rust_driver_i2c")), ())
+/// (i2c::DeviceId::new(c"rust_driver_i2c"), ())
/// ]
/// );
///
@@ -289,7 +289,7 @@ macro_rules! module_i2c_driver {
/// MODULE_OF_TABLE,
/// <MyDriver as i2c::Driver>::IdInfo,
/// [
-/// (of::DeviceId::new(c_str!("test,device")), ())
+/// (of::DeviceId::new(c"test,device"), ())
/// ]
/// );
///
diff --git a/rust/kernel/impl_flags.rs b/rust/kernel/impl_flags.rs
new file mode 100644
index 000000000000..e2bd7639da12
--- /dev/null
+++ b/rust/kernel/impl_flags.rs
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bitflag type generator.
+
+/// Common helper for declaring bitflag and bitmask types.
+///
+/// This macro takes as input:
+/// - A struct declaration representing a bitmask type
+/// (e.g., `pub struct Permissions(u32)`).
+/// - An enumeration declaration representing individual bit flags
+/// (e.g., `pub enum Permission { ... }`).
+///
+/// And generates:
+/// - The struct and enum types with appropriate `#[repr]` attributes.
+/// - Implementations of common bitflag operators
+/// ([`::core::ops::BitOr`], [`::core::ops::BitAnd`], etc.).
+/// - Utility methods such as `.contains()` to check flags.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::impl_flags;
+///
+/// impl_flags!(
+/// /// Represents multiple permissions.
+/// #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
+/// pub struct Permissions(u32);
+///
+/// /// Represents a single permission.
+/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+/// pub enum Permission {
+/// /// Read permission.
+/// Read = 1 << 0,
+///
+/// /// Write permission.
+/// Write = 1 << 1,
+///
+/// /// Execute permission.
+/// Execute = 1 << 2,
+/// }
+/// );
+///
+/// // Combine multiple permissions using the bitwise OR (`|`) operator.
+/// let mut read_write: Permissions = Permission::Read | Permission::Write;
+/// assert!(read_write.contains(Permission::Read));
+/// assert!(read_write.contains(Permission::Write));
+/// assert!(!read_write.contains(Permission::Execute));
+/// assert!(read_write.contains_any(Permission::Read | Permission::Execute));
+/// assert!(read_write.contains_all(Permission::Read | Permission::Write));
+///
+/// // Using the bitwise OR assignment (`|=`) operator.
+/// read_write |= Permission::Execute;
+/// assert!(read_write.contains(Permission::Execute));
+///
+/// // Masking a permission with the bitwise AND (`&`) operator.
+/// let read_only: Permissions = read_write & Permission::Read;
+/// assert!(read_only.contains(Permission::Read));
+/// assert!(!read_only.contains(Permission::Write));
+///
+/// // Toggling permissions with the bitwise XOR (`^`) operator.
+/// let toggled: Permissions = read_only ^ Permission::Read;
+/// assert!(!toggled.contains(Permission::Read));
+///
+/// // Inverting permissions with the bitwise NOT (`!`) operator.
+/// let negated = !read_only;
+/// assert!(negated.contains(Permission::Write));
+/// assert!(!negated.contains(Permission::Read));
+/// ```
+#[macro_export]
+macro_rules! impl_flags {
+ (
+ $(#[$outer_flags:meta])*
+ $vis_flags:vis struct $flags:ident($ty:ty);
+
+ $(#[$outer_flag:meta])*
+ $vis_flag:vis enum $flag:ident {
+ $(
+ $(#[$inner_flag:meta])*
+ $name:ident = $value:expr
+ ),+ $( , )?
+ }
+ ) => {
+ $(#[$outer_flags])*
+ #[repr(transparent)]
+ $vis_flags struct $flags($ty);
+
+ $(#[$outer_flag])*
+ #[repr($ty)]
+ $vis_flag enum $flag {
+ $(
+ $(#[$inner_flag])*
+ $name = $value
+ ),+
+ }
+
+ impl ::core::convert::From<$flag> for $flags {
+ #[inline]
+ fn from(value: $flag) -> Self {
+ Self(value as $ty)
+ }
+ }
+
+ impl ::core::convert::From<$flags> for $ty {
+ #[inline]
+ fn from(value: $flags) -> Self {
+ value.0
+ }
+ }
+
+ impl ::core::ops::BitOr for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ Self(self.0 | rhs.0)
+ }
+ }
+
+ impl ::core::ops::BitOrAssign for $flags {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = *self | rhs;
+ }
+ }
+
+ impl ::core::ops::BitOr<$flag> for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: $flag) -> Self::Output {
+ self | Self::from(rhs)
+ }
+ }
+
+ impl ::core::ops::BitOrAssign<$flag> for $flags {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: $flag) {
+ *self = *self | rhs;
+ }
+ }
+
+ impl ::core::ops::BitAnd for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ Self(self.0 & rhs.0)
+ }
+ }
+
+ impl ::core::ops::BitAndAssign for $flags {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = *self & rhs;
+ }
+ }
+
+ impl ::core::ops::BitAnd<$flag> for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitand(self, rhs: $flag) -> Self::Output {
+ self & Self::from(rhs)
+ }
+ }
+
+ impl ::core::ops::BitAndAssign<$flag> for $flags {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: $flag) {
+ *self = *self & rhs;
+ }
+ }
+
+ impl ::core::ops::BitXor for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ Self((self.0 ^ rhs.0) & Self::all_bits())
+ }
+ }
+
+ impl ::core::ops::BitXorAssign for $flags {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = *self ^ rhs;
+ }
+ }
+
+ impl ::core::ops::BitXor<$flag> for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitxor(self, rhs: $flag) -> Self::Output {
+ self ^ Self::from(rhs)
+ }
+ }
+
+ impl ::core::ops::BitXorAssign<$flag> for $flags {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: $flag) {
+ *self = *self ^ rhs;
+ }
+ }
+
+ impl ::core::ops::Not for $flags {
+ type Output = Self;
+ #[inline]
+ fn not(self) -> Self::Output {
+ Self((!self.0) & Self::all_bits())
+ }
+ }
+
+ impl ::core::ops::BitOr for $flag {
+ type Output = $flags;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ $flags(self as $ty | rhs as $ty)
+ }
+ }
+
+ impl ::core::ops::BitAnd for $flag {
+ type Output = $flags;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ $flags(self as $ty & rhs as $ty)
+ }
+ }
+
+ impl ::core::ops::BitXor for $flag {
+ type Output = $flags;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ $flags((self as $ty ^ rhs as $ty) & $flags::all_bits())
+ }
+ }
+
+ impl ::core::ops::Not for $flag {
+ type Output = $flags;
+ #[inline]
+ fn not(self) -> Self::Output {
+ $flags((!(self as $ty)) & $flags::all_bits())
+ }
+ }
+
+ impl $flags {
+ /// Returns an empty instance where no flags are set.
+ #[inline]
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ /// Returns a mask containing all valid flag bits.
+ #[inline]
+ pub const fn all_bits() -> $ty {
+ 0 $( | $value )+
+ }
+
+ /// Checks if a specific flag is set.
+ #[inline]
+ pub fn contains(self, flag: $flag) -> bool {
+ (self.0 & flag as $ty) == flag as $ty
+ }
+
+ /// Checks if at least one of the provided flags is set.
+ #[inline]
+ pub fn contains_any(self, flags: $flags) -> bool {
+ (self.0 & flags.0) != 0
+ }
+
+ /// Checks if all of the provided flags are set.
+ #[inline]
+ pub fn contains_all(self, flags: $flags) -> bool {
+ (self.0 & flags.0) == flags.0
+ }
+ }
+ };
+}
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 899b9a962762..7a0d4559d7b5 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -219,20 +219,12 @@ pub trait InPlaceInit<T>: Sized {
/// [`Error`]: crate::error::Error
#[macro_export]
macro_rules! try_init {
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }) => {
- ::pin_init::try_init!($(&$this in)? $t $(::<$($generics),*>)? {
- $($fields)*
- }? $crate::error::Error)
- };
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }? $err:ty) => {
- ::pin_init::try_init!($(&$this in)? $t $(::<$($generics),*>)? {
- $($fields)*
- }? $err)
- };
+ ($($args:tt)*) => {
+ ::pin_init::init!(
+ #[default_error($crate::error::Error)]
+ $($args)*
+ )
+ }
}
/// Construct an in-place, fallible pinned initializer for `struct`s.
@@ -279,18 +271,10 @@ macro_rules! try_init {
/// [`Error`]: crate::error::Error
#[macro_export]
macro_rules! try_pin_init {
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }) => {
- ::pin_init::try_pin_init!($(&$this in)? $t $(::<$($generics),*>)? {
- $($fields)*
- }? $crate::error::Error)
- };
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }? $err:ty) => {
- ::pin_init::try_pin_init!($(&$this in)? $t $(::<$($generics),*>)? {
- $($fields)*
- }? $err)
- };
+ ($($args:tt)*) => {
+ ::pin_init::pin_init!(
+ #[default_error($crate::error::Error)]
+ $($args)*
+ )
+ }
}
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
index 79436509dd73..f93f24a60bdd 100644
--- a/rust/kernel/kunit.rs
+++ b/rust/kernel/kunit.rs
@@ -9,9 +9,6 @@
use crate::fmt;
use crate::prelude::*;
-#[cfg(CONFIG_PRINTK)]
-use crate::c_str;
-
/// Prints a KUnit error-level message.
///
/// Public but hidden since it should only be used from KUnit generated code.
@@ -22,7 +19,7 @@ pub fn err(args: fmt::Arguments<'_>) {
#[cfg(CONFIG_PRINTK)]
unsafe {
bindings::_printk(
- c_str!("\x013%pA").as_char_ptr(),
+ c"\x013%pA".as_char_ptr(),
core::ptr::from_ref(&args).cast::<c_void>(),
);
}
@@ -38,7 +35,7 @@ pub fn info(args: fmt::Arguments<'_>) {
#[cfg(CONFIG_PRINTK)]
unsafe {
bindings::_printk(
- c_str!("\x016%pA").as_char_ptr(),
+ c"\x016%pA".as_char_ptr(),
core::ptr::from_ref(&args).cast::<c_void>(),
);
}
@@ -60,7 +57,7 @@ macro_rules! kunit_assert {
break 'out;
}
- static FILE: &'static $crate::str::CStr = $crate::c_str!($file);
+ static FILE: &'static $crate::str::CStr = $file;
static LINE: i32 = ::core::line!() as i32 - $diff;
static CONDITION: &'static $crate::str::CStr = $crate::c_str!(stringify!($condition));
@@ -192,9 +189,6 @@ pub fn is_test_result_ok(t: impl TestResult) -> bool {
}
/// Represents an individual test case.
-///
-/// The [`kunit_unsafe_test_suite!`] macro expects a NULL-terminated list of valid test cases.
-/// Use [`kunit_case_null`] to generate such a delimiter.
#[doc(hidden)]
pub const fn kunit_case(
name: &'static kernel::str::CStr,
@@ -215,32 +209,11 @@ pub const fn kunit_case(
}
}
-/// Represents the NULL test case delimiter.
-///
-/// The [`kunit_unsafe_test_suite!`] macro expects a NULL-terminated list of test cases. This
-/// function returns such a delimiter.
-#[doc(hidden)]
-pub const fn kunit_case_null() -> kernel::bindings::kunit_case {
- kernel::bindings::kunit_case {
- run_case: None,
- name: core::ptr::null_mut(),
- generate_params: None,
- attr: kernel::bindings::kunit_attributes {
- speed: kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
- },
- status: kernel::bindings::kunit_status_KUNIT_SUCCESS,
- module_name: core::ptr::null_mut(),
- log: core::ptr::null_mut(),
- param_init: None,
- param_exit: None,
- }
-}
-
/// Registers a KUnit test suite.
///
/// # Safety
///
-/// `test_cases` must be a NULL terminated array of valid test cases,
+/// `test_cases` must be a `NULL` terminated array of valid test cases,
/// whose lifetime is at least that of the test suite (i.e., static).
///
/// # Examples
@@ -253,8 +226,8 @@ pub const fn kunit_case_null() -> kernel::bindings::kunit_case {
/// }
///
/// static mut KUNIT_TEST_CASES: [kernel::bindings::kunit_case; 2] = [
-/// kernel::kunit::kunit_case(kernel::c_str!("name"), test_fn),
-/// kernel::kunit::kunit_case_null(),
+/// kernel::kunit::kunit_case(c"name", test_fn),
+/// pin_init::zeroed(),
/// ];
/// kernel::kunit_unsafe_test_suite!(suite_name, KUNIT_TEST_CASES);
/// ```
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index f812cf120042..696f62f85eb5 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -100,6 +100,8 @@ pub mod fs;
#[cfg(CONFIG_I2C = "y")]
pub mod i2c;
pub mod id_pool;
+#[doc(hidden)]
+pub mod impl_flags;
pub mod init;
pub mod io;
pub mod ioctl;
@@ -133,6 +135,7 @@ pub mod pwm;
pub mod rbtree;
pub mod regulator;
pub mod revocable;
+pub mod safety;
pub mod scatterlist;
pub mod security;
pub mod seq_file;
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
index 2d743d78d220..6fd84389a858 100644
--- a/rust/kernel/print.rs
+++ b/rust/kernel/print.rs
@@ -11,6 +11,11 @@ use crate::{
fmt,
prelude::*,
str::RawFormatter,
+ sync::atomic::{
+ Atomic,
+ AtomicType,
+ Relaxed, //
+ },
};
// Called from `vsprintf` with format specifier `%pA`.
@@ -423,3 +428,151 @@ macro_rules! pr_cont (
$crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
)
);
+
+/// A lightweight `call_once` primitive.
+///
+/// This structure provides the Rust equivalent of the kernel's `DO_ONCE_LITE` macro.
+/// While it would be possible to implement the feature entirely as a Rust macro,
+/// the functionality that can be implemented as regular functions has been
+/// extracted and implemented as the `OnceLite` struct for better code maintainability.
+pub struct OnceLite(Atomic<State>);
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[repr(i32)]
+enum State {
+ Incomplete = 0,
+ Complete = 1,
+}
+
+// SAFETY: `State` and `i32` has the same size and alignment, and it's round-trip
+// transmutable to `i32`.
+unsafe impl AtomicType for State {
+ type Repr = i32;
+}
+
+impl OnceLite {
+ /// Creates a new [`OnceLite`] in the incomplete state.
+ #[inline(always)]
+ #[allow(clippy::new_without_default)]
+ pub const fn new() -> Self {
+ OnceLite(Atomic::new(State::Incomplete))
+ }
+
+ /// Calls the provided function exactly once.
+ ///
+ /// There is no other synchronization between two `call_once()`s
+ /// except that only one will execute `f`, in other words, callers
+ /// should not use a failed `call_once()` as a proof that another
+ /// `call_once()` has already finished and the effect is observable
+ /// to this thread.
+ pub fn call_once<F>(&self, f: F) -> bool
+ where
+ F: FnOnce(),
+ {
+ // Avoid expensive cmpxchg if already completed.
+ // ORDERING: `Relaxed` is used here since no synchronization is required.
+ let old = self.0.load(Relaxed);
+ if old == State::Complete {
+ return false;
+ }
+
+ // ORDERING: `Relaxed` is used here since no synchronization is required.
+ let old = self.0.xchg(State::Complete, Relaxed);
+ if old == State::Complete {
+ return false;
+ }
+
+ f();
+ true
+ }
+}
+
+/// Run the given function exactly once.
+///
+/// This is equivalent to the kernel's `DO_ONCE_LITE` macro.
+///
+/// # Examples
+///
+/// ```
+/// kernel::do_once_lite! {
+/// kernel::pr_info!("This will be printed only once\n");
+/// };
+/// ```
+#[macro_export]
+macro_rules! do_once_lite {
+ { $($e:tt)* } => {{
+ #[link_section = ".data..once"]
+ static ONCE: $crate::print::OnceLite = $crate::print::OnceLite::new();
+ ONCE.call_once(|| { $($e)* });
+ }};
+}
+
+/// Prints an emergency-level message (level 0) only once.
+///
+/// Equivalent to the kernel's `pr_emerg_once` macro.
+#[macro_export]
+macro_rules! pr_emerg_once (
+ ($($arg:tt)*) => (
+ $crate::do_once_lite! { $crate::pr_emerg!($($arg)*) }
+ )
+);
+
+/// Prints an alert-level message (level 1) only once.
+///
+/// Equivalent to the kernel's `pr_alert_once` macro.
+#[macro_export]
+macro_rules! pr_alert_once (
+ ($($arg:tt)*) => (
+ $crate::do_once_lite! { $crate::pr_alert!($($arg)*) }
+ )
+);
+
+/// Prints a critical-level message (level 2) only once.
+///
+/// Equivalent to the kernel's `pr_crit_once` macro.
+#[macro_export]
+macro_rules! pr_crit_once (
+ ($($arg:tt)*) => (
+ $crate::do_once_lite! { $crate::pr_crit!($($arg)*) }
+ )
+);
+
+/// Prints an error-level message (level 3) only once.
+///
+/// Equivalent to the kernel's `pr_err_once` macro.
+#[macro_export]
+macro_rules! pr_err_once (
+ ($($arg:tt)*) => (
+ $crate::do_once_lite! { $crate::pr_err!($($arg)*) }
+ )
+);
+
+/// Prints a warning-level message (level 4) only once.
+///
+/// Equivalent to the kernel's `pr_warn_once` macro.
+#[macro_export]
+macro_rules! pr_warn_once (
+ ($($arg:tt)*) => (
+ $crate::do_once_lite! { $crate::pr_warn!($($arg)*) }
+ )
+);
+
+/// Prints a notice-level message (level 5) only once.
+///
+/// Equivalent to the kernel's `pr_notice_once` macro.
+#[macro_export]
+macro_rules! pr_notice_once (
+ ($($arg:tt)*) => (
+ $crate::do_once_lite! { $crate::pr_notice!($($arg)*) }
+ )
+);
+
+/// Prints an info-level message (level 6) only once.
+///
+/// Equivalent to the kernel's `pr_info_once` macro.
+#[macro_export]
+macro_rules! pr_info_once (
+ ($($arg:tt)*) => (
+ $crate::do_once_lite! { $crate::pr_info!($($arg)*) }
+ )
+);
diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
index e3893ed04049..5b6a382637fe 100644
--- a/rust/kernel/ptr.rs
+++ b/rust/kernel/ptr.rs
@@ -5,8 +5,6 @@
use core::mem::align_of;
use core::num::NonZero;
-use crate::build_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
@@ -40,10 +38,12 @@ impl Alignment {
/// ```
#[inline(always)]
pub const fn new<const ALIGN: usize>() -> Self {
- build_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.
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
index 312cecab72e7..6fbd579d4a43 100644
--- a/rust/kernel/rbtree.rs
+++ b/rust/kernel/rbtree.rs
@@ -414,14 +414,17 @@ where
// SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
// point to the links field of `Node<K, V>` objects.
let this = unsafe { container_of!(node, Node<K, V>, links) };
+
// SAFETY: `this` is a non-null node so it is valid by the type invariants.
- node = match key.cmp(unsafe { &(*this).key }) {
- // SAFETY: `node` is a non-null node so it is valid by the type invariants.
- Ordering::Less => unsafe { (*node).rb_left },
- // SAFETY: `node` is a non-null node so it is valid by the type invariants.
- Ordering::Greater => unsafe { (*node).rb_right },
- // SAFETY: `node` is a non-null node so it is valid by the type invariants.
- Ordering::Equal => return Some(unsafe { &(*this).value }),
+ let this_ref = unsafe { &*this };
+
+ // SAFETY: `node` is a non-null node so it is valid by the type invariants.
+ let node_ref = unsafe { &*node };
+
+ node = match key.cmp(&this_ref.key) {
+ Ordering::Less => node_ref.rb_left,
+ Ordering::Greater => node_ref.rb_right,
+ Ordering::Equal => return Some(&this_ref.value),
}
}
None
@@ -498,10 +501,10 @@ where
let this = unsafe { container_of!(node, Node<K, V>, links) };
// SAFETY: `this` is a non-null node so it is valid by the type invariants.
let this_key = unsafe { &(*this).key };
+
// SAFETY: `node` is a non-null node so it is valid by the type invariants.
- let left_child = unsafe { (*node).rb_left };
- // SAFETY: `node` is a non-null node so it is valid by the type invariants.
- let right_child = unsafe { (*node).rb_right };
+ let node_ref = unsafe { &*node };
+
match key.cmp(this_key) {
Ordering::Equal => {
// SAFETY: `this` is a non-null node so it is valid by the type invariants.
@@ -509,7 +512,7 @@ where
break;
}
Ordering::Greater => {
- node = right_child;
+ node = node_ref.rb_right;
}
Ordering::Less => {
let is_better_match = match best_key {
@@ -521,7 +524,7 @@ where
// 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;
+ node = node_ref.rb_left;
}
};
}
diff --git a/rust/kernel/safety.rs b/rust/kernel/safety.rs
new file mode 100644
index 000000000000..c1c6bd0fa2cc
--- /dev/null
+++ b/rust/kernel/safety.rs
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Safety related APIs.
+
+/// Checks that a precondition of an unsafe function is followed.
+///
+/// The check is enabled at runtime if debug assertions (`CONFIG_RUST_DEBUG_ASSERTIONS`)
+/// are enabled. Otherwise, this macro is a no-op.
+///
+/// # Examples
+///
+/// ```no_run
+/// use kernel::unsafe_precondition_assert;
+///
+/// struct RawBuffer<T: Copy, const N: usize> {
+/// data: [T; N],
+/// }
+///
+/// impl<T: Copy, const N: usize> RawBuffer<T, N> {
+/// /// # Safety
+/// ///
+/// /// The caller must ensure that `index` is less than `N`.
+/// unsafe fn set_unchecked(&mut self, index: usize, value: T) {
+/// unsafe_precondition_assert!(
+/// index < N,
+/// "RawBuffer::set_unchecked() requires index ({index}) < N ({N})"
+/// );
+///
+/// // SAFETY: By the safety requirements of this function, `index` is valid.
+/// unsafe {
+/// *self.data.get_unchecked_mut(index) = value;
+/// }
+/// }
+/// }
+/// ```
+///
+/// # Panics
+///
+/// Panics if the expression is evaluated to [`false`] at runtime.
+#[macro_export]
+macro_rules! unsafe_precondition_assert {
+ ($cond:expr $(,)?) => {
+ $crate::unsafe_precondition_assert!(@inner $cond, ::core::stringify!($cond))
+ };
+
+ ($cond:expr, $($arg:tt)+) => {
+ $crate::unsafe_precondition_assert!(@inner $cond, $crate::prelude::fmt!($($arg)+))
+ };
+
+ (@inner $cond:expr, $msg:expr) => {
+ ::core::debug_assert!($cond, "unsafe precondition violated: {}", $msg)
+ };
+}
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index be5dbf3829e2..5711580c9f9b 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -170,6 +170,10 @@ macro_rules! impl_frombytes {
}
impl_frombytes! {
+ // SAFETY: Inhabited ZSTs only have one possible bit pattern, and these two have no invariant.
+ (),
+ {<T>} core::marker::PhantomData<T>,
+
// SAFETY: All bit patterns are acceptable values of the types below.
u8, u16, u32, u64, usize,
i8, i16, i32, i64, isize,
@@ -230,6 +234,10 @@ macro_rules! impl_asbytes {
}
impl_asbytes! {
+ // SAFETY: Inhabited ZSTs only have one possible bit pattern, and these two have no invariant.
+ (),
+ {<T>} core::marker::PhantomData<T>,
+
// SAFETY: Instances of the following types have no uninitialized portions.
u8, u16, u32, u64, usize,
i8, i16, i32, i64, isize,