[PATCH 2/2] rust: kernel: migrate to cfg_select! for config-based selection

From: Nika Krasnova

Date: Sun Jun 28 2026 - 23:52:49 EST


Convert the paired #[cfg(CONFIG_FOO)] / #[cfg(not(CONFIG_FOO))]
selections in the kernel crate to cfg_select!. These sites each choose
one of several mutually-exclusive implementations, which is exactly what
cfg_select! expresses as a single construct.

One case is deliberately left as #[cfg]: a #[macro_export] macro_rules!
that is referred to by an absolute path ($crate::/crate::) cannot be
wrapped in cfg_select!, because a macro produced by macro expansion may
not be named that way (see rust-lang/rust#52234). print_macro in
print.rs hits this and is kept as paired #[cfg]; macros invoked only by
their bare name, such as the asm! wrapper in lib.rs, are unaffected and
are converted.

Link: https://github.com/Rust-for-Linux/linux/issues/1183
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Nika Krasnova <nika@xxxxxxxxxxxx>
---
rust/kernel/cpu.rs | 21 ++---
rust/kernel/cpumask.rs | 42 +++++-----
rust/kernel/debugfs.rs | 145 ++++++++++++++++++-----------------
rust/kernel/driver.rs | 44 ++++++-----
rust/kernel/drm/device.rs | 53 +++++++------
rust/kernel/error.rs | 47 ++++++------
rust/kernel/kunit.rs | 54 +++++++------
rust/kernel/lib.rs | 77 ++++++++++---------
rust/kernel/mm.rs | 36 +++++----
rust/kernel/sync/atomic.rs | 54 +++++++------
rust/kernel/sync/atomic/predefine.rs | 35 +++++----
rust/kernel/time.rs | 82 ++++++++++----------
12 files changed, 366 insertions(+), 324 deletions(-)

diff --git a/rust/kernel/cpu.rs b/rust/kernel/cpu.rs
index cb6c0338ef5a..b6730331fda8 100644
--- a/rust/kernel/cpu.rs
+++ b/rust/kernel/cpu.rs
@@ -4,20 +4,21 @@
//!
//! C header: [`include/linux/cpu.h`](srctree/include/linux/cpu.h)

-use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
+use crate::{bindings, cfg_select, device::Device, error::Result, prelude::ENODEV};

/// Returns the maximum number of possible CPUs in the current system configuration.
#[inline]
pub fn nr_cpu_ids() -> u32 {
- #[cfg(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS))]
- {
- bindings::NR_CPUS
- }
-
- #[cfg(not(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS)))]
- // SAFETY: `nr_cpu_ids` is a valid global provided by the kernel.
- unsafe {
- bindings::nr_cpu_ids
+ cfg_select! {
+ any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS) => {
+ bindings::NR_CPUS
+ }
+ _ => {
+ // SAFETY: `nr_cpu_ids` is a valid global provided by the kernel.
+ unsafe {
+ bindings::nr_cpu_ids
+ }
+ }
}
}

diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs
index 44bb36636ee3..f86ec96acfe2 100644
--- a/rust/kernel/cpumask.rs
+++ b/rust/kernel/cpumask.rs
@@ -307,28 +307,34 @@ pub fn try_clone(cpumask: &Cpumask) -> Result<Self> {
impl Deref for CpumaskVar {
type Target = Cpumask;

- #[cfg(CONFIG_CPUMASK_OFFSTACK)]
- fn deref(&self) -> &Self::Target {
- // SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.
- unsafe { &*self.ptr.as_ptr() }
- }
-
- #[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
- fn deref(&self) -> &Self::Target {
- &self.mask
+ cfg_select! {
+ CONFIG_CPUMASK_OFFSTACK => {
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.
+ unsafe { &*self.ptr.as_ptr() }
+ }
+ }
+ _ => {
+ fn deref(&self) -> &Self::Target {
+ &self.mask
+ }
+ }
}
}

impl DerefMut for CpumaskVar {
- #[cfg(CONFIG_CPUMASK_OFFSTACK)]
- fn deref_mut(&mut self) -> &mut Cpumask {
- // SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.
- unsafe { self.ptr.as_mut() }
- }
-
- #[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
- fn deref_mut(&mut self) -> &mut Cpumask {
- &mut self.mask
+ cfg_select! {
+ CONFIG_CPUMASK_OFFSTACK => {
+ fn deref_mut(&mut self) -> &mut Cpumask {
+ // SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.
+ unsafe { self.ptr.as_mut() }
+ }
+ }
+ _ => {
+ fn deref_mut(&mut self) -> &mut Cpumask {
+ &mut self.mask
+ }
+ }
}
}

diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index d7b8014a6474..39657bfd1714 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -75,22 +75,22 @@
impl Dir {
/// Create a new directory in DebugFS. If `parent` is [`None`], it will be created at the root.
fn create(name: &CStr, parent: Option<&Dir>) -> Self {
- #[cfg(CONFIG_DEBUG_FS)]
- {
- let parent_entry = match parent {
- // If the parent couldn't be allocated, just early-return
- Some(Dir(None)) => return Self(None),
- Some(Dir(Some(entry))) => Some(entry.clone()),
- None => None,
- };
- Self(
- // If Arc creation fails, the `Entry` will be dropped, so the directory will be
- // cleaned up.
- Arc::new(Entry::dynamic_dir(name, parent_entry), GFP_KERNEL).ok(),
- )
+ cfg_select! {
+ CONFIG_DEBUG_FS => {
+ let parent_entry = match parent {
+ // If the parent couldn't be allocated, just early-return
+ Some(Dir(None)) => return Self(None),
+ Some(Dir(Some(entry))) => Some(entry.clone()),
+ None => None,
+ };
+ Self(
+ // If Arc creation fails, the `Entry` will be dropped, so the directory will be
+ // cleaned up.
+ Arc::new(Entry::dynamic_dir(name, parent_entry), GFP_KERNEL).ok(),
+ )
+ }
+ _ => { Self() }
}
- #[cfg(not(CONFIG_DEBUG_FS))]
- Self()
}

/// Creates a DebugFS file which will own the data produced by the initializer provided in
@@ -360,19 +360,19 @@ pub fn write_callback_file<'a, T, E: 'a, W>(
// Unless you also extract the `entry` later and schedule it for `Drop` at the appropriate
// time, a `ScopedDir` with a `Dir` parent will never be deleted.
fn scoped_dir<'data>(&self, name: &CStr) -> ScopedDir<'data, 'static> {
- #[cfg(CONFIG_DEBUG_FS)]
- {
- let parent_entry = match &self.0 {
- None => return ScopedDir::empty(),
- Some(entry) => entry.clone(),
- };
- ScopedDir {
- entry: ManuallyDrop::new(Entry::dynamic_dir(name, Some(parent_entry))),
- _phantom: PhantomData,
+ cfg_select! {
+ CONFIG_DEBUG_FS => {
+ let parent_entry = match &self.0 {
+ None => return ScopedDir::empty(),
+ Some(entry) => entry.clone(),
+ };
+ ScopedDir {
+ entry: ManuallyDrop::new(Entry::dynamic_dir(name, Some(parent_entry))),
+ _phantom: PhantomData,
+ }
}
+ _ => { ScopedDir::empty() }
}
- #[cfg(not(CONFIG_DEBUG_FS))]
- ScopedDir::empty()
}

/// Creates a new scope, which is a directory associated with some data `T`.
@@ -430,47 +430,50 @@ pub struct File<T> {
scope: Scope<T>,
}

-#[cfg(not(CONFIG_DEBUG_FS))]
-impl<'b, T: 'b> Scope<T> {
- fn new<E: 'b, F>(data: impl PinInit<T, E> + 'b, init: F) -> impl PinInit<Self, E> + 'b
- where
- F: for<'a> FnOnce(&'a T) + 'b,
- {
- try_pin_init! {
- Self {
- data <- data,
- _pin: PhantomPinned
- } ? E
- }
- .pin_chain(|scope| {
- init(&scope.data);
- Ok(())
- })
- }
-}
+cfg_select! {
+ CONFIG_DEBUG_FS => {
+ impl<'b, T: 'b> Scope<T> {
+ fn entry_mut(self: Pin<&mut Self>) -> &mut Entry<'static> {
+ // SAFETY: _entry is not structurally pinned.
+ unsafe { &mut Pin::into_inner_unchecked(self)._entry }
+ }

-#[cfg(CONFIG_DEBUG_FS)]
-impl<'b, T: 'b> Scope<T> {
- fn entry_mut(self: Pin<&mut Self>) -> &mut Entry<'static> {
- // SAFETY: _entry is not structurally pinned.
- unsafe { &mut Pin::into_inner_unchecked(self)._entry }
+ fn new<E: 'b, F>(data: impl PinInit<T, E> + 'b, init: F) -> impl PinInit<Self, E> + 'b
+ where
+ F: for<'a> FnOnce(&'a T) -> Entry<'static> + 'b,
+ {
+ try_pin_init! {
+ Self {
+ _entry: Entry::empty(),
+ data <- data,
+ _pin: PhantomPinned
+ } ? E
+ }
+ .pin_chain(|scope| {
+ *scope.entry_mut() = init(&scope.data);
+ Ok(())
+ })
+ }
+ }
}
-
- fn new<E: 'b, F>(data: impl PinInit<T, E> + 'b, init: F) -> impl PinInit<Self, E> + 'b
- where
- F: for<'a> FnOnce(&'a T) -> Entry<'static> + 'b,
- {
- try_pin_init! {
- Self {
- _entry: Entry::empty(),
- data <- data,
- _pin: PhantomPinned
- } ? E
+ _ => {
+ impl<'b, T: 'b> Scope<T> {
+ fn new<E: 'b, F>(data: impl PinInit<T, E> + 'b, init: F) -> impl PinInit<Self, E> + 'b
+ where
+ F: for<'a> FnOnce(&'a T) + 'b,
+ {
+ try_pin_init! {
+ Self {
+ data <- data,
+ _pin: PhantomPinned
+ } ? E
+ }
+ .pin_chain(|scope| {
+ init(&scope.data);
+ Ok(())
+ })
+ }
}
- .pin_chain(|scope| {
- *scope.entry_mut() = init(&scope.data);
- Ok(())
- })
}
}

@@ -702,12 +705,16 @@ fn empty() -> Self {
_phantom: PhantomData,
}
}
- #[cfg(CONFIG_DEBUG_FS)]
- fn into_entry(self) -> Entry<'dir> {
- ManuallyDrop::into_inner(self.entry)
+ cfg_select! {
+ CONFIG_DEBUG_FS => {
+ fn into_entry(self) -> Entry<'dir> {
+ ManuallyDrop::into_inner(self.entry)
+ }
+ }
+ _ => {
+ fn into_entry(self) {}
+ }
}
- #[cfg(not(CONFIG_DEBUG_FS))]
- fn into_entry(self) {}
}

