Add a short exercise for Rust's per-CPU variable API, modelled after
lib/percpu_test.c
Signed-off-by: Mitchell Levy <levymitchell0@gmail.com>
---
lib/Kconfig.debug | 9 +++++++
lib/Makefile | 1 +
lib/percpu_test_rust.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+)
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index f3d723705879..75a91f1766ce 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2404,6 +2404,15 @@ config PERCPU_TEST
If unsure, say N.
+config PERCPU_TEST_RUST
+ tristate "Rust per cpu operations test"
+ depends on m && DEBUG_KERNEL && RUST
+ help
+ Enable this option to build a test module which validates Rust per-cpu
+ operations.
+
+ If unsure, say N.
+
config ATOMIC64_SELFTEST
tristate "Perform an atomic64_t self-test"
help
diff --git a/lib/Makefile b/lib/Makefile
index a8155c972f02..0ea8d414763c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -301,6 +301,7 @@ obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o
obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o
obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
+obj-$(CONFIG_PERCPU_TEST_RUST) += percpu_test_rust.o
obj-$(CONFIG_ASN1) += asn1_decoder.o
obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o
diff --git a/lib/percpu_test_rust.rs b/lib/percpu_test_rust.rs
new file mode 100644
index 000000000000..60df44332d7a
--- /dev/null
+++ b/lib/percpu_test_rust.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+//! A simple self test for the rust per-CPU API.
+use kernel::{
+ define_per_cpu, percpu::cpu_guard::*, percpu::*, pr_info, prelude::*, unsafe_get_per_cpu_ref,
+};
+
+module! {
+ type: PerCpuTestModule,
+ name: "percpu_test_rust",
+ author: "Mitchell Levy",
+ description: "Test code to exercise the Rust Per CPU variable API",
+ license: "GPL v2",
+}
+
+struct PerCpuTestModule;
+
+define_per_cpu!(PERCPU: i64 = 0);
+define_per_cpu!(UPERCPU: u64 = 0);
+
+impl kernel::Module for PerCpuTestModule {
+ fn init(_module: &'static ThisModule) -> Result<Self, Error> {
+ pr_info!("rust percpu test start\n");
+
+ let mut native: i64 = 0;
+ let mut pcpu: PerCpuRef<i64> = unsafe { unsafe_get_per_cpu_ref!(PERCPU, CpuGuard::new()) };
+
+ native += -1;
+ *pcpu += -1;
+ assert!(native == *pcpu && native == -1);
+
+ native += 1;
+ *pcpu += 1;
+ assert!(native == *pcpu && native == 0);
+
+ let mut unative: u64 = 0;
+ let mut upcpu: PerCpuRef<u64> =
+ unsafe { unsafe_get_per_cpu_ref!(UPERCPU, CpuGuard::new()) };
+
+ unative += 1;
+ *upcpu += 1;
+ assert!(unative == *upcpu && unative == 1);
+
+ unative = unative.wrapping_add((-1i64) as u64);
+ *upcpu = upcpu.wrapping_add((-1i64) as u64);
+ assert!(unative == *upcpu && unative == 0);
+
+ unative = unative.wrapping_add((-1i64) as u64);
+ *upcpu = upcpu.wrapping_add((-1i64) as u64);
+ assert!(unative == *upcpu && unative == (-1i64) as u64);
+
+ unative = 0;
+ *upcpu = 0;
+
+ unative = unative.wrapping_sub(1);
+ *upcpu = upcpu.wrapping_sub(1);
+ assert!(unative == *upcpu && unative == (-1i64) as u64);
+ assert!(unative == *upcpu && unative == u64::MAX);
+
+ pr_info!("rust percpu test done\n");
+
+ // Return Err to unload the module
+ Result::Err(EINVAL)
+ }
+}
+
--
2.34.1
On Thu, 19 Dec 2024, Mitchell Levy wrote:
> + let mut native: i64 = 0;
> + let mut pcpu: PerCpuRef<i64> = unsafe { unsafe_get_per_cpu_ref!(PERCPU, CpuGuard::new()) };
A bit complex.
> + native += -1;
> + *pcpu += -1;
> + assert!(native == *pcpu && native == -1);
> +
> + native += 1;
> + *pcpu += 1;
> + assert!(native == *pcpu && native == 0);
> +
That's pretty straightforward..... But is there no symbolic access to the
per cpu namespace? How would you access the kernel per cpu variables
defined in C?
How do you go about using per cpu atomics like
this_cpu_inc(nr_dentry_unused);
"Christoph Lameter (Ampere)" <cl@gentwo.org> writes:
> On Thu, 19 Dec 2024, Mitchell Levy wrote:
>
>> + let mut native: i64 = 0;
>> + let mut pcpu: PerCpuRef<i64> = unsafe { unsafe_get_per_cpu_ref!(PERCPU, CpuGuard::new()) };
>
> A bit complex.
I agree with this, maybe a helper function would suffise? Something in
terms of,
unsafe fn get_per_cpu<T>(var: &PerCpuVariable<T>) -> PerCpuRef<T> {
unsafe_get_per_cpu_ref!(var, CpuGuard::new())
}
>
>> + native += -1;
>> + *pcpu += -1;
>> + assert!(native == *pcpu && native == -1);
>> +
>> + native += 1;
>> + *pcpu += 1;
>> + assert!(native == *pcpu && native == 0);
>> +
>
> That's pretty straightforward..... But is there no symbolic access to the
> per cpu namespace? How would you access the kernel per cpu variables
> defined in C?
>
> How do you go about using per cpu atomics like
>
> this_cpu_inc(nr_dentry_unused);
On Sun, Jan 05, 2025 at 01:01:43PM +0000, Charalampos Mitrodimas wrote:
> "Christoph Lameter (Ampere)" <cl@gentwo.org> writes:
>
> > On Thu, 19 Dec 2024, Mitchell Levy wrote:
> >
> >> + let mut native: i64 = 0;
> >> + let mut pcpu: PerCpuRef<i64> = unsafe { unsafe_get_per_cpu_ref!(PERCPU, CpuGuard::new()) };
> >
> > A bit complex.
>
> I agree with this, maybe a helper function would suffise? Something in
> terms of,
> unsafe fn get_per_cpu<T>(var: &PerCpuVariable<T>) -> PerCpuRef<T> {
> unsafe_get_per_cpu_ref!(var, CpuGuard::new())
> }
I'm certainly open to adding such a helper. Is the main concern here the
unwieldy name? Generally, I prefer to keep modifications to global state
(disabling preemption via CpuGuard::new()) as explicit as possible, but
if there's consensus to the contrary, I'm happy to roll it into the
macro/a helper function.
> >
> >> + native += -1;
> >> + *pcpu += -1;
> >> + assert!(native == *pcpu && native == -1);
> >> +
> >> + native += 1;
> >> + *pcpu += 1;
> >> + assert!(native == *pcpu && native == 0);
> >> +
> >
> > That's pretty straightforward..... But is there no symbolic access to the
> > per cpu namespace? How would you access the kernel per cpu variables
> > defined in C?
> >
> > How do you go about using per cpu atomics like
> >
> > this_cpu_inc(nr_dentry_unused);
Mitchell Levy <levymitchell0@gmail.com> writes:
> On Sun, Jan 05, 2025 at 01:01:43PM +0000, Charalampos Mitrodimas wrote:
>> "Christoph Lameter (Ampere)" <cl@gentwo.org> writes:
>>
>> > On Thu, 19 Dec 2024, Mitchell Levy wrote:
>> >
>> >> + let mut native: i64 = 0;
>> >> + let mut pcpu: PerCpuRef<i64> = unsafe { unsafe_get_per_cpu_ref!(PERCPU, CpuGuard::new()) };
>> >
>> > A bit complex.
>>
>> I agree with this, maybe a helper function would suffise? Something in
>> terms of,
>> unsafe fn get_per_cpu<T>(var: &PerCpuVariable<T>) -> PerCpuRef<T> {
>> unsafe_get_per_cpu_ref!(var, CpuGuard::new())
>> }
>
> I'm certainly open to adding such a helper. Is the main concern here the
> unwieldy name? Generally, I prefer to keep modifications to global state
> (disabling preemption via CpuGuard::new()) as explicit as possible, but
> if there's consensus to the contrary, I'm happy to roll it into the
> macro/a helper function.
Yes, in my opinion, the macro name is indeed complex. You're right about
keeping modifications as explicit as possible. A helper wouldn’t be
necessary if the macro name were simpler.
Is adding "unsafe_" to a macro that is unsafe a standard practice? Maybe
we can remove it from the macro name. Documentation is enough IMO.
>
>> >
>> >> + native += -1;
>> >> + *pcpu += -1;
>> >> + assert!(native == *pcpu && native == -1);
>> >> +
>> >> + native += 1;
>> >> + *pcpu += 1;
>> >> + assert!(native == *pcpu && native == 0);
>> >> +
>> >
>> > That's pretty straightforward..... But is there no symbolic access to the
>> > per cpu namespace? How would you access the kernel per cpu variables
>> > defined in C?
>> >
>> > How do you go about using per cpu atomics like
>> >
>> > this_cpu_inc(nr_dentry_unused);
On Fri, Dec 20, 2024 at 09:56:54AM -0800, Christoph Lameter (Ampere) wrote:
> On Thu, 19 Dec 2024, Mitchell Levy wrote:
>
> > + let mut native: i64 = 0;
> > + let mut pcpu: PerCpuRef<i64> = unsafe { unsafe_get_per_cpu_ref!(PERCPU, CpuGuard::new()) };
>
> A bit complex.
>
> > + native += -1;
> > + *pcpu += -1;
> > + assert!(native == *pcpu && native == -1);
> > +
> > + native += 1;
> > + *pcpu += 1;
> > + assert!(native == *pcpu && native == 0);
> > +
>
> That's pretty straightforward..... But is there no symbolic access to the
> per cpu namespace? How would you access the kernel per cpu variables
> defined in C?
>
FWIW, there is a declare_extern_per_cpu!() marco in patch #1, and
Mitchell used it to access this_cpu_off (defined in C).
Maybe we want to see an example here?
Regards,
Boqun
> How do you go about using per cpu atomics like
>
> this_cpu_inc(nr_dentry_unused);
>
>
© 2016 - 2026 Red Hat, Inc.