Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rust: Use CpuId in place of raw CPU numbers

Use the newly defined `CpuId` abstraction instead of raw CPU numbers.

This also fixes a doctest failure for configurations where `nr_cpu_ids <
4`.

The C `cpumask_{set|clear}_cpu()` APIs emit a warning when given an
invalid CPU number — but only if `CONFIG_DEBUG_PER_CPU_MAPS=y` is set.

Meanwhile, `cpumask_weight()` only considers CPUs up to `nr_cpu_ids`,
which can cause inconsistencies: a CPU number greater than `nr_cpu_ids`
may be set in the mask, yet the weight calculation won't reflect it.

This leads to doctest failures when `nr_cpu_ids < 4`, as the test tries
to set CPUs 2 and 3:

rust_doctest_kernel_cpumask_rs_0.location: rust/kernel/cpumask.rs:180
rust_doctest_kernel_cpumask_rs_0: ASSERTION FAILED at rust/kernel/cpumask.rs:190

Fixes: 8961b8cb3099 ("rust: cpumask: Add initial abstractions")
Reported-by: Miguel Ojeda <ojeda@kernel.org>
Closes: https://lore.kernel.org/rust-for-linux/CANiq72k3ozKkLMinTLQwvkyg9K=BeRxs1oYZSKhJHY-veEyZdg@mail.gmail.com/
Reported-by: Andreas Hindborg <a.hindborg@kernel.org>
Closes: https://lore.kernel.org/all/87qzzy3ric.fsf@kernel.org/
Suggested-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>

