// SPDX-License-Identifier: GPL-2.012// Copyright (C) 2025 Google LLC.34//! Rust API for bitmap.5//!6//! C headers: [`include/linux/bitmap.h`](srctree/include/linux/bitmap.h).78use crate::alloc::{AllocError, Flags};9use crate::bindings;10#[cfg(not(CONFIG_RUST_BITMAP_HARDENED))]11use crate::pr_err;12use core::ptr::NonNull;1314const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize;1516/// Represents a C bitmap. Wraps underlying C bitmap API.17///18/// # Invariants19///20/// Must reference a `[c_ulong]` long enough to fit `data.len()` bits.21#[cfg_attr(CONFIG_64BIT, repr(align(8)))]22#[cfg_attr(not(CONFIG_64BIT), repr(align(4)))]23pub struct Bitmap {24data: [()],25}2627impl Bitmap {28/// Borrows a C bitmap.29///30/// # Safety31///32/// * `ptr` holds a non-null address of an initialized array of `unsigned long`33/// that is large enough to hold `nbits` bits.34/// * the array must not be freed for the lifetime of this [`Bitmap`]35/// * concurrent access only happens through atomic operations36pub unsafe fn from_raw<'a>(ptr: *const usize, nbits: usize) -> &'a Bitmap {37let data: *const [()] = core::ptr::slice_from_raw_parts(ptr.cast(), nbits);38// INVARIANT: `data` references an initialized array that can hold `nbits` bits.39// SAFETY:40// The caller guarantees that `data` (derived from `ptr` and `nbits`)41// points to a valid, initialized, and appropriately sized memory region42// that will not be freed for the lifetime 'a.43// We are casting `*const [()]` to `*const Bitmap`. The `Bitmap`44// struct is a ZST with a `data: [()]` field. This means its layout45// is compatible with a slice of `()`, and effectively it's a "thin pointer"46// (its size is 0 and alignment is 1). The `slice_from_raw_parts`47// function correctly encodes the length (number of bits, not elements)48// into the metadata of the fat pointer. Therefore, dereferencing this49// pointer as `&Bitmap` is safe given the caller's guarantees.50unsafe { &*(data as *const Bitmap) }51}5253/// Borrows a C bitmap exclusively.54///55/// # Safety56///57/// * `ptr` holds a non-null address of an initialized array of `unsigned long`58/// that is large enough to hold `nbits` bits.59/// * the array must not be freed for the lifetime of this [`Bitmap`]60/// * no concurrent access may happen.61pub unsafe fn from_raw_mut<'a>(ptr: *mut usize, nbits: usize) -> &'a mut Bitmap {62let data: *mut [()] = core::ptr::slice_from_raw_parts_mut(ptr.cast(), nbits);63// INVARIANT: `data` references an initialized array that can hold `nbits` bits.64// SAFETY:65// The caller guarantees that `data` (derived from `ptr` and `nbits`)66// points to a valid, initialized, and appropriately sized memory region67// that will not be freed for the lifetime 'a.68// Furthermore, the caller guarantees no concurrent access will happen,69// which upholds the exclusivity requirement for a mutable reference.70// Similar to `from_raw`, casting `*mut [()]` to `*mut Bitmap` is71// safe because `Bitmap` is a ZST with a `data: [()]` field,72// making its layout compatible with a slice of `()`.73unsafe { &mut *(data as *mut Bitmap) }74}7576/// Returns a raw pointer to the backing [`Bitmap`].77pub fn as_ptr(&self) -> *const usize {78core::ptr::from_ref::<Bitmap>(self).cast::<usize>()79}8081/// Returns a mutable raw pointer to the backing [`Bitmap`].82pub fn as_mut_ptr(&mut self) -> *mut usize {83core::ptr::from_mut::<Bitmap>(self).cast::<usize>()84}8586/// Returns length of this [`Bitmap`].87#[expect(clippy::len_without_is_empty)]88pub fn len(&self) -> usize {89self.data.len()90}91}9293/// Holds either a pointer to array of `unsigned long` or a small bitmap.94#[repr(C)]95union BitmapRepr {96bitmap: usize,97ptr: NonNull<usize>,98}99100macro_rules! bitmap_assert {101($cond:expr, $($arg:tt)+) => {102#[cfg(CONFIG_RUST_BITMAP_HARDENED)]103assert!($cond, $($arg)*);104}105}106107macro_rules! bitmap_assert_return {108($cond:expr, $($arg:tt)+) => {109#[cfg(CONFIG_RUST_BITMAP_HARDENED)]110assert!($cond, $($arg)*);111112#[cfg(not(CONFIG_RUST_BITMAP_HARDENED))]113if !($cond) {114pr_err!($($arg)*);115return116}117}118}119120/// Represents an owned bitmap.121///122/// Wraps underlying C bitmap API. See [`Bitmap`] for available123/// methods.124///125/// # Examples126///127/// Basic usage128///129/// ```130/// use kernel::alloc::flags::GFP_KERNEL;131/// use kernel::bitmap::BitmapVec;132///133/// let mut b = BitmapVec::new(16, GFP_KERNEL)?;134///135/// assert_eq!(16, b.len());136/// for i in 0..16 {137/// if i % 4 == 0 {138/// b.set_bit(i);139/// }140/// }141/// assert_eq!(Some(0), b.next_bit(0));142/// assert_eq!(Some(1), b.next_zero_bit(0));143/// assert_eq!(Some(4), b.next_bit(1));144/// assert_eq!(Some(5), b.next_zero_bit(4));145/// assert_eq!(Some(12), b.last_bit());146/// # Ok::<(), Error>(())147/// ```148///149/// # Invariants150///151/// * `nbits` is `<= i32::MAX` and never changes.152/// * if `nbits <= bindings::BITS_PER_LONG`, then `repr` is a `usize`.153/// * otherwise, `repr` holds a non-null pointer to an initialized154/// array of `unsigned long` that is large enough to hold `nbits` bits.155pub struct BitmapVec {156/// Representation of bitmap.157repr: BitmapRepr,158/// Length of this bitmap. Must be `<= i32::MAX`.159nbits: usize,160}161162impl core::ops::Deref for BitmapVec {163type Target = Bitmap;164165fn deref(&self) -> &Bitmap {166let ptr = if self.nbits <= BITS_PER_LONG {167// SAFETY: Bitmap is represented inline.168unsafe { core::ptr::addr_of!(self.repr.bitmap) }169} else {170// SAFETY: Bitmap is represented as array of `unsigned long`.171unsafe { self.repr.ptr.as_ptr() }172};173174// SAFETY: We got the right pointer and invariants of [`Bitmap`] hold.175// An inline bitmap is treated like an array with single element.176unsafe { Bitmap::from_raw(ptr, self.nbits) }177}178}179180impl core::ops::DerefMut for BitmapVec {181fn deref_mut(&mut self) -> &mut Bitmap {182let ptr = if self.nbits <= BITS_PER_LONG {183// SAFETY: Bitmap is represented inline.184unsafe { core::ptr::addr_of_mut!(self.repr.bitmap) }185} else {186// SAFETY: Bitmap is represented as array of `unsigned long`.187unsafe { self.repr.ptr.as_ptr() }188};189190// SAFETY: We got the right pointer and invariants of [`BitmapVec`] hold.191// An inline bitmap is treated like an array with single element.192unsafe { Bitmap::from_raw_mut(ptr, self.nbits) }193}194}195196/// Enable ownership transfer to other threads.197///198/// SAFETY: We own the underlying bitmap representation.199unsafe impl Send for BitmapVec {}200201/// Enable unsynchronized concurrent access to [`BitmapVec`] through shared references.202///203/// SAFETY: `deref()` will return a reference to a [`Bitmap`]. Its methods204/// take immutable references are either atomic or read-only.205unsafe impl Sync for BitmapVec {}206207impl Drop for BitmapVec {208fn drop(&mut self) {209if self.nbits <= BITS_PER_LONG {210return;211}212// SAFETY: `self.ptr` was returned by the C `bitmap_zalloc`.213//214// INVARIANT: there is no other use of the `self.ptr` after this215// call and the value is being dropped so the broken invariant is216// not observable on function exit.217unsafe { bindings::bitmap_free(self.repr.ptr.as_ptr()) };218}219}220221impl BitmapVec {222/// Constructs a new [`BitmapVec`].223///224/// Fails with [`AllocError`] when the [`BitmapVec`] could not be allocated. This225/// includes the case when `nbits` is greater than `i32::MAX`.226#[inline]227pub fn new(nbits: usize, flags: Flags) -> Result<Self, AllocError> {228if nbits <= BITS_PER_LONG {229return Ok(BitmapVec {230repr: BitmapRepr { bitmap: 0 },231nbits,232});233}234if nbits > i32::MAX.try_into().unwrap() {235return Err(AllocError);236}237let nbits_u32 = u32::try_from(nbits).unwrap();238// SAFETY: `BITS_PER_LONG < nbits` and `nbits <= i32::MAX`.239let ptr = unsafe { bindings::bitmap_zalloc(nbits_u32, flags.as_raw()) };240let ptr = NonNull::new(ptr).ok_or(AllocError)?;241// INVARIANT: `ptr` returned by C `bitmap_zalloc` and `nbits` checked.242Ok(BitmapVec {243repr: BitmapRepr { ptr },244nbits,245})246}247248/// Returns length of this [`Bitmap`].249#[allow(clippy::len_without_is_empty)]250#[inline]251pub fn len(&self) -> usize {252self.nbits253}254255/// Fills this `Bitmap` with random bits.256#[cfg(CONFIG_FIND_BIT_BENCHMARK_RUST)]257pub fn fill_random(&mut self) {258// SAFETY: `self.as_mut_ptr` points to either an array of the259// appropriate length or one usize.260unsafe {261bindings::get_random_bytes(262self.as_mut_ptr().cast::<ffi::c_void>(),263usize::div_ceil(self.nbits, bindings::BITS_PER_LONG as usize)264* bindings::BITS_PER_LONG as usize265/ 8,266);267}268}269}270271impl Bitmap {272/// Set bit with index `index`.273///274/// ATTENTION: `set_bit` is non-atomic, which differs from the naming275/// convention in C code. The corresponding C function is `__set_bit`.276///277/// If CONFIG_RUST_BITMAP_HARDENED is not enabled and `index` is greater than278/// or equal to `self.nbits`, does nothing.279///280/// # Panics281///282/// Panics if CONFIG_RUST_BITMAP_HARDENED is enabled and `index` is greater than283/// or equal to `self.nbits`.284#[inline]285pub fn set_bit(&mut self, index: usize) {286bitmap_assert_return!(287index < self.len(),288"Bit `index` must be < {}, was {}",289self.len(),290index291);292// SAFETY: Bit `index` is within bounds.293unsafe { bindings::__set_bit(index, self.as_mut_ptr()) };294}295296/// Set bit with index `index`, atomically.297///298/// This is a relaxed atomic operation (no implied memory barriers).299///300/// ATTENTION: The naming convention differs from C, where the corresponding301/// function is called `set_bit`.302///303/// If CONFIG_RUST_BITMAP_HARDENED is not enabled and `index` is greater than304/// or equal to `self.len()`, does nothing.305///306/// # Panics307///308/// Panics if CONFIG_RUST_BITMAP_HARDENED is enabled and `index` is greater than309/// or equal to `self.len()`.310#[inline]311pub fn set_bit_atomic(&self, index: usize) {312bitmap_assert_return!(313index < self.len(),314"Bit `index` must be < {}, was {}",315self.len(),316index317);318// SAFETY: `index` is within bounds and the caller has ensured that319// there is no mix of non-atomic and atomic operations.320unsafe { bindings::set_bit(index, self.as_ptr().cast_mut()) };321}322323/// Clear `index` bit.324///325/// ATTENTION: `clear_bit` is non-atomic, which differs from the naming326/// convention in C code. The corresponding C function is `__clear_bit`.327///328/// If CONFIG_RUST_BITMAP_HARDENED is not enabled and `index` is greater than329/// or equal to `self.len()`, does nothing.330///331/// # Panics332///333/// Panics if CONFIG_RUST_BITMAP_HARDENED is enabled and `index` is greater than334/// or equal to `self.len()`.335#[inline]336pub fn clear_bit(&mut self, index: usize) {337bitmap_assert_return!(338index < self.len(),339"Bit `index` must be < {}, was {}",340self.len(),341index342);343// SAFETY: `index` is within bounds.344unsafe { bindings::__clear_bit(index, self.as_mut_ptr()) };345}346347/// Clear `index` bit, atomically.348///349/// This is a relaxed atomic operation (no implied memory barriers).350///351/// ATTENTION: The naming convention differs from C, where the corresponding352/// function is called `clear_bit`.353///354/// If CONFIG_RUST_BITMAP_HARDENED is not enabled and `index` is greater than355/// or equal to `self.len()`, does nothing.356///357/// # Panics358///359/// Panics if CONFIG_RUST_BITMAP_HARDENED is enabled and `index` is greater than360/// or equal to `self.len()`.361#[inline]362pub fn clear_bit_atomic(&self, index: usize) {363bitmap_assert_return!(364index < self.len(),365"Bit `index` must be < {}, was {}",366self.len(),367index368);369// SAFETY: `index` is within bounds and the caller has ensured that370// there is no mix of non-atomic and atomic operations.371unsafe { bindings::clear_bit(index, self.as_ptr().cast_mut()) };372}373374/// Copy `src` into this [`Bitmap`] and set any remaining bits to zero.375///376/// # Examples377///378/// ```379/// use kernel::alloc::{AllocError, flags::GFP_KERNEL};380/// use kernel::bitmap::BitmapVec;381///382/// let mut long_bitmap = BitmapVec::new(256, GFP_KERNEL)?;383///384/// assert_eq!(None, long_bitmap.last_bit());385///386/// let mut short_bitmap = BitmapVec::new(16, GFP_KERNEL)?;387///388/// short_bitmap.set_bit(7);389/// long_bitmap.copy_and_extend(&short_bitmap);390/// assert_eq!(Some(7), long_bitmap.last_bit());391///392/// # Ok::<(), AllocError>(())393/// ```394#[inline]395pub fn copy_and_extend(&mut self, src: &Bitmap) {396let len = core::cmp::min(src.len(), self.len());397// SAFETY: access to `self` and `src` is within bounds.398unsafe {399bindings::bitmap_copy_and_extend(400self.as_mut_ptr(),401src.as_ptr(),402len as u32,403self.len() as u32,404)405};406}407408/// Finds last set bit.409///410/// # Examples411///412/// ```413/// use kernel::alloc::{AllocError, flags::GFP_KERNEL};414/// use kernel::bitmap::BitmapVec;415///416/// let bitmap = BitmapVec::new(64, GFP_KERNEL)?;417///418/// match bitmap.last_bit() {419/// Some(idx) => {420/// pr_info!("The last bit has index {idx}.\n");421/// }422/// None => {423/// pr_info!("All bits in this bitmap are 0.\n");424/// }425/// }426/// # Ok::<(), AllocError>(())427/// ```428#[inline]429pub fn last_bit(&self) -> Option<usize> {430// SAFETY: `_find_next_bit` access is within bounds due to invariant.431let index = unsafe { bindings::_find_last_bit(self.as_ptr(), self.len()) };432if index >= self.len() {433None434} else {435Some(index)436}437}438439/// Finds next set bit, starting from `start`.440///441/// Returns `None` if `start` is greater or equal to `self.nbits`.442#[inline]443pub fn next_bit(&self, start: usize) -> Option<usize> {444bitmap_assert!(445start < self.len(),446"`start` must be < {} was {}",447self.len(),448start449);450// SAFETY: `_find_next_bit` tolerates out-of-bounds arguments and returns a451// value larger than or equal to `self.len()` in that case.452let index = unsafe { bindings::_find_next_bit(self.as_ptr(), self.len(), start) };453if index >= self.len() {454None455} else {456Some(index)457}458}459460/// Finds next zero bit, starting from `start`.461/// Returns `None` if `start` is greater than or equal to `self.len()`.462#[inline]463pub fn next_zero_bit(&self, start: usize) -> Option<usize> {464bitmap_assert!(465start < self.len(),466"`start` must be < {} was {}",467self.len(),468start469);470// SAFETY: `_find_next_zero_bit` tolerates out-of-bounds arguments and returns a471// value larger than or equal to `self.len()` in that case.472let index = unsafe { bindings::_find_next_zero_bit(self.as_ptr(), self.len(), start) };473if index >= self.len() {474None475} else {476Some(index)477}478}479}480481use macros::kunit_tests;482483#[kunit_tests(rust_kernel_bitmap)]484mod tests {485use super::*;486use kernel::alloc::flags::GFP_KERNEL;487488#[test]489fn bitmap_borrow() {490let fake_bitmap: [usize; 2] = [0, 0];491// SAFETY: `fake_c_bitmap` is an array of expected length.492let b = unsafe { Bitmap::from_raw(fake_bitmap.as_ptr(), 2 * BITS_PER_LONG) };493assert_eq!(2 * BITS_PER_LONG, b.len());494assert_eq!(None, b.next_bit(0));495}496497#[test]498fn bitmap_copy() {499let fake_bitmap: usize = 0xFF;500// SAFETY: `fake_c_bitmap` can be used as one-element array of expected length.501let b = unsafe { Bitmap::from_raw(core::ptr::addr_of!(fake_bitmap), 8) };502assert_eq!(8, b.len());503assert_eq!(None, b.next_zero_bit(0));504}505506#[test]507fn bitmap_vec_new() -> Result<(), AllocError> {508let b = BitmapVec::new(0, GFP_KERNEL)?;509assert_eq!(0, b.len());510511let b = BitmapVec::new(3, GFP_KERNEL)?;512assert_eq!(3, b.len());513514let b = BitmapVec::new(1024, GFP_KERNEL)?;515assert_eq!(1024, b.len());516517// Requesting too large values results in [`AllocError`].518let res = BitmapVec::new(1 << 31, GFP_KERNEL);519assert!(res.is_err());520Ok(())521}522523#[test]524fn bitmap_set_clear_find() -> Result<(), AllocError> {525let mut b = BitmapVec::new(128, GFP_KERNEL)?;526527// Zero-initialized528assert_eq!(None, b.next_bit(0));529assert_eq!(Some(0), b.next_zero_bit(0));530assert_eq!(None, b.last_bit());531532b.set_bit(17);533534assert_eq!(Some(17), b.next_bit(0));535assert_eq!(Some(17), b.next_bit(17));536assert_eq!(None, b.next_bit(18));537assert_eq!(Some(17), b.last_bit());538539b.set_bit(107);540541assert_eq!(Some(17), b.next_bit(0));542assert_eq!(Some(17), b.next_bit(17));543assert_eq!(Some(107), b.next_bit(18));544assert_eq!(Some(107), b.last_bit());545546b.clear_bit(17);547548assert_eq!(Some(107), b.next_bit(0));549assert_eq!(Some(107), b.last_bit());550Ok(())551}552553#[test]554fn owned_bitmap_out_of_bounds() -> Result<(), AllocError> {555// TODO: Kunit #[test]s do not support `cfg` yet,556// so we add it here in the body.557#[cfg(not(CONFIG_RUST_BITMAP_HARDENED))]558{559let mut b = BitmapVec::new(128, GFP_KERNEL)?;560b.set_bit(2048);561b.set_bit_atomic(2048);562b.clear_bit(2048);563b.clear_bit_atomic(2048);564assert_eq!(None, b.next_bit(2048));565assert_eq!(None, b.next_zero_bit(2048));566assert_eq!(None, b.last_bit());567}568Ok(())569}570571// TODO: uncomment once kunit supports [should_panic] and `cfg`.572// #[cfg(CONFIG_RUST_BITMAP_HARDENED)]573// #[test]574// #[should_panic]575// fn owned_bitmap_out_of_bounds() -> Result<(), AllocError> {576// let mut b = BitmapVec::new(128, GFP_KERNEL)?;577//578// b.set_bit(2048);579// }580581#[test]582fn bitmap_copy_and_extend() -> Result<(), AllocError> {583let mut long_bitmap = BitmapVec::new(256, GFP_KERNEL)?;584585long_bitmap.set_bit(3);586long_bitmap.set_bit(200);587588let mut short_bitmap = BitmapVec::new(32, GFP_KERNEL)?;589590short_bitmap.set_bit(17);591592long_bitmap.copy_and_extend(&short_bitmap);593594// Previous bits have been cleared.595assert_eq!(Some(17), long_bitmap.next_bit(0));596assert_eq!(Some(17), long_bitmap.last_bit());597Ok(())598}599}600601602