impl<'data> ScopedDir<'data, 'static> {
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index bf5ba0d27553..871ea9e04804 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -328,29 +328,31 @@ pub trait Adapter {
///
/// If this returns `None`, it means there is no match with an entry in the [`acpi::IdTable`].
fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
- #[cfg(not(CONFIG_ACPI))]
- {
- let _ = dev;
- None
- }
+ cfg_select! {
+ CONFIG_ACPI => {
+ let table = Self::acpi_id_table()?;

- #[cfg(CONFIG_ACPI)]
- {
- let table = Self::acpi_id_table()?;
-
- // SAFETY:
- // - `table` has static lifetime, hence it's valid for read,
- // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
- let raw_id = unsafe { bindings::acpi_match_device(table.as_ptr(), dev.as_raw()) };
-
- if raw_id.is_null() {
+ // SAFETY:
+ // - `table` has static lifetime, hence it's valid for read,
+ // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
+ let raw_id = unsafe { bindings::acpi_match_device(table.as_ptr(), dev.as_raw()) };
+
+ if raw_id.is_null() {
+ None
+ } else {
+ // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of
+ // `struct acpi_device_id` and does not add additional invariants, so
+ // it's safe to transmute.
+ let id = unsafe { &*raw_id.cast::<acpi::DeviceId>() };
+
+ Some(table.info(
+ <acpi::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id),
+ ))
+ }
+ }
+ _ => {
+ let _ = dev;
None
- } else {
- // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct acpi_device_id`
- // and does not add additional invariants, so it's safe to transmute.
- let id = unsafe { &*raw_id.cast::<acpi::DeviceId>() };
-
- Some(table.info(<acpi::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id)))
}
}
}
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 477cf771fb10..61a184241d55 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -41,33 +41,36 @@
},
};

