// SPDX-License-Identifier: GPL-2.012//! CPU Mask abstractions.3//!4//! C header: [`include/linux/cpumask.h`](srctree/include/linux/cpumask.h)56use crate::{7alloc::{AllocError, Flags},8cpu::CpuId,9prelude::*,10types::Opaque,11};1213#[cfg(CONFIG_CPUMASK_OFFSTACK)]14use core::ptr::{self, NonNull};1516use core::ops::{Deref, DerefMut};1718/// A CPU Mask.19///20/// Rust abstraction for the C `struct cpumask`.21///22/// # Invariants23///24/// A [`Cpumask`] instance always corresponds to a valid C `struct cpumask`.25///26/// The callers must ensure that the `struct cpumask` is valid for access and27/// remains valid for the lifetime of the returned reference.28///29/// # Examples30///31/// The following example demonstrates how to update a [`Cpumask`].32///33/// ```34/// use kernel::bindings;35/// use kernel::cpu::CpuId;36/// use kernel::cpumask::Cpumask;37///38/// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: CpuId, clear_cpu: CpuId) {39/// // SAFETY: The `ptr` is valid for writing and remains valid for the lifetime of the40/// // returned reference.41/// let mask = unsafe { Cpumask::as_mut_ref(ptr) };42///43/// mask.set(set_cpu);44/// mask.clear(clear_cpu);45/// }46/// ```47#[repr(transparent)]48pub struct Cpumask(Opaque<bindings::cpumask>);4950impl Cpumask {51/// Creates a mutable reference to an existing `struct cpumask` pointer.52///53/// # Safety54///55/// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime56/// of the returned reference.57pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask) -> &'a mut Self {58// SAFETY: Guaranteed by the safety requirements of the function.59//60// INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the61// lifetime of the returned reference.62unsafe { &mut *ptr.cast() }63}6465/// Creates a reference to an existing `struct cpumask` pointer.66///67/// # Safety68///69/// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime70/// of the returned reference.71pub unsafe fn as_ref<'a>(ptr: *const bindings::cpumask) -> &'a Self {72// SAFETY: Guaranteed by the safety requirements of the function.73//74// INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the75// lifetime of the returned reference.76unsafe { &*ptr.cast() }77}7879/// Obtain the raw `struct cpumask` pointer.80pub fn as_raw(&self) -> *mut bindings::cpumask {81let this: *const Self = self;82this.cast_mut().cast()83}8485/// Set `cpu` in the cpumask.86///87/// ATTENTION: Contrary to C, this Rust `set()` method is non-atomic.88/// This mismatches kernel naming convention and corresponds to the C89/// function `__cpumask_set_cpu()`.90#[inline]91pub fn set(&mut self, cpu: CpuId) {92// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `__cpumask_set_cpu`.93unsafe { bindings::__cpumask_set_cpu(u32::from(cpu), self.as_raw()) };94}9596/// Clear `cpu` in the cpumask.97///98/// ATTENTION: Contrary to C, this Rust `clear()` method is non-atomic.99/// This mismatches kernel naming convention and corresponds to the C100/// function `__cpumask_clear_cpu()`.101#[inline]102pub fn clear(&mut self, cpu: CpuId) {103// SAFETY: By the type invariant, `self.as_raw` is a valid argument to104// `__cpumask_clear_cpu`.105unsafe { bindings::__cpumask_clear_cpu(i32::from(cpu), self.as_raw()) };106}107108/// Test `cpu` in the cpumask.109///110/// Equivalent to the kernel's `cpumask_test_cpu` API.111#[inline]112pub fn test(&self, cpu: CpuId) -> bool {113// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_test_cpu`.114unsafe { bindings::cpumask_test_cpu(i32::from(cpu), self.as_raw()) }115}116117/// Set all CPUs in the cpumask.118///119/// Equivalent to the kernel's `cpumask_setall` API.120#[inline]121pub fn setall(&mut self) {122// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_setall`.123unsafe { bindings::cpumask_setall(self.as_raw()) };124}125126/// Checks if cpumask is empty.127///128/// Equivalent to the kernel's `cpumask_empty` API.129#[inline]130pub fn empty(&self) -> bool {131// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_empty`.132unsafe { bindings::cpumask_empty(self.as_raw()) }133}134135/// Checks if cpumask is full.136///137/// Equivalent to the kernel's `cpumask_full` API.138#[inline]139pub fn full(&self) -> bool {140// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_full`.141unsafe { bindings::cpumask_full(self.as_raw()) }142}143144/// Get weight of the cpumask.145///146/// Equivalent to the kernel's `cpumask_weight` API.147#[inline]148pub fn weight(&self) -> u32 {149// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_weight`.150unsafe { bindings::cpumask_weight(self.as_raw()) }151}152153/// Copy cpumask.154///155/// Equivalent to the kernel's `cpumask_copy` API.156#[inline]157pub fn copy(&self, dstp: &mut Self) {158// SAFETY: By the type invariant, `Self::as_raw` is a valid argument to `cpumask_copy`.159unsafe { bindings::cpumask_copy(dstp.as_raw(), self.as_raw()) };160}161}162163/// A CPU Mask pointer.164///165/// Rust abstraction for the C `struct cpumask_var_t`.166///167/// # Invariants168///169/// A [`CpumaskVar`] instance always corresponds to a valid C `struct cpumask_var_t`.170///171/// The callers must ensure that the `struct cpumask_var_t` is valid for access and remains valid172/// for the lifetime of [`CpumaskVar`].173///174/// # Examples175///176/// The following example demonstrates how to create and update a [`CpumaskVar`].177///178/// ```179/// use kernel::cpu::CpuId;180/// use kernel::cpumask::CpumaskVar;181///182/// let mut mask = CpumaskVar::new_zero(GFP_KERNEL).unwrap();183///184/// assert!(mask.empty());185/// let mut count = 0;186///187/// let cpu2 = CpuId::from_u32(2);188/// if let Some(cpu) = cpu2 {189/// mask.set(cpu);190/// assert!(mask.test(cpu));191/// count += 1;192/// }193///194/// let cpu3 = CpuId::from_u32(3);195/// if let Some(cpu) = cpu3 {196/// mask.set(cpu);197/// assert!(mask.test(cpu));198/// count += 1;199/// }200///201/// assert_eq!(mask.weight(), count);202///203/// let mask2 = CpumaskVar::try_clone(&mask).unwrap();204///205/// if let Some(cpu) = cpu2 {206/// assert!(mask2.test(cpu));207/// }208///209/// if let Some(cpu) = cpu3 {210/// assert!(mask2.test(cpu));211/// }212/// assert_eq!(mask2.weight(), count);213/// ```214#[repr(transparent)]215pub struct CpumaskVar {216#[cfg(CONFIG_CPUMASK_OFFSTACK)]217ptr: NonNull<Cpumask>,218#[cfg(not(CONFIG_CPUMASK_OFFSTACK))]219mask: Cpumask,220}221222impl CpumaskVar {223/// Creates a zero-initialized instance of the [`CpumaskVar`].224pub fn new_zero(_flags: Flags) -> Result<Self, AllocError> {225Ok(Self {226#[cfg(CONFIG_CPUMASK_OFFSTACK)]227ptr: {228let mut ptr: *mut bindings::cpumask = ptr::null_mut();229230// SAFETY: It is safe to call this method as the reference to `ptr` is valid.231//232// INVARIANT: The associated memory is freed when the `CpumaskVar` goes out of233// scope.234unsafe { bindings::zalloc_cpumask_var(&mut ptr, _flags.as_raw()) };235NonNull::new(ptr.cast()).ok_or(AllocError)?236},237238#[cfg(not(CONFIG_CPUMASK_OFFSTACK))]239mask: Cpumask(Opaque::zeroed()),240})241}242243/// Creates an instance of the [`CpumaskVar`].244///245/// # Safety246///247/// The caller must ensure that the returned [`CpumaskVar`] is properly initialized before248/// getting used.249pub unsafe fn new(_flags: Flags) -> Result<Self, AllocError> {250Ok(Self {251#[cfg(CONFIG_CPUMASK_OFFSTACK)]252ptr: {253let mut ptr: *mut bindings::cpumask = ptr::null_mut();254255// SAFETY: It is safe to call this method as the reference to `ptr` is valid.256//257// INVARIANT: The associated memory is freed when the `CpumaskVar` goes out of258// scope.259unsafe { bindings::alloc_cpumask_var(&mut ptr, _flags.as_raw()) };260NonNull::new(ptr.cast()).ok_or(AllocError)?261},262#[cfg(not(CONFIG_CPUMASK_OFFSTACK))]263mask: Cpumask(Opaque::uninit()),264})265}266267/// Creates a mutable reference to an existing `struct cpumask_var_t` pointer.268///269/// # Safety270///271/// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime272/// of the returned reference.273pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self {274// SAFETY: Guaranteed by the safety requirements of the function.275//276// INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the277// lifetime of the returned reference.278unsafe { &mut *ptr.cast() }279}280281/// Creates a reference to an existing `struct cpumask_var_t` pointer.282///283/// # Safety284///285/// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime286/// of the returned reference.287pub unsafe fn from_raw<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self {288// SAFETY: Guaranteed by the safety requirements of the function.289//290// INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the291// lifetime of the returned reference.292unsafe { &*ptr.cast() }293}294295/// Clones cpumask.296pub fn try_clone(cpumask: &Cpumask) -> Result<Self> {297// SAFETY: The returned cpumask_var is initialized right after this call.298let mut cpumask_var = unsafe { Self::new(GFP_KERNEL) }?;299300cpumask.copy(&mut cpumask_var);301Ok(cpumask_var)302}303}304305// Make [`CpumaskVar`] behave like a pointer to [`Cpumask`].306impl Deref for CpumaskVar {307type Target = Cpumask;308309#[cfg(CONFIG_CPUMASK_OFFSTACK)]310fn deref(&self) -> &Self::Target {311// SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.312unsafe { &*self.ptr.as_ptr() }313}314315#[cfg(not(CONFIG_CPUMASK_OFFSTACK))]316fn deref(&self) -> &Self::Target {317&self.mask318}319}320321impl DerefMut for CpumaskVar {322#[cfg(CONFIG_CPUMASK_OFFSTACK)]323fn deref_mut(&mut self) -> &mut Cpumask {324// SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.325unsafe { self.ptr.as_mut() }326}327328#[cfg(not(CONFIG_CPUMASK_OFFSTACK))]329fn deref_mut(&mut self) -> &mut Cpumask {330&mut self.mask331}332}333334impl Drop for CpumaskVar {335fn drop(&mut self) {336#[cfg(CONFIG_CPUMASK_OFFSTACK)]337// SAFETY: By the type invariant, `self.as_raw` is a valid argument to `free_cpumask_var`.338unsafe {339bindings::free_cpumask_var(self.as_raw())340};341}342}343344345