lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 30 May 2023 14:48:21 +0800
From:   "Qingsong Chen" <changxian.cqs@...group.com>
To:     linux-kernel@...r.kernel.org
Cc:     "田洪亮" <tate.thl@...group.com>,
        "Qingsong Chen" <changxian.cqs@...group.com>,
        "Boqun Feng" <boqun.feng@...il.com>,
        "Miguel Ojeda" <ojeda@...nel.org>,
        "Alex Gaynor" <alex.gaynor@...il.com>,
        "Wedson Almeida Filho" <wedsonaf@...il.com>,
        "Gary Guo" <gary@...yguo.net>,
        "Björn Roy Baron" <bjorn3_gh@...tonmail.com>,
        "Benno Lossin" <benno.lossin@...ton.me>,
        "Martin Rodriguez Reboredo" <yakoyoku@...il.com>,
        "Asahi Lina" <lina@...hilina.net>,
        "Sven Van Asbroeck" <thesven73@...il.com>,
        "Viktor Garske" <viktor@...ar.de>, "Finn Behrens" <me@...enk.dev>,
        <rust-for-linux@...r.kernel.org>
Subject: [PATCH 2/2] samples: rust: add `SgTable` and `ScatterList` selftests

Add a selftest module to provide a temporary place to put "pure tests"
for Rust funtionality and wrappers.

Add test cases for `SgTable` and `ScatterList`.

