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