-#[cfg(CONFIG_DRM_LEGACY)]
-macro_rules! drm_legacy_fields {
- ( $($field:ident: $val:expr),* $(,)? ) => {
- bindings::drm_driver {
- $( $field: $val ),*,
- firstopen: None,
- preclose: None,
- dma_ioctl: None,
- dma_quiescent: None,
- context_dtor: None,
- irq_handler: None,
- irq_preinstall: None,
- irq_postinstall: None,
- irq_uninstall: None,
- get_vblank_counter: None,
- enable_vblank: None,
- disable_vblank: None,
- dev_priv_size: 0,
+cfg_select! {
+ CONFIG_DRM_LEGACY => {
+ macro_rules! drm_legacy_fields {
+ ( $($field:ident: $val:expr),* $(,)? ) => {
+ bindings::drm_driver {
+ $( $field: $val ),*,
+ firstopen: None,
+ preclose: None,
+ dma_ioctl: None,
+ dma_quiescent: None,
+ context_dtor: None,
+ irq_handler: None,
+ irq_preinstall: None,
+ irq_postinstall: None,
+ irq_uninstall: None,
+ get_vblank_counter: None,
+ enable_vblank: None,
+ disable_vblank: None,
+ dev_priv_size: 0,
+ }
+ }
}
}
-}
-
-#[cfg(not(CONFIG_DRM_LEGACY))]
-macro_rules! drm_legacy_fields {
- ( $($field:ident: $val:expr),* $(,)? ) => {
- bindings::drm_driver {
- $( $field: $val ),*
+ _ => {
+ macro_rules! drm_legacy_fields {
+ ( $($field:ident: $val:expr),* $(,)? ) => {
+ bindings::drm_driver {
+ $( $field: $val ),*
+ }
+ }
}
}
}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index a56ba6309594..733c2d08c5e6 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -8,7 +8,7 @@

use crate::{
alloc::{layout::LayoutError, AllocError},
- fmt,
+ cfg_select, fmt,
str::CStr,
};

@@ -173,29 +173,32 @@ pub fn to_ptr<T>(self) -> *mut T {
unsafe { bindings::ERR_PTR(self.0.get() as crate::ffi::c_long).cast() }
}

- /// Returns a string representing the error, if one exists.
- #[cfg(not(testlib))]
- pub fn name(&self) -> Option<&'static CStr> {
- // SAFETY: Just an FFI call, there are no extra safety requirements.
- let ptr = unsafe { bindings::errname(-self.0.get()) };
- if ptr.is_null() {
- None
- } else {
- use crate::str::CStrExt as _;
-
- // SAFETY: The string returned by `errname` is static and `NUL`-terminated.
- Some(unsafe { CStr::from_char_ptr(ptr) })
+ cfg_select! {
+ testlib => {
+ /// Returns a string representing the error, if one exists.
+ ///
+ /// When `testlib` is configured, this always returns `None` to avoid
+ /// the dependency on a kernel function so that tests that use this
+ /// (e.g., by calling [`Result::unwrap`]) can still run in userspace.
+ pub fn name(&self) -> Option<&'static CStr> {
+ None
+ }
}
- }
+ _ => {
+ /// Returns a string representing the error, if one exists.
+ pub fn name(&self) -> Option<&'static CStr> {
+ // SAFETY: Just an FFI call, there are no extra safety requirements.
+ let ptr = unsafe { bindings::errname(-self.0.get()) };
+ if ptr.is_null() {
+ None
+ } else {
+ use crate::str::CStrExt as _;

- /// Returns a string representing the error, if one exists.
- ///
- /// When `testlib` is configured, this always returns `None` to avoid the dependency on a
- /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still
- /// run in userspace.
- #[cfg(testlib)]
- pub fn name(&self) -> Option<&'static CStr> {
- None
+ // SAFETY: The string returned by `errname` is static and `NUL`-terminated.
+ Some(unsafe { CStr::from_char_ptr(ptr) })
+ }
+ }
+ }
}
}

diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
index cdee5f27bd7f..5ec15bfbfee6 100644
--- a/rust/kernel/kunit.rs
+++ b/rust/kernel/kunit.rs
@@ -14,18 +14,21 @@
/// Public but hidden since it should only be used from KUnit generated code.
#[doc(hidden)]
pub fn err(args: fmt::Arguments<'_>) {
- // `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
- #[cfg(not(CONFIG_PRINTK))]
- let _ = args;
-
- // SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
- // are passing.
- #[cfg(CONFIG_PRINTK)]
- unsafe {
- bindings::_printk(
- c"\x013%pA".as_char_ptr(),
- core::ptr::from_ref(&args).cast::<c_void>(),
- );
+ cfg_select! {
+ CONFIG_PRINTK => {
+ // SAFETY: The format string is null-terminated and the `%pA` specifier matches the
+ // argument we are passing.
+ unsafe {
+ bindings::_printk(
+ c"\x013%pA".as_char_ptr(),
+ core::ptr::from_ref(&args).cast::<c_void>(),
+ );
+ }
+ }
+ _ => {
+ // `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
+ let _ = args;
+ }
}
}

@@ -34,18 +37,21 @@ pub fn err(args: fmt::Arguments<'_>) {
/// Public but hidden since it should only be used from KUnit generated code.
#[doc(hidden)]
pub fn info(args: fmt::Arguments<'_>) {
- // `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
- #[cfg(not(CONFIG_PRINTK))]
- let _ = args;
-
- // SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
- // are passing.
- #[cfg(CONFIG_PRINTK)]
- unsafe {
- bindings::_printk(
- c"\x016%pA".as_char_ptr(),
- core::ptr::from_ref(&args).cast::<c_void>(),
- );
+ cfg_select! {
+ CONFIG_PRINTK => {
+ // SAFETY: The format string is null-terminated and the `%pA` specifier matches the
+ // argument we are passing.
+ unsafe {
+ bindings::_printk(
+ c"\x016%pA".as_char_ptr(),
+ core::ptr::from_ref(&args).cast::<c_void>(),
+ );
+ }
+ }
+ _ => {
+ // `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
+ let _ = args;
+ }
}
}

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index cdcbb34047c0..ba233a037fe6 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -276,30 +276,34 @@ macro_rules! concat_literals {
};
}

-/// Wrapper around `asm!` configured for use in the kernel.
-///
-/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
-/// syntax.
-// For x86, `asm!` uses intel syntax by default, but we want to use at&t syntax in the kernel.
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-#[macro_export]
-macro_rules! asm {
- ($($asm:expr),* ; $($rest:tt)*) => {
- ::core::arch::asm!( $($asm)*, options(att_syntax), $($rest)* )
- };
-}
-
-/// Wrapper around `asm!` configured for use in the kernel.
-///
-/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
-/// syntax.
-// For non-x86 arches we just pass through to `asm!`.
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-#[macro_export]
-macro_rules! asm {
- ($($asm:expr),* ; $($rest:tt)*) => {
- ::core::arch::asm!( $($asm)*, $($rest)* )
- };
+cfg_select! {
+ any(target_arch = "x86", target_arch = "x86_64") => {
+ /// Wrapper around `asm!` configured for use in the kernel.
+ ///
+ /// Uses a semicolon to avoid parsing ambiguities, even though this does
+ /// not match native `asm!` syntax.
+ // For x86, `asm!` uses intel syntax by default, but we want to use at&t
+ // syntax in the kernel.
+ #[macro_export]
+ macro_rules! asm {
+ ($($asm:expr),* ; $($rest:tt)*) => {
+ ::core::arch::asm!( $($asm)*, options(att_syntax), $($rest)* )
+ };
+ }
+ }
+ _ => {
+ /// Wrapper around `asm!` configured for use in the kernel.
+ ///
+ /// Uses a semicolon to avoid parsing ambiguities, even though this does
+ /// not match native `asm!` syntax.
+ // For non-x86 arches we just pass through to `asm!`.
+ #[macro_export]
+ macro_rules! asm {
+ ($($asm:expr),* ; $($rest:tt)*) => {
+ ::core::arch::asm!( $($asm)*, $($rest)* )
+ };
+ }
+ }
}

/// Gets the C string file name of a [`Location`].
@@ -334,19 +338,16 @@ macro_rules! asm {
/// ```
#[inline]
pub fn file_from_location<'a>(loc: &'a core::panic::Location<'a>) -> &'a core::ffi::CStr {
- #[cfg(CONFIG_RUSTC_HAS_FILE_AS_C_STR)]
- {
- loc.file_as_c_str()
- }
-
- #[cfg(all(CONFIG_RUSTC_HAS_FILE_WITH_NUL, not(CONFIG_RUSTC_HAS_FILE_AS_C_STR)))]
- {
- loc.file_with_nul()
- }
-
- #[cfg(not(CONFIG_RUSTC_HAS_FILE_WITH_NUL))]
- {
- let _ = loc;
- c"<Location::file_as_c_str() not supported>"
+ cfg_select! {
+ CONFIG_RUSTC_HAS_FILE_AS_C_STR => {
+ loc.file_as_c_str()
+ }
+ all(CONFIG_RUSTC_HAS_FILE_WITH_NUL, not(CONFIG_RUSTC_HAS_FILE_AS_C_STR)) => {
+ loc.file_with_nul()
+ }
+ not(CONFIG_RUSTC_HAS_FILE_WITH_NUL) => {
+ let _ = loc;
+ c"<Location::file_as_c_str() not supported>"
+ }
}
}
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
index 4764d7b68f2a..b3937d37b3a2 100644
--- a/rust/kernel/mm.rs
+++ b/rust/kernel/mm.rs
@@ -12,7 +12,7 @@
//! C header: [`include/linux/mm.h`](srctree/include/linux/mm.h)

use crate::{
- bindings,
+ bindings, cfg_select,
sync::aref::{ARef, AlwaysRefCounted},
types::{NotThreadSafe, Opaque},
};
@@ -174,25 +174,27 @@ pub unsafe fn from_raw<'a>(ptr: *const bindings::mm_struct) -> &'a MmWithUser {
/// When per-vma locks are disabled, this always returns `None`.
#[inline]
pub fn lock_vma_under_rcu(&self, vma_addr: usize) -> Option<VmaReadGuard<'_>> {
- #[cfg(CONFIG_PER_VMA_LOCK)]
- {
- // SAFETY: Calling `bindings::lock_vma_under_rcu` is always okay given an mm where
- // `mm_users` is non-zero.
- let vma = unsafe { bindings::lock_vma_under_rcu(self.as_raw(), vma_addr) };
- if !vma.is_null() {
- return Some(VmaReadGuard {
- // SAFETY: If `lock_vma_under_rcu` returns a non-null ptr, then it points at a
- // valid vma. The vma is stable for as long as the vma read lock is held.
- vma: unsafe { VmaRef::from_raw(vma) },
- _nts: NotThreadSafe,
- });
+ cfg_select! {
+ CONFIG_PER_VMA_LOCK => {
+ // SAFETY: Calling `bindings::lock_vma_under_rcu` is always okay given an mm where
+ // `mm_users` is non-zero.
+ let vma = unsafe { bindings::lock_vma_under_rcu(self.as_raw(), vma_addr) };
+ if !vma.is_null() {
+ return Some(VmaReadGuard {
+ // SAFETY: If `lock_vma_under_rcu` returns a non-null ptr, then it
+ // points at a valid vma. The vma is stable for as long as the vma
+ // read lock is held.
+ vma: unsafe { VmaRef::from_raw(vma) },
+ _nts: NotThreadSafe,
+ });
+ }
+ }
+ _ => {
+ // Silence warnings about unused variables.
+ let _ = vma_addr;
}
}

- // Silence warnings about unused variables.
- #[cfg(not(CONFIG_PER_VMA_LOCK))]
- let _ = vma_addr;
-
None
}

diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs
index 9cd009d57e35..d67dc44e8b2e 100644
--- a/rust/kernel/sync/atomic.rs
+++ b/rust/kernel/sync/atomic.rs
@@ -26,6 +26,7 @@
pub(crate) use internal::{AtomicArithmeticOps, AtomicBasicOps, AtomicExchangeOps};

use crate::build_error;
+use crate::cfg_select;
use internal::AtomicRepr;
use ordering::OrderingType;

@@ -620,25 +621,28 @@ pub fn fetch_sub<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering)
}
}

-#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
-#[repr(C)]
-#[derive(Clone, Copy)]
-struct Flag {
- bool_field: bool,
-}
-
-/// # Invariants
-///
-/// `padding` must be all zeroes.
-#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
-#[repr(C, align(4))]
-#[derive(Clone, Copy)]
-struct Flag {
- #[cfg(target_endian = "big")]
- padding: [u8; 3],
- bool_field: bool,
- #[cfg(target_endian = "little")]
- padding: [u8; 3],
+cfg_select! {
+ any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64) => {
+ #[repr(C)]
+ #[derive(Clone, Copy)]
+ struct Flag {
+ bool_field: bool,
+ }
+ }
+ _ => {
+ /// # Invariants
+ ///
+ /// `padding` must be all zeroes.
+ #[repr(C, align(4))]
+ #[derive(Clone, Copy)]
+ struct Flag {
+ #[cfg(target_endian = "big")]
+ padding: [u8; 3],
+ bool_field: bool,
+ #[cfg(target_endian = "little")]
+ padding: [u8; 3],
+ }
+ }
}

impl Flag {
@@ -656,10 +660,14 @@ const fn new(b: bool) -> Self {
// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip
// transmutable to the selected representation (`i8` or `i32`).
unsafe impl AtomicType for Flag {
- #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
- type Repr = i8;
- #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
- type Repr = i32;
+ cfg_select! {
+ any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64) => {
+ type Repr = i8;
+ }
+ _ => {
+ type Repr = i32;
+ }
+ }
}

/// An atomic flag type intended to be backed by performance-optimal integer type.
diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs
index 3d63f40791fa..7156e9b67c8c 100644
--- a/rust/kernel/sync/atomic/predefine.rs
+++ b/rust/kernel/sync/atomic/predefine.rs
@@ -76,23 +76,24 @@ fn rhs_into_delta(rhs: i64) -> i64 {
// Defines an internal type that always maps to the integer type which has the same size alignment
// as `isize` and `usize`, and `isize` and `usize` are always bi-directional transmutable to
// `isize_atomic_repr`, which also always implements `AtomicImpl`.
-#[allow(non_camel_case_types)]
-#[cfg(not(testlib))]
-#[cfg(not(CONFIG_64BIT))]
-type isize_atomic_repr = i32;
-#[allow(non_camel_case_types)]
-#[cfg(not(testlib))]
-#[cfg(CONFIG_64BIT)]
-type isize_atomic_repr = i64;
-
-#[allow(non_camel_case_types)]
-#[cfg(testlib)]
-#[cfg(target_pointer_width = "32")]
-type isize_atomic_repr = i32;
-#[allow(non_camel_case_types)]
-#[cfg(testlib)]
-#[cfg(target_pointer_width = "64")]
-type isize_atomic_repr = i64;
+cfg_select! {
+ all(not(testlib), not(CONFIG_64BIT)) => {
+ #[allow(non_camel_case_types)]
+ type isize_atomic_repr = i32;
+ }
+ all(not(testlib), CONFIG_64BIT) => {
+ #[allow(non_camel_case_types)]
+ type isize_atomic_repr = i64;
+ }
+ all(testlib, target_pointer_width = "32") => {
+ #[allow(non_camel_case_types)]
+ type isize_atomic_repr = i32;
+ }
+ all(testlib, target_pointer_width = "64") => {
+ #[allow(non_camel_case_types)]
+ type isize_atomic_repr = i64;
+ }
+}

// Ensure size and alignment requirements are checked.
static_assert!(size_of::<isize>() == size_of::<isize_atomic_repr>());
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 363e93cbb139..5cca5b9d111e 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -27,6 +27,8 @@
use core::marker::PhantomData;
use core::ops;

+use crate::cfg_select;
+
pub mod delay;
pub mod hrtimer;

@@ -360,15 +362,14 @@ impl ops::Div for Delta {

#[inline]
fn div(self, rhs: Self) -> Self::Output {
- #[cfg(CONFIG_64BIT)]
- {
- self.nanos / rhs.nanos
- }
-
- #[cfg(not(CONFIG_64BIT))]
- {
- // SAFETY: This function is always safe to call regardless of the input values
- unsafe { bindings::div64_s64(self.nanos, rhs.nanos) }
+ cfg_select! {
+ CONFIG_64BIT => {
+ self.nanos / rhs.nanos
+ }
+ _ => {
+ // SAFETY: This function is always safe to call regardless of the input values
+ unsafe { bindings::div64_s64(self.nanos, rhs.nanos) }
+ }
}
}
}
@@ -441,30 +442,32 @@ pub const fn as_nanos(self) -> i64 {
/// to the value in the [`Delta`].
#[inline]
pub fn as_micros_ceil(self) -> i64 {
- #[cfg(CONFIG_64BIT)]
- {
- self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC
- }
-
- #[cfg(not(CONFIG_64BIT))]
- // SAFETY: It is always safe to call `ktime_to_us()` with any value.
- unsafe {
- bindings::ktime_to_us(self.as_nanos().saturating_add(NSEC_PER_USEC - 1))
+ cfg_select! {
+ CONFIG_64BIT => {
+ self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC
+ }
+ _ => {
+ // SAFETY: It is always safe to call `ktime_to_us()` with any value.
+ unsafe {
+ bindings::ktime_to_us(self.as_nanos().saturating_add(NSEC_PER_USEC - 1))
+ }
+ }
}
}

/// Return the number of milliseconds in the [`Delta`].
#[inline]
pub fn as_millis(self) -> i64 {
- #[cfg(CONFIG_64BIT)]
- {
- self.as_nanos() / NSEC_PER_MSEC
- }
-
- #[cfg(not(CONFIG_64BIT))]
- // SAFETY: It is always safe to call `ktime_to_ms()` with any value.
- unsafe {
- bindings::ktime_to_ms(self.as_nanos())
+ cfg_select! {
+ CONFIG_64BIT => {
+ self.as_nanos() / NSEC_PER_MSEC
+ }
+ _ => {
+ // SAFETY: It is always safe to call `ktime_to_ms()` with any value.
+ unsafe {
+ bindings::ktime_to_ms(self.as_nanos())
+ }
+ }
}
}

@@ -474,22 +477,21 @@ pub fn as_millis(self) -> i64 {
/// limited to 32 bit dividends.
#[inline]
pub fn rem_nanos(self, dividend: i32) -> Self {
- #[cfg(CONFIG_64BIT)]
- {
- Self {
- nanos: self.as_nanos() % i64::from(dividend),
+ cfg_select! {
+ CONFIG_64BIT => {
+ Self {
+ nanos: self.as_nanos() % i64::from(dividend),
+ }
}
- }
-
- #[cfg(not(CONFIG_64BIT))]
- {
- let mut rem = 0;
+ _ => {
+ let mut rem = 0;

- // SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
- unsafe { bindings::div_s64_rem(self.as_nanos(), dividend, &mut rem) };
+ // SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
+ unsafe { bindings::div_s64_rem(self.as_nanos(), dividend, &mut rem) };

- Self {
- nanos: i64::from(rem),
+ Self {
+ nanos: i64::from(rem),
+ }
}
}
}

--
2.54.0