Co-developed-by: Boqun Feng <boqun.feng@...il.com>
Signed-off-by: Boqun Feng <boqun.feng@...il.com>
Signed-off-by: Qingsong Chen <changxian.cqs@...group.com>
---
 rust/kernel/error.rs           |   2 +-
 samples/rust/Kconfig           |  10 ++
 samples/rust/Makefile          |   1 +
 samples/rust/rust_selftests.rs | 186 +++++++++++++++++++++++++++++++++
 4 files changed, 198 insertions(+), 1 deletion(-)
 create mode 100644 samples/rust/rust_selftests.rs

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 5f4114b30b94..40f2db9d57a6 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -68,7 +68,7 @@ pub mod code {
 /// # Invariants
 ///
 /// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct Error(core::ffi::c_int);
 
 impl Error {
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index b0f74a81c8f9..a1f29e5aaf83 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -30,6 +30,16 @@ config SAMPLE_RUST_PRINT
 
 	  If unsure, say N.
 
+config SAMPLE_RUST_SELFTESTS
+	tristate "Self tests"
+	help
+	  This option builds the self test cases for Rust.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_selftests.
+
+	  If unsure, say N.
+
 config SAMPLE_RUST_HOSTPROGS
 	bool "Host programs"
 	help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 03086dabbea4..4519a567db7c 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -2,5 +2,6 @@
 
 obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
 obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_SELFTESTS)		+= rust_selftests.o
 
 subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/rust_selftests.rs b/samples/rust/rust_selftests.rs
new file mode 100644
index 000000000000..843d53159ac8
--- /dev/null
+++ b/samples/rust/rust_selftests.rs
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Self test cases for Rust.
+
+use kernel::prelude::*;
+// Keep the `use` for a test in its test function. Module-level `use`s are only for the test
+// framework.
+
+module! {
+    type: RustSelftests,
+    name: "rust_selftests",
+    author: "Rust for Linux Contributors",
+    description: "Self test cases for Rust",
+    license: "GPL",
+}
+
+struct RustSelftests;
+
+/// A summary of testing.
+///
+/// A test can
+///
+/// * pass (successfully), or
+/// * fail (without hitting any error), or
+/// * hit an error (interrupted).
+///
+/// This is the type that differentiates the first two (pass and fail) cases.
+///
+/// When a test hits an error, the test function should skip and return the error. Note that this
+/// doesn't mean the test fails, for example if the system doesn't have enough memory for
+/// testing, the test function may return an `Err(ENOMEM)` and skip.
+#[allow(dead_code)]
+enum TestSummary {
+    Pass,
+    Fail,
+}
+
+use TestSummary::Fail;
+use TestSummary::Pass;
+
+macro_rules! do_tests {
+    ($($name:ident),*) => {
+        let mut total = 0;
+        let mut pass = 0;
+        let mut fail = 0;
+
+        $({
+            total += 1;
+
+            match $name() {
+                Ok(Pass) => {
+                    pass += 1;
+                    pr_info!("{} passed!", stringify!($name));
+                },
+                Ok(Fail) => {
+                    fail += 1;
+                    pr_info!("{} failed!", stringify!($name));
+                },
+                Err(err) => {
+                    pr_info!("{} hit error {:?}", stringify!($name), err);
+                }
+            }
+        })*
+
+        pr_info!("{} tests run, {} passed, {} failed, {} hit errors\n",
+                 total, pass, fail, total - pass - fail);
+
+        if total == pass {
+            pr_info!("All tests passed. Congratulations!\n");
+        }
+    }
+}
+
+/// An example of test.
+#[allow(dead_code)]
+fn test_example() -> Result<TestSummary> {
+    // `use` declarations for the test can be put here, e.g. `use foo::bar;`.
+
+    // Always pass.
+    Ok(Pass)
+}
+
+/// A selftest case for `SgTable`.
+fn test_sgtable() -> Result<TestSummary> {
+    use core::pin::pin;
+    use kernel::scatterlist::*;
+
+    // Prepare memory buffers.
+    let buf0: Pin<&mut [u8]> = pin!([0u8; 512]);
+    let buf1: Pin<&mut [u8]> = pin!([1u8; 512]);
+    let mut entries = Vec::<Pin<&mut [u8]>>::new();
+    entries.try_push(buf0)?;
+    entries.try_push(buf1)?;
+
+    // Construct two `SgTable` instances. And the first is chainable, which
+    // requires one entry reserved.
+    let mut sgt0: Pin<Box<SgTable<'_, 3>>> =
+        Box::pin_init(SgTable::<'_, 3>::new(entries.as_slice(), true))?;
+    let mut sgt1: Pin<Box<SgTable<'_, 2>>> =
+        Box::pin_init(SgTable::<'_, 2>::new(entries.as_slice(), false))?;
+
+    // Assert the total count of entries in the table.
+    assert_eq!(sgt0.count(), 2);
+    assert_eq!(sgt1.count(), 2);
+
+    // Chain two `SgTable` together.
+    sgt0.chain_sgt(sgt1.as_mut())?;
+    assert_eq!(sgt0.count(), 4);
+    assert_eq!(sgt1.count(), 2);
+
+    // Get the immutable reference to the entry in the table.
+    let sgl1: Pin<&ScatterList<'_>> = sgt0.get(1).ok_or(EINVAL)?;
+    assert_eq!(sgl1.count(), 3);
+
+    // Get the mutable reference to the entry in the table.
+    let sgl3: Pin<&mut ScatterList<'_>> = sgt0.get_mut(3).ok_or(EINVAL)?;
+    assert_eq!(sgl3.count(), 1);
+
+    // Try to get a non-exist entry from the table.
+    let sgl4 = sgt0.get(4);
+    assert_eq!(sgl4.is_none(), true);
+
+    // Split the first table from chained scatterlist.
+    sgt0.split()?;
+    assert_eq!(sgt0.count(), 2);
+    assert_eq!(sgt1.count(), 2);
+
+    // Chain `SgTable` with single `ScatterList`.
+    let mut sgl: Pin<Box<ScatterList<'_>>> = Box::pin_init(ScatterList::new(&entries[0]))?;
+    sgt0.chain_sgl(sgl.as_mut())?;
+    assert_eq!(sgt0.count(), 3);
+
+    Ok(Pass)
+}
+
+/// A selftest case for `ScatterList`.
+fn test_scatterlist() -> Result<TestSummary> {
+    use core::pin::pin;
+    use kernel::scatterlist::*;
+
+    // Prepare memory buffers.
+    let buf0: Pin<&mut [u8]> = pin!([0u8; 512]);
+    let buf1: Pin<&mut [u8]> = pin!([1u8; 512]);
+
+    // Construct a `ScatterList` instance. And assert its attributes.
+    let mut sgl: Pin<Box<ScatterList<'_>>> = Box::pin_init(ScatterList::new(&buf0))?;
+    assert_eq!(sgl.length(), 512);
+    assert_eq!(sgl.is_dma_bus_address(), false);
+    assert_eq!(sgl.dma_address(), 0);
+    assert_eq!(sgl.dma_length(), 0);
+    assert_eq!(sgl.is_chain(), false);
+    assert_eq!(sgl.is_last(), true);
+    assert_eq!(sgl.count(), 1);
+
+    // Get an immutable reference to the memory buffer.
+    assert_eq!(sgl.get_buf(), [0u8; 512]);
+
+    // Reset the memory buffer.
+    sgl.set_buf(&buf1);
+    assert_eq!(sgl.get_buf(), [1u8; 512]);
+
+    // Get a mutable reference to memory buffer.
+    sgl.get_mut_buf().fill(2);
+    assert_eq!(sgl.get_buf(), [2u8; 512]);
+
+    Ok(Pass)
+}
+
+impl kernel::Module for RustSelftests {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust self tests (init)\n");
+
+        do_tests! {
+            test_sgtable,
+            test_scatterlist
+        };
+
+        Ok(RustSelftests)
+    }
+}
+
+impl Drop for RustSelftests {
+    fn drop(&mut self) {
+        pr_info!("Rust self tests (exit)\n");
+    }
+}
-- 
2.40.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