diff mbox series

[RFC,3/3] rust: percpu: add a rust per-CPU variable test

Message ID 20241219-rust-percpu-v1-3-209117e822b1@gmail.com (mailing list archive)
State New
Headers show
Series rust: Add Per-CPU Variable API | expand

Commit Message

Mitchell Levy Dec. 19, 2024, 9:08 p.m. UTC
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(+)

Comments

Christoph Lameter (Ampere) Dec. 20, 2024, 5:56 p.m. UTC | #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);
diff mbox series

Patch

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)
+    }
+}
+