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