Files
Linus Torvalds 12d5fc96eb Merge tag 'rust-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust updates from Miguel Ojeda:
 "Toolchain and infrastructure:

   - Update vendored 'zerocopy' crate to v0.8.62 (released 2026-10-08).

     This update advances 8 releases, with 3 of them carrying most of
     the changes. It contains new features as well as fixes. However,
     almost nothing has changed that requires updates on our side (a
     move of our non-ASCII change and the addition of an SPDX license
     identifier).

   - Generate Rust KUnit test suites for doctests reusing the
     '#[kunit_tests]' and '#[test]' attributes instead of C FFI
     functions, which allows to remove the generated C glue file.

     Relatedly, simplify 'kunit_assert!' by using 'file!()' and
     'line!()' inside (which doctests override as needed), which allows
     to remove the 'file' helper and 'CONFIG_RUSTC_HAS_SPAN_FILE'.

   - Trim the function names in doctests generated by 'rustdoc' < 1.95.0
     when building with 'O=', which were not reproducible.

   - Fix the 'VM_MAYSHARE' value in the generated bindings and its
     blocklist entry, due to typos.

   - Build 'core' with '--cfg no_io_statics' to ensure 'core' does not
     introduce any use of 'core::sync::atomic' into the kernel image
     since upstream Rust is moving 'std::io::Error' into 'core', which
     uses a global atomic pointer.

     Upstream Rust merged a PR to add a test checking that builds of
     'core' are warning-free with that 'cfg' enabled.

   - Enable the unstable 'proc_macro_span' feature in 'proc-macro2',
     which provides 'Span::join' and thus improves the quality of the
     diagnostics of all our procedural macros, notably 'pin-init'. This
     is only used for producing diagnostics, thus there is no hard
     reliance on the feature.

   - Globally allow 'clippy::comparison_chain', since its suggestions
     are not always ideal and upstream downgraded it to 'pedantic' too.

  'kernel' crate:

   - New 'mem' module: add the 'Align<N>' zero-sized type so that
     alignment can be specified via const generics ('repr(align(...))'
     only works with integer literals), e.g.:

         const N: usize = 128;

         struct S {
             _align: Align<N>,
         }

         assert_eq!(align_of::<S>(), N);

   - New 'ratelimit' module: add the 'Ratelimit' abstraction for 'struct
     ratelimit_state' and, based on it, the 'pr_*_ratelimited!' printing
     macros, which can be used for printing that may be triggered by
     userspace.

     In addition, convert Rust Binder to use them.

   - 'sync' module: to construct a global 'struct ratelimit_state', add
     a 'const' constructor for 'raw_spinlock_t'.

     In addition, move the lockdep types into a new 'sync::lockdep'
     submodule, since there were starting to be too many of them.

   - 'num' module: add the 'cv!' macro to create constant values ("cv")
     from an integer constant expression, with validity checked at
     compile time, inferring the target type from the context. It works
     for any type that implements the new 'FromConst' trait, e.g.:

         let a: Alignment = cv!(4096);
         let b: Bounded<u32, 4> = cv!(15);

         // Any integer constant expression works, not only literals.
         let m: NonZero<usize> = cv!(usize::MAX);

         // Checked narrowing, including in `const` items.
         const SMALL: u8 = cv!(200u32);

         // The target type can be given explicitly.
         let e = cv!(200u32 => u8);

         // With an explicit primitive target, the expression can use
         // generic parameters.
         const fn as_u64<const KEY: u16>() -> u64 {
             cv!(KEY => u64)
         }

     This avoids the verbose turbofish syntax which disincentivized
     using these types at interface boundaries (e.g.
     'Alignment::new::<8>()').

   - 'alloc' module:

       - Allow different error types in 'KBox::pin_slice()', enabling use
         of infallible initializers.

       - Add 'NumaNode::id()' accessor to retrieve the underlying NUMA
         node identifier.

   - 'time' module:

       - Add 'Delta::to_jiffies_timeout()' for use in timeout arguments.

       - Add 'Delta::as_jiffies_unsigned()'.

       - Make 'Delta::ZERO' generic over the time unit.

       - Warn and assert when passing out-of-range inputs to 'fsleep' and
         'udelay'.

       - Rename 'ClockSource' to 'ClockId' to better align with naming
         conventions in C kernel.

       - Make 'CONFIG_HZ' value available as 'bindings::HZ'.

       - Add implementation detail documentation for 'HrTimer'.

   - 'bitmap' module:

       - Add contiguous area operations ('next_zero_area{,_off}', 'set'
         and 'clear'), with extra checks compared to the underlying C
         code, plus additional ones under 'CONFIG_RUST_BITMAP_HARDENED'.
         It includes tests demonstrating the edge cases.

       - Restrict bitmap length to at most 'i32::MAX', matching
         'BitmapVec::MAX_LEN' and simplifying a few things. This also
         fixes 'u32' casts truncating in 'copy_and_extend', which could
         otherwise lead to OOB writes.

   - 'bug' module:

       - Fix 'warn_on!' on UML which called 'warn_slowpath_fmt()' with
         the wrong arguments; and fix its '// SAFETY:' comment too.

       - Add a KUnit test for 'warn_on!'.

   - 'id_pool' module: add contiguous ID reservation via the new
     'reserve_ids' and 'release_ids' methods, built on top of the new
     bitmap area operations.

   - 'sizes' module: add the sub-1K size constants ('SZ_1' to 'SZ_512')
     and implement 'SizeConstants' for 'Alignment', so that one can
     write e.g. 'Alignment::SZ_8'.

  'macros' crate:

   - Add '#[optional]' attribute for optional methods in '#[vtable]' to
     replace the 'build_error!(VTABLE_DEFAULT_ERROR)' boilerplate, e.g.:

         #[vtable]
         pub trait Operations: Sized {
             #[optional]
             fn f(&self) -> Result;
         }

     In addition, apply it to miscdevice and hide generated 'HAS_'
     constants for required methods.

   - Allow non-ASCII characters in the 'authors' field of the 'module!'
     macro, which was unintentionally restricted when multiple authors
     support was introduced.

  'pin-init' crate:

    [ Extra context from Gary's pull request:
       "This is a cycle packed with feature updates. Two of the most
        anticipated features, tuple struct support and safe self
        reference creation, has been included in this pull request.

        Safe self reference is a big one and is pushed a bit late in the
        cycle. The initial plan was to include a minimum subset for this
        cycle because I was worried about potential soundness issues;
        however during Plumbers it was agreed that the features should be
        upstreamed at once. This is because the initial users (Nova,
        JobQueue) would all need the advanced features, so it is better
        to ensure that the feature get put into use for real, and it can
        iterate with users, rather than being fully designed on paper.
        The existing safety checks are already very comprehensive, and
        Benno and I are confident that if new ones are discovered, it
        wouldn't affect the overall design.

        That said, the the usage of the advanced features (invariance,
        existential lifetime) shall be limited to the pre-agreed users
        only, so even in case where the feature needs to be reworked, the
        blast radius is limited.

        Another theme in this cycle is to improve the developer
        experience when things are used wrongly. A lot of work has been
        done to use proper spans from user-provided tokens so error
        message point to things that cause them. Many common misuse
        scenarios also gain additional custom diagnostics." ]

   - User visible changes:

       - Support tuple structs.

       - Allow safe creation of self references.

       - Vastly improve diagnostics for common misuse scenarios.

   - Other changes:

       - Use 'mixed_site' hygiene consistently.

  'MAINTAINERS':

   - Add 'RUST [BUG]' entry for the Rust 'bug' module (i.e. 'warn_on!'),
     which will be maintained by FUJITA Tomonori -- thank you!

   - Add Alice Ryhl as co-maintainer for 'Rust [ALLOC]'.

  And some other fixes, cleanups and improvements.

* tag 'rust-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (91 commits)
  rust: zerocopy: update to v0.8.62
  rust: zerocopy: fix link to upstream `README.md`
  rust: id_pool: add contiguous ID reservation
  rust: bitmap: add contiguous area operations
  rust: sizes: implement SizeConstants for Alignment
  rust: sizes: add sub-1K size constants
  rust: bitmap: restrict bitmap length to at most i32::MAX
  rust: bitmap: use function-level cfg on kunit test
  rust: num: add cv! macro to create values from constant expressions
  rust: bug: update the SAFETY comment for warn_slowpath_fmt() on UML
  rust: time: add Delta::as_jiffies_unsigned()
  rust: time: make Delta::ZERO generic over the time unit
  rust_binder: use pr_*_ratelimited! for printing
  rust: add pr_*_ratelimited! macros for printing
  rust: sync: add const constructor for raw_spinlock_t
  rust: sync: move lockdep types to rust/kernel/sync/lockdep.rs
  rust: pin-init: internal: suppress `explicit_outlives_requirements`
  MAINTAINERS: add entry for the Rust `bug` module
  rust: pin-init: internal: pin_data: support existential lifetimes
  rust: pin-init: internal: pin_data: support shared projection
  ...
2026-10-21 10:20:36 -10:00

341 lines
10 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.
//! Rust API for an ID pool backed by a [`BitmapVec`].
use core::{
num::NonZero,
ops::Range, //
};
use crate::alloc::{AllocError, Flags};
use crate::bitmap::BitmapVec;
use crate::ptr::Alignment;
/// Represents a dynamic ID pool backed by a [`BitmapVec`].
///
/// Clients acquire and release IDs from unset bits in a bitmap.
///
/// The capacity of the ID pool may be adjusted by users as
/// needed. The API supports the scenario where users need precise control
/// over the time of allocation of a new backing bitmap, which may require
/// release of spinlock.
/// Due to concurrent updates, all operations are re-verified to determine
/// if the grow or shrink is sill valid.
///
/// # Examples
///
/// Basic usage
///
/// ```
/// use kernel::alloc::AllocError;
/// use kernel::id_pool::{IdPool, UnusedId};
///
/// let mut pool = IdPool::with_capacity(64, GFP_KERNEL)?;
/// for i in 0..64 {
/// assert_eq!(i, pool.find_unused_id(i).ok_or(ENOSPC)?.acquire());
/// }
///
/// pool.release_id(23);
/// assert_eq!(23, pool.find_unused_id(0).ok_or(ENOSPC)?.acquire());
///
/// assert!(pool.find_unused_id(0).is_none()); // time to realloc.
/// let resizer = pool.grow_request().ok_or(ENOSPC)?.realloc(GFP_KERNEL)?;
/// pool.grow(resizer);
///
/// assert_eq!(pool.find_unused_id(0).ok_or(ENOSPC)?.acquire(), 64);
/// # Ok::<(), Error>(())
/// ```
///
/// Releasing spinlock to grow the pool
///
/// ```no_run
/// use kernel::alloc::{AllocError, flags::GFP_KERNEL};
/// use kernel::sync::{new_spinlock, SpinLock};
/// use kernel::id_pool::IdPool;
///
/// fn get_id_maybe_realloc(guarded_pool: &SpinLock<IdPool>) -> Result<usize, AllocError> {
/// let mut pool = guarded_pool.lock();
/// loop {
/// match pool.find_unused_id(0) {
/// Some(index) => return Ok(index.acquire()),
/// None => {
/// let alloc_request = pool.grow_request();
/// drop(pool);
/// let resizer = alloc_request.ok_or(AllocError)?.realloc(GFP_KERNEL)?;
/// pool = guarded_pool.lock();
/// pool.grow(resizer)
/// }
/// }
/// }
/// }
/// ```
pub struct IdPool {
map: BitmapVec,
}
/// Indicates that an [`IdPool`] should change to a new target size.
pub struct ReallocRequest {
num_ids: usize,
}
/// Contains a [`BitmapVec`] of a size suitable for reallocating [`IdPool`].
pub struct PoolResizer {
new: BitmapVec,
}
impl ReallocRequest {
/// Allocates a new backing [`BitmapVec`] for [`IdPool`].
///
/// This method only prepares reallocation and does not complete it.
/// Reallocation will complete after passing the [`PoolResizer`] to the
/// [`IdPool::grow`] or [`IdPool::shrink`] operation, which will check
/// that reallocation still makes sense.
pub fn realloc(&self, flags: Flags) -> Result<PoolResizer, AllocError> {
let new = BitmapVec::new(self.num_ids, flags)?;
Ok(PoolResizer { new })
}
}
impl IdPool {
/// Constructs a new [`IdPool`].
///
/// The pool will have a capacity of [`MAX_INLINE_LEN`].
///
/// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN
#[inline]
pub fn new() -> Self {
Self {
map: BitmapVec::new_inline(),
}
}
/// Constructs a new [`IdPool`] with space for a specific number of bits.
///
/// A capacity below [`MAX_INLINE_LEN`] is adjusted to [`MAX_INLINE_LEN`].
///
/// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN
#[inline]
pub fn with_capacity(num_ids: usize, flags: Flags) -> Result<Self, AllocError> {
let num_ids = usize::max(num_ids, BitmapVec::MAX_INLINE_LEN);
let map = BitmapVec::new(num_ids, flags)?;
Ok(Self { map })
}
/// Returns how many IDs this pool can currently have.
#[inline]
pub fn capacity(&self) -> usize {
self.map.len()
}
/// Returns a [`ReallocRequest`] if the [`IdPool`] can be shrunk, [`None`] otherwise.
///
/// The capacity of an [`IdPool`] cannot be shrunk below [`MAX_INLINE_LEN`].
///
/// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN
///
/// # Examples
///
/// ```
/// use kernel::{
/// alloc::AllocError,
/// bitmap::BitmapVec,
/// id_pool::{
/// IdPool,
/// ReallocRequest,
/// },
/// };
///
/// let mut pool = IdPool::with_capacity(1024, GFP_KERNEL)?;
/// let alloc_request = pool.shrink_request().ok_or(AllocError)?;
/// let resizer = alloc_request.realloc(GFP_KERNEL)?;
/// pool.shrink(resizer);
/// assert_eq!(pool.capacity(), BitmapVec::MAX_INLINE_LEN);
/// # Ok::<(), AllocError>(())
/// ```
#[inline]
pub fn shrink_request(&self) -> Option<ReallocRequest> {
let cap = self.capacity();
// Shrinking below `MAX_INLINE_LEN` is never possible.
if cap <= BitmapVec::MAX_INLINE_LEN {
return None;
}
// Determine if the bitmap can shrink based on the position of
// its last set bit. If the bit is within the first quarter of
// the bitmap then shrinking is possible. In this case, the
// bitmap should shrink to half its current size.
let Some(bit) = self.map.last_bit() else {
return Some(ReallocRequest {
num_ids: BitmapVec::MAX_INLINE_LEN,
});
};
if bit >= (cap / 4) {
return None;
}
let num_ids = usize::max(BitmapVec::MAX_INLINE_LEN, cap / 2);
Some(ReallocRequest { num_ids })
}
/// Shrinks pool by using a new [`BitmapVec`], if still possible.
#[inline]
pub fn shrink(&mut self, mut resizer: PoolResizer) {
// Between request to shrink that led to allocation of `resizer` and now,
// bits may have changed.
// Verify that shrinking is still possible. In case shrinking to
// the size of `resizer` is no longer possible, do nothing,
// drop `resizer` and move on.
let Some(updated) = self.shrink_request() else {
return;
};
if updated.num_ids > resizer.new.len() {
return;
}
resizer.new.copy_and_extend(&self.map);
self.map = resizer.new;
}
/// Returns a [`ReallocRequest`] for growing this [`IdPool`], if possible.
///
/// The capacity of an [`IdPool`] cannot be grown above [`MAX_LEN`].
///
/// [`MAX_LEN`]: BitmapVec::MAX_LEN
#[inline]
pub fn grow_request(&self) -> Option<ReallocRequest> {
let num_ids = self.capacity() * 2;
if num_ids > BitmapVec::MAX_LEN {
return None;
}
Some(ReallocRequest { num_ids })
}
/// Grows pool by using a new [`BitmapVec`], if still necessary.
///
/// The `resizer` arguments has to be obtained by calling [`Self::grow_request`]
/// on this object and performing a [`ReallocRequest::realloc`].
#[inline]
pub fn grow(&mut self, mut resizer: PoolResizer) {
// Between request to grow that led to allocation of `resizer` and now,
// another thread may have already grown the capacity.
// In this case, do nothing, drop `resizer` and move on.
if resizer.new.len() <= self.capacity() {
return;
}
resizer.new.copy_and_extend(&self.map);
self.map = resizer.new;
}
/// Finds an unused ID in the bitmap.
///
/// Upon success, returns its index. Otherwise, returns [`None`]
/// to indicate that a [`Self::grow_request`] is needed. `offset` must be
/// within bounds.
///
/// # Panics
///
/// Panics if `CONFIG_RUST_BITMAP_HARDENED` is enabled and `offset` is out
/// of bounds.
#[inline]
#[must_use]
pub fn find_unused_id(&mut self, offset: usize) -> Option<UnusedId<'_>> {
// INVARIANT: `next_zero_bit()` returns None or an integer less than `map.len()`
Some(UnusedId {
id: self.map.next_zero_bit(offset)?,
pool: self,
})
}
/// Releases an ID.
///
/// The `id` must be within bounds.
///
/// # Panics
///
/// Panics if `CONFIG_RUST_BITMAP_HARDENED` is enabled and `id` is out of
/// bounds.
#[inline]
pub fn release_id(&mut self, id: usize) {
self.map.clear_bit(id);
}
/// Reserves a contiguous area of `count` IDs at or after `offset`.
///
/// The start of the returned area is a multiple of `align`.
///
/// Returns the reserved range upon success, or [`None`] if no such area could be found.
#[inline]
#[must_use]
pub fn reserve_ids(
&mut self,
offset: usize,
count: NonZero<usize>,
align: Alignment,
) -> Option<Range<usize>> {
let start = self.map.next_zero_area(offset, count, align)?;
self.map.set(start, count);
Some(start..start + count.get())
}
/// Releases a contiguous area of IDs.
#[inline]
pub fn release_ids(&mut self, range: &Range<usize>) {
if let Some(nbits) = NonZero::new(range.len()) {
self.map.clear(range.start, nbits);
}
}
}
/// Represents an unused id in an [`IdPool`].
///
/// # Invariants
///
/// The value of `id` is less than `pool.map.len()`.
pub struct UnusedId<'pool> {
id: usize,
pool: &'pool mut IdPool,
}
impl<'pool> UnusedId<'pool> {
/// Get the unused id as an usize.
///
/// Be aware that the id has not yet been acquired in the pool. The
/// [`acquire`] method must be called to prevent others from taking the id.
///
/// [`acquire`]: UnusedId::acquire()
#[inline]
#[must_use]
pub fn as_usize(&self) -> usize {
self.id
}
/// Get the unused id as an u32.
///
/// Be aware that the id has not yet been acquired in the pool. The
/// [`acquire`] method must be called to prevent others from taking the id.
///
/// [`acquire`]: UnusedId::acquire()
#[inline]
#[must_use]
pub fn as_u32(&self) -> u32 {
// CAST: By the type invariants:
// `self.id < pool.map.len() <= BitmapVec::MAX_LEN = i32::MAX`.
self.id as u32
}
/// Acquire the unused id.
#[inline]
pub fn acquire(self) -> usize {
self.pool.map.set_bit(self.id);
self.id
}
}
impl Default for IdPool {
#[inline]
fn default() -> Self {
Self::new()
}
}