+59 -27
+2 -2
drivers/cpufreq/rcpufreq_dt.rs
··· 26 26 } 27 27 28 28 /// Finds supply name for the CPU from DT. 29 - fn find_supply_names(dev: &Device, cpu: u32) -> Option<KVec<CString>> { 29 + fn find_supply_names(dev: &Device, cpu: cpu::CpuId) -> Option<KVec<CString>> { 30 30 // Try "cpu0" for older DTs, fallback to "cpu". 31 - let name = (cpu == 0) 31 + let name = (cpu.as_u32() == 0) 32 32 .then(|| find_supply_name_exact(dev, "cpu0")) 33 33 .flatten() 34 34 .or_else(|| find_supply_name_exact(dev, "cpu"))?;
+2 -2
rust/kernel/cpu.rs
··· 127 127 /// Callers must ensure that the CPU device is not used after it has been unregistered. 128 128 /// This can be achieved, for example, by registering a CPU hotplug notifier and removing 129 129 /// any references to the CPU device within the notifier's callback. 130 - pub unsafe fn from_cpu(cpu: u32) -> Result<&'static Device> { 130 + pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> { 131 131 // SAFETY: It is safe to call `get_cpu_device()` for any CPU. 132 - let ptr = unsafe { bindings::get_cpu_device(cpu) }; 132 + let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) }; 133 133 if ptr.is_null() { 134 134 return Err(ENODEV); 135 135 }
+19 -8
rust/kernel/cpufreq.rs
··· 10 10 11 11 use crate::{ 12 12 clk::Hertz, 13 + cpu::CpuId, 13 14 cpumask, 14 15 device::{Bound, Device}, 15 16 devres::Devres, ··· 466 465 467 466 /// Returns the primary CPU for the [`Policy`]. 468 467 #[inline] 469 - pub fn cpu(&self) -> u32 { 470 - self.as_ref().cpu 468 + pub fn cpu(&self) -> CpuId { 469 + // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. 470 + unsafe { CpuId::from_u32_unchecked(self.as_ref().cpu) } 471 471 } 472 472 473 473 /// Returns the minimum frequency for the [`Policy`]. ··· 527 525 #[inline] 528 526 pub fn generic_get(&self) -> Result<u32> { 529 527 // SAFETY: By the type invariant, the pointer stored in `self` is valid. 530 - Ok(unsafe { bindings::cpufreq_generic_get(self.cpu()) }) 528 + Ok(unsafe { bindings::cpufreq_generic_get(u32::from(self.cpu())) }) 531 529 } 532 530 533 531 /// Provides a wrapper to the register with energy model using the OPP core. ··· 680 678 struct PolicyCpu<'a>(&'a mut Policy); 681 679 682 680 impl<'a> PolicyCpu<'a> { 683 - fn from_cpu(cpu: u32) -> Result<Self> { 681 + fn from_cpu(cpu: CpuId) -> Result<Self> { 684 682 // SAFETY: It is safe to call `cpufreq_cpu_get` for any valid CPU. 685 - let ptr = from_err_ptr(unsafe { bindings::cpufreq_cpu_get(cpu) })?; 683 + let ptr = from_err_ptr(unsafe { bindings::cpufreq_cpu_get(u32::from(cpu)) })?; 686 684 687 685 Ok(Self( 688 686 // SAFETY: The `ptr` is guaranteed to be valid and remains valid for the lifetime of ··· 1268 1266 target_perf: usize, 1269 1267 capacity: usize, 1270 1268 ) { 1271 - if let Ok(mut policy) = PolicyCpu::from_cpu(cpu) { 1269 + // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. 1270 + let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) }; 1271 + 1272 + if let Ok(mut policy) = PolicyCpu::from_cpu(cpu_id) { 1272 1273 T::adjust_perf(&mut policy, min_perf, target_perf, capacity); 1273 1274 } 1274 1275 } ··· 1326 1321 /// 1327 1322 /// - This function may only be called from the cpufreq C infrastructure. 1328 1323 unsafe extern "C" fn get_callback(cpu: u32) -> kernel::ffi::c_uint { 1329 - PolicyCpu::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy).map_or(0, |f| f)) 1324 + // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. 1325 + let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) }; 1326 + 1327 + PolicyCpu::from_cpu(cpu_id).map_or(0, |mut policy| T::get(&mut policy).map_or(0, |f| f)) 1330 1328 } 1331 1329 1332 1330 /// Driver's `update_limit` callback. ··· 1352 1344 /// - This function may only be called from the cpufreq C infrastructure. 1353 1345 /// - The pointer arguments must be valid pointers. 1354 1346 unsafe extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel::ffi::c_int { 1347 + // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. 1348 + let cpu_id = unsafe { CpuId::from_i32_unchecked(cpu) }; 1349 + 1355 1350 from_result(|| { 1356 - let mut policy = PolicyCpu::from_cpu(cpu as u32)?; 1351 + let mut policy = PolicyCpu::from_cpu(cpu_id)?; 1357 1352 1358 1353 // SAFETY: `limit` is guaranteed by the C code to be valid. 1359 1354 T::bios_limit(&mut policy, &mut (unsafe { *limit })).map(|()| 0)
+36 -15
rust/kernel/cpumask.rs
··· 6 6 7 7 use crate::{ 8 8 alloc::{AllocError, Flags}, 9 + cpu::CpuId, 9 10 prelude::*, 10 11 types::Opaque, 11 12 }; ··· 36 35 /// 37 36 /// ``` 38 37 /// use kernel::bindings; 38 + /// use kernel::cpu::CpuId; 39 39 /// use kernel::cpumask::Cpumask; 40 40 /// 41 - /// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: u32, clear_cpu: i32) { 41 + /// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: CpuId, clear_cpu: CpuId) { 42 42 /// // SAFETY: The `ptr` is valid for writing and remains valid for the lifetime of the 43 43 /// // returned reference. 44 44 /// let mask = unsafe { Cpumask::as_mut_ref(ptr) }; ··· 92 90 /// This mismatches kernel naming convention and corresponds to the C 93 91 /// function `__cpumask_set_cpu()`. 94 92 #[inline] 95 - pub fn set(&mut self, cpu: u32) { 93 + pub fn set(&mut self, cpu: CpuId) { 96 94 // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `__cpumask_set_cpu`. 97 - unsafe { bindings::__cpumask_set_cpu(cpu, self.as_raw()) }; 95 + unsafe { bindings::__cpumask_set_cpu(u32::from(cpu), self.as_raw()) }; 98 96 } 99 97 100 98 /// Clear `cpu` in the cpumask. ··· 103 101 /// This mismatches kernel naming convention and corresponds to the C 104 102 /// function `__cpumask_clear_cpu()`. 105 103 #[inline] 106 - pub fn clear(&mut self, cpu: i32) { 104 + pub fn clear(&mut self, cpu: CpuId) { 107 105 // SAFETY: By the type invariant, `self.as_raw` is a valid argument to 108 106 // `__cpumask_clear_cpu`. 109 - unsafe { bindings::__cpumask_clear_cpu(cpu, self.as_raw()) }; 107 + unsafe { bindings::__cpumask_clear_cpu(i32::from(cpu), self.as_raw()) }; 110 108 } 111 109 112 110 /// Test `cpu` in the cpumask. 113 111 /// 114 112 /// Equivalent to the kernel's `cpumask_test_cpu` API. 115 113 #[inline] 116 - pub fn test(&self, cpu: i32) -> bool { 114 + pub fn test(&self, cpu: CpuId) -> bool { 117 115 // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_test_cpu`. 118 - unsafe { bindings::cpumask_test_cpu(cpu, self.as_raw()) } 116 + unsafe { bindings::cpumask_test_cpu(i32::from(cpu), self.as_raw()) } 119 117 } 120 118 121 119 /// Set all CPUs in the cpumask. ··· 180 178 /// The following example demonstrates how to create and update a [`CpumaskVar`]. 181 179 /// 182 180 /// ``` 181 + /// use kernel::cpu::CpuId; 183 182 /// use kernel::cpumask::CpumaskVar; 184 183 /// 185 184 /// let mut mask = CpumaskVar::new_zero(GFP_KERNEL).unwrap(); 186 185 /// 187 186 /// assert!(mask.empty()); 188 - /// mask.set(2); 189 - /// assert!(mask.test(2)); 190 - /// mask.set(3); 191 - /// assert!(mask.test(3)); 192 - /// assert_eq!(mask.weight(), 2); 187 + /// let mut count = 0; 188 + /// 189 + /// let cpu2 = CpuId::from_u32(2); 190 + /// if let Some(cpu) = cpu2 { 191 + /// mask.set(cpu); 192 + /// assert!(mask.test(cpu)); 193 + /// count += 1; 194 + /// } 195 + /// 196 + /// let cpu3 = CpuId::from_u32(3); 197 + /// if let Some(cpu) = cpu3 { 198 + /// mask.set(cpu); 199 + /// assert!(mask.test(cpu)); 200 + /// count += 1; 201 + /// } 202 + /// 203 + /// assert_eq!(mask.weight(), count); 193 204 /// 194 205 /// let mask2 = CpumaskVar::try_clone(&mask).unwrap(); 195 - /// assert!(mask2.test(2)); 196 - /// assert!(mask2.test(3)); 197 - /// assert_eq!(mask2.weight(), 2); 206 + /// 207 + /// if let Some(cpu) = cpu2 { 208 + /// assert!(mask2.test(cpu)); 209 + /// } 210 + /// 211 + /// if let Some(cpu) = cpu3 { 212 + /// assert!(mask2.test(cpu)); 213 + /// } 214 + /// assert_eq!(mask2.weight(), count); 198 215 /// ``` 199 216 pub struct CpumaskVar { 200 217 #[cfg(CONFIG_CPUMASK_OFFSTACK)]