kernel/
cpumask.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! CPU Mask abstractions.
4//!
5//! C header: [`include/linux/cpumask.h`](srctree/include/linux/cpumask.h)
6
7use crate::{
8    alloc::{AllocError, Flags},
9    prelude::*,
10    types::Opaque,
11};
12
13#[cfg(CONFIG_CPUMASK_OFFSTACK)]
14use core::ptr::{self, NonNull};
15
16#[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
17use core::mem::MaybeUninit;
18
19use core::ops::{Deref, DerefMut};
20
21/// A CPU Mask.
22///
23/// Rust abstraction for the C `struct cpumask`.
24///
25/// # Invariants
26///
27/// A [`Cpumask`] instance always corresponds to a valid C `struct cpumask`.
28///
29/// The callers must ensure that the `struct cpumask` is valid for access and
30/// remains valid for the lifetime of the returned reference.
31///
32/// ## Examples
33///
34/// The following example demonstrates how to update a [`Cpumask`].
35///
36/// ```
37/// use kernel::bindings;
38/// use kernel::cpumask::Cpumask;
39///
40/// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: u32, clear_cpu: i32) {
41///     // SAFETY: The `ptr` is valid for writing and remains valid for the lifetime of the
42///     // returned reference.
43///     let mask = unsafe { Cpumask::as_mut_ref(ptr) };
44///
45///     mask.set(set_cpu);
46///     mask.clear(clear_cpu);
47/// }
48/// ```
49#[repr(transparent)]
50pub struct Cpumask(Opaque<bindings::cpumask>);
51
52impl Cpumask {
53    /// Creates a mutable reference to an existing `struct cpumask` pointer.
54    ///
55    /// # Safety
56    ///
57    /// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime
58    /// of the returned reference.
59    pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask) -> &'a mut Self {
60        // SAFETY: Guaranteed by the safety requirements of the function.
61        //
62        // INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the
63        // lifetime of the returned reference.
64        unsafe { &mut *ptr.cast() }
65    }
66
67    /// Creates a reference to an existing `struct cpumask` pointer.
68    ///
69    /// # Safety
70    ///
71    /// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime
72    /// of the returned reference.
73    pub unsafe fn as_ref<'a>(ptr: *const bindings::cpumask) -> &'a Self {
74        // SAFETY: Guaranteed by the safety requirements of the function.
75        //
76        // INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the
77        // lifetime of the returned reference.
78        unsafe { &*ptr.cast() }
79    }
80
81    /// Obtain the raw `struct cpumask` pointer.
82    pub fn as_raw(&self) -> *mut bindings::cpumask {
83        let this: *const Self = self;
84        this.cast_mut().cast()
85    }
86
87    /// Set `cpu` in the cpumask.
88    ///
89    /// ATTENTION: Contrary to C, this Rust `set()` method is non-atomic.
90    /// This mismatches kernel naming convention and corresponds to the C
91    /// function `__cpumask_set_cpu()`.
92    #[inline]
93    pub fn set(&mut self, cpu: u32) {
94        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `__cpumask_set_cpu`.
95        unsafe { bindings::__cpumask_set_cpu(cpu, self.as_raw()) };
96    }
97
98    /// Clear `cpu` in the cpumask.
99    ///
100    /// ATTENTION: Contrary to C, this Rust `clear()` method is non-atomic.
101    /// This mismatches kernel naming convention and corresponds to the C
102    /// function `__cpumask_clear_cpu()`.
103    #[inline]
104    pub fn clear(&mut self, cpu: i32) {
105        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to
106        // `__cpumask_clear_cpu`.
107        unsafe { bindings::__cpumask_clear_cpu(cpu, self.as_raw()) };
108    }
109
110    /// Test `cpu` in the cpumask.
111    ///
112    /// Equivalent to the kernel's `cpumask_test_cpu` API.
113    #[inline]
114    pub fn test(&self, cpu: i32) -> bool {
115        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_test_cpu`.
116        unsafe { bindings::cpumask_test_cpu(cpu, self.as_raw()) }
117    }
118
119    /// Set all CPUs in the cpumask.
120    ///
121    /// Equivalent to the kernel's `cpumask_setall` API.
122    #[inline]
123    pub fn setall(&mut self) {
124        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_setall`.
125        unsafe { bindings::cpumask_setall(self.as_raw()) };
126    }
127
128    /// Checks if cpumask is empty.
129    ///
130    /// Equivalent to the kernel's `cpumask_empty` API.
131    #[inline]
132    pub fn empty(&self) -> bool {
133        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_empty`.
134        unsafe { bindings::cpumask_empty(self.as_raw()) }
135    }
136
137    /// Checks if cpumask is full.
138    ///
139    /// Equivalent to the kernel's `cpumask_full` API.
140    #[inline]
141    pub fn full(&self) -> bool {
142        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_full`.
143        unsafe { bindings::cpumask_full(self.as_raw()) }
144    }
145
146    /// Get weight of the cpumask.
147    ///
148    /// Equivalent to the kernel's `cpumask_weight` API.
149    #[inline]
150    pub fn weight(&self) -> u32 {
151        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_weight`.
152        unsafe { bindings::cpumask_weight(self.as_raw()) }
153    }
154
155    /// Copy cpumask.
156    ///
157    /// Equivalent to the kernel's `cpumask_copy` API.
158    #[inline]
159    pub fn copy(&self, dstp: &mut Self) {
160        // SAFETY: By the type invariant, `Self::as_raw` is a valid argument to `cpumask_copy`.
161        unsafe { bindings::cpumask_copy(dstp.as_raw(), self.as_raw()) };
162    }
163}
164
165/// A CPU Mask pointer.
166///
167/// Rust abstraction for the C `struct cpumask_var_t`.
168///
169/// # Invariants
170///
171/// A [`CpumaskVar`] instance always corresponds to a valid C `struct cpumask_var_t`.
172///
173/// The callers must ensure that the `struct cpumask_var_t` is valid for access and remains valid
174/// for the lifetime of [`CpumaskVar`].
175///
176/// ## Examples
177///
178/// The following example demonstrates how to create and update a [`CpumaskVar`].
179///
180/// ```
181/// use kernel::cpumask::CpumaskVar;
182///
183/// let mut mask = CpumaskVar::new_zero(GFP_KERNEL).unwrap();
184///
185/// assert!(mask.empty());
186/// mask.set(2);
187/// assert!(mask.test(2));
188/// mask.set(3);
189/// assert!(mask.test(3));
190/// assert_eq!(mask.weight(), 2);
191///
192/// let mask2 = CpumaskVar::try_clone(&mask).unwrap();
193/// assert!(mask2.test(2));
194/// assert!(mask2.test(3));
195/// assert_eq!(mask2.weight(), 2);
196/// ```
197pub struct CpumaskVar {
198    #[cfg(CONFIG_CPUMASK_OFFSTACK)]
199    ptr: NonNull<Cpumask>,
200    #[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
201    mask: Cpumask,
202}
203
204impl CpumaskVar {
205    /// Creates a zero-initialized instance of the [`CpumaskVar`].
206    pub fn new_zero(_flags: Flags) -> Result<Self, AllocError> {
207        Ok(Self {
208            #[cfg(CONFIG_CPUMASK_OFFSTACK)]
209            ptr: {
210                let mut ptr: *mut bindings::cpumask = ptr::null_mut();
211
212                // SAFETY: It is safe to call this method as the reference to `ptr` is valid.
213                //
214                // INVARIANT: The associated memory is freed when the `CpumaskVar` goes out of
215                // scope.
216                unsafe { bindings::zalloc_cpumask_var(&mut ptr, _flags.as_raw()) };
217                NonNull::new(ptr.cast()).ok_or(AllocError)?
218            },
219
220            #[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
221            // SAFETY: FFI type is valid to be zero-initialized.
222            //
223            // INVARIANT: The associated memory is freed when the `CpumaskVar` goes out of scope.
224            mask: unsafe { core::mem::zeroed() },
225        })
226    }
227
228    /// Creates an instance of the [`CpumaskVar`].
229    ///
230    /// # Safety
231    ///
232    /// The caller must ensure that the returned [`CpumaskVar`] is properly initialized before
233    /// getting used.
234    pub unsafe fn new(_flags: Flags) -> Result<Self, AllocError> {
235        Ok(Self {
236            #[cfg(CONFIG_CPUMASK_OFFSTACK)]
237            ptr: {
238                let mut ptr: *mut bindings::cpumask = ptr::null_mut();
239
240                // SAFETY: It is safe to call this method as the reference to `ptr` is valid.
241                //
242                // INVARIANT: The associated memory is freed when the `CpumaskVar` goes out of
243                // scope.
244                unsafe { bindings::alloc_cpumask_var(&mut ptr, _flags.as_raw()) };
245                NonNull::new(ptr.cast()).ok_or(AllocError)?
246            },
247            #[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
248            // SAFETY: Guaranteed by the safety requirements of the function.
249            //
250            // INVARIANT: The associated memory is freed when the `CpumaskVar` goes out of scope.
251            mask: unsafe { MaybeUninit::uninit().assume_init() },
252        })
253    }
254
255    /// Creates a mutable reference to an existing `struct cpumask_var_t` pointer.
256    ///
257    /// # Safety
258    ///
259    /// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime
260    /// of the returned reference.
261    pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self {
262        // SAFETY: Guaranteed by the safety requirements of the function.
263        //
264        // INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the
265        // lifetime of the returned reference.
266        unsafe { &mut *ptr.cast() }
267    }
268
269    /// Creates a reference to an existing `struct cpumask_var_t` pointer.
270    ///
271    /// # Safety
272    ///
273    /// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime
274    /// of the returned reference.
275    pub unsafe fn as_ref<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self {
276        // SAFETY: Guaranteed by the safety requirements of the function.
277        //
278        // INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the
279        // lifetime of the returned reference.
280        unsafe { &*ptr.cast() }
281    }
282
283    /// Clones cpumask.
284    pub fn try_clone(cpumask: &Cpumask) -> Result<Self> {
285        // SAFETY: The returned cpumask_var is initialized right after this call.
286        let mut cpumask_var = unsafe { Self::new(GFP_KERNEL) }?;
287
288        cpumask.copy(&mut cpumask_var);
289        Ok(cpumask_var)
290    }
291}
292
293// Make [`CpumaskVar`] behave like a pointer to [`Cpumask`].
294impl Deref for CpumaskVar {
295    type Target = Cpumask;
296
297    #[cfg(CONFIG_CPUMASK_OFFSTACK)]
298    fn deref(&self) -> &Self::Target {
299        // SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.
300        unsafe { &*self.ptr.as_ptr() }
301    }
302
303    #[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
304    fn deref(&self) -> &Self::Target {
305        &self.mask
306    }
307}
308
309impl DerefMut for CpumaskVar {
310    #[cfg(CONFIG_CPUMASK_OFFSTACK)]
311    fn deref_mut(&mut self) -> &mut Cpumask {
312        // SAFETY: The caller owns CpumaskVar, so it is safe to deref the cpumask.
313        unsafe { self.ptr.as_mut() }
314    }
315
316    #[cfg(not(CONFIG_CPUMASK_OFFSTACK))]
317    fn deref_mut(&mut self) -> &mut Cpumask {
318        &mut self.mask
319    }
320}
321
322impl Drop for CpumaskVar {
323    fn drop(&mut self) {
324        #[cfg(CONFIG_CPUMASK_OFFSTACK)]
325        // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `free_cpumask_var`.
326        unsafe {
327            bindings::free_cpumask_var(self.as_raw())
328        };
329    }
330}