Skip to contentSkip to conversation

rust: alloc: kvec doc example and allocator unit tests

PATCH Superseded Hui Zhu 3 participants 7 messages Jul 25, 2025 – Jul 30, 2025

Subsystems (2)

v5 of 8 Superseded Latest is v8 →

lore
Share & tools
lore

Hui Zhu

author
#0 lore raw

v5 cover rust: alloc: kvec doc example and allocator unit tests

From: Hui Zhu <[email protected]>

This series includes two Rust patches:

Patch 1 adds KUnit tests for alignment guarantees in Rust allocators. Validates kmalloc handling of standard (128B) and page-size (8KB) alignments.
Confirms vmalloc/kvmalloc reject oversized alignment requests. Ensures Rust allocators respect kernel allocation constraints.

Patch 2 improves the documentation for KVec::as_slice() by adding a code example. This shows how to use the method with push operations and assertions.

Both patches are co-developed with Geliang Tang. Tested on x86_64 using KUnit.

Changelog:
v5:
According to the comments of Danilo, change to use generic struct and allocator Generics in allocator.rs.
v4:
According to the comments of, add the error check for push. v3:
According to the comments of Danilo and Boqun, move KVec test to doc example and move VBox to allocator unit tests.
v2:
According to the comments of Danilo, updated the commit to samples the usage of VBox and KVec.

Hui Zhu (2):
rust: allocator: add KUnit tests for alignment guarantees
rust: alloc: kvec: add doc example for as_slice method

 rust/kernel/alloc/allocator.rs | 58 ++++++++++++++++++++++++++++++++++
 rust/kernel/alloc/kvec.rs      | 10 ++++++
 2 files changed, 68 insertions(+)
Signature · 1 line
2.43.0
author
#1 lore raw

PATCH v5 1/2 rust: allocator: add KUnit tests for alignment guarantees

From: Hui Zhu <[email protected]>

Add comprehensive tests to verify correct alignment handling in Rust allocator wrappers. The tests validate:

That kmalloc respects both standard (128-byte) and page-size (8192-byte) alignments when allocating structs with explicit alignment attributes.

That vmalloc correctly handles standard alignments but intentionally rejects allocations requiring alignments larger than its capabilities.

That kvmalloc mirrors vmalloc's constraints, accepting standard alignments but rejecting excessive alignment requirements.

The test infrastructure uses specialized aligned structs (Blob and LargeAlignBlob) and a test harness (TestAlign) to validate pointer alignment through different allocation paths. This ensures our Rust allocators correctly propagate kernel allocation constraints.

---
 rust/kernel/alloc/allocator.rs | 58 ++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
rust/kernel/alloc/allocator.rs +58 -0
index aa2dfa9dca4c..bcc916240f11 100644
@@ -187,3 +187,61 @@ unsafe fn realloc(
         unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, old_layout, flags) }
     }
 }
+
+#[macros::kunit_tests(rust_allocator_kunit)]
+mod tests {
+    use super::*;
+    use core::mem::MaybeUninit;
+    use kernel::prelude::*;
+
+    const TEST_SIZE: usize = 1024;
+    const TEST_LARGE_ALIGN_SIZE: usize = kernel::page::PAGE_SIZE * 4;
+
+    // These two structs are used to test allocating aligned memory.
+    // they don't need to be accessed, so they're marked as dead_code.
+    #[allow(dead_code)]
+    #[repr(align(128))]
+    struct Blob([u8; TEST_SIZE]);
+    #[allow(dead_code)]
+    #[repr(align(8192))]
+    struct LargeAlignBlob([u8; TEST_LARGE_ALIGN_SIZE]);
+
+    struct TestAlign<T, A: Allocator>(Box<MaybeUninit<T>, A>);
+    impl<T, A: Allocator> TestAlign<T, A> {
+        fn new() -> Result<Self> {
+            Ok(Self(Box::<_, A>::new_uninit(GFP_KERNEL)?))
+        }
+
+        fn alignment_valid(&self, align: usize) -> bool {
+            assert!(align.is_power_of_two());
+
+            let addr = self.0.as_ptr() as usize;
+            if addr & (align - 1) != 0 {
+                false
+            } else {
+                true
+            }
+        }
+    }
+
+    #[test]
+    fn test_alignment() -> Result<()> {
+        let ta = TestAlign::<Blob, Kmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        let ta = TestAlign::<LargeAlignBlob, Kmalloc>::new()?;
+        assert!(ta.alignment_valid(8192));
+
+        let ta = TestAlign::<Blob, Vmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        assert!(TestAlign::<LargeAlignBlob, Vmalloc>::new().is_err());
+
+        let ta = TestAlign::<Blob, KVmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        assert!(TestAlign::<LargeAlignBlob, KVmalloc>::new().is_err());
+
+        Ok(())
+    }
+}
Signature · 1 line
2.43.0
maintainer
#2 lore raw

Re: [PATCH v5 1/2] rust: allocator: add KUnit tests for alignment guarantees

Quoted 15 lines · Hui Zhu

From: Hui Zhu <[email protected]>

Add comprehensive tests to verify correct alignment handling in Rust allocator wrappers. The tests validate:

That kmalloc respects both standard (128-byte) and page-size (8192-byte) alignments when allocating structs with explicit alignment attributes.

That vmalloc correctly handles standard alignments but intentionally rejects allocations requiring alignments larger than its capabilities.

That kvmalloc mirrors vmalloc's constraints, accepting standard alignments but rejecting excessive alignment requirements.

Quoted 8 lines

The test infrastructure uses specialized aligned structs (Blob and LargeAlignBlob) and a test harness (TestAlign) to validate pointer alignment through different allocation paths. This ensures our Rust allocators correctly propagate kernel allocation constraints.

Thanks, this looks good. I think it would be good to rebase onto [1], since it will likely land in the same cycle. Additionally, two nits below.

As a follow-up we could also test alignment in the context of Allocator::realloc(), i.e. when growing and shrinking buffers or requesting a different NUMA node.

[1] https://lore.kernel.org/lkml/[email protected]/

Quoted 9 lines
---
 rust/kernel/alloc/allocator.rs | 58 ++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
rust/kernel/alloc/allocator.rs +0 -0
index aa2dfa9dca4c..bcc916240f11 100644

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 196

Quoted 10 lines
rust/kernel/alloc/allocator.rs +7 -0
@@ -187,3 +187,61 @@ unsafe fn realloc(
         unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, old_layout, flags) }
     }
 }
+
+#[macros::kunit_tests(rust_allocator_kunit)]
+mod tests {
+    use super::*;
+    use core::mem::MaybeUninit;
+    use kernel::prelude::*;
+

--8<--

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 202

Quoted 6 lines
rust/kernel/alloc/allocator.rs +6 -0
+    const TEST_SIZE: usize = 1024;
+    const TEST_LARGE_ALIGN_SIZE: usize = kernel::page::PAGE_SIZE * 4;
+
+    // These two structs are used to test allocating aligned memory.
+    // they don't need to be accessed, so they're marked as dead_code.
+    #[allow(dead_code)]

This should be #[expect(dead_code)].

Quoted 11 lines
rust/kernel/alloc/allocator.rs +11 -0
+    #[repr(align(128))]
+    struct Blob([u8; TEST_SIZE]);
+    #[allow(dead_code)]
+    #[repr(align(8192))]
+    struct LargeAlignBlob([u8; TEST_LARGE_ALIGN_SIZE]);
+
+    struct TestAlign<T, A: Allocator>(Box<MaybeUninit<T>, A>);
+    impl<T, A: Allocator> TestAlign<T, A> {
+        fn new() -> Result<Self> {
+            Ok(Self(Box::<_, A>::new_uninit(GFP_KERNEL)?))
+        }

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 223

Quoted 10 lines
rust/kernel/alloc/allocator.rs +10 -0
+
+        fn alignment_valid(&self, align: usize) -> bool {
+            assert!(align.is_power_of_two());
+
+            let addr = self.0.as_ptr() as usize;
+            if addr & (align - 1) != 0 {
+                false
+            } else {
+                true
+            }

This can just be

	addr & (align - 1) == 0

instead of the conditional clause.

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 225

Quoted 2 lines
rust/kernel/alloc/allocator.rs +2 -0
+        }
+    }

We could move all the above into test_alignment() given that it's likely only needed from there.

Quoted 24 lines
rust/kernel/alloc/allocator.rs +22 -0
+
+    #[test]
+    fn test_alignment() -> Result<()> {
+        let ta = TestAlign::<Blob, Kmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        let ta = TestAlign::<LargeAlignBlob, Kmalloc>::new()?;
+        assert!(ta.alignment_valid(8192));
+
+        let ta = TestAlign::<Blob, Vmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        assert!(TestAlign::<LargeAlignBlob, Vmalloc>::new().is_err());
+
+        let ta = TestAlign::<Blob, KVmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        assert!(TestAlign::<LargeAlignBlob, KVmalloc>::new().is_err());
+
+        Ok(())
+    }
+}
Signature · 1 line
2.43.0
maintainer
#3 lore raw

Re: [PATCH v5 1/2] rust: allocator: add KUnit tests for alignment guarantees

(Cc: Andrew)

Quoted 21 lines · Danilo Krummrich
Quoted 20 lines · Hui Zhu

From: Hui Zhu <[email protected]>

Add comprehensive tests to verify correct alignment handling in Rust allocator wrappers. The tests validate:

That kmalloc respects both standard (128-byte) and page-size (8192-byte) alignments when allocating structs with explicit alignment attributes.

That vmalloc correctly handles standard alignments but intentionally rejects allocations requiring alignments larger than its capabilities.

That kvmalloc mirrors vmalloc's constraints, accepting standard alignments but rejecting excessive alignment requirements.

The test infrastructure uses specialized aligned structs (Blob and LargeAlignBlob) and a test harness (TestAlign) to validate pointer alignment through different allocation paths. This ensures our Rust allocators correctly propagate kernel allocation constraints.

Quoted 6 lines
Quoted 3 lines

Thanks, this looks good. I think it would be good to rebase onto [1], since it will likely land in the same cycle. Additionally, two nits below.

Please also Cc: Andrew for subsequent submissions, since this will, due to the interaction with [1] likely go through his tree.

Quoted 95 lines

As a follow-up we could also test alignment in the context of Allocator::realloc(), i.e. when growing and shrinking buffers or requesting a different NUMA node.

[1] https://lore.kernel.org/lkml/[email protected]/

Quoted 9 lines
---
 rust/kernel/alloc/allocator.rs | 58 ++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
rust/kernel/alloc/allocator.rs +0 -0
index aa2dfa9dca4c..bcc916240f11 100644

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 196

Quoted 10 lines
rust/kernel/alloc/allocator.rs +7 -0
@@ -187,3 +187,61 @@ unsafe fn realloc(
         unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, old_layout, flags) }
     }
 }
+
+#[macros::kunit_tests(rust_allocator_kunit)]
+mod tests {
+    use super::*;
+    use core::mem::MaybeUninit;
+    use kernel::prelude::*;
+

--8<--

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 202

Quoted 6 lines
rust/kernel/alloc/allocator.rs +6 -0
+    const TEST_SIZE: usize = 1024;
+    const TEST_LARGE_ALIGN_SIZE: usize = kernel::page::PAGE_SIZE * 4;
+
+    // These two structs are used to test allocating aligned memory.
+    // they don't need to be accessed, so they're marked as dead_code.
+    #[allow(dead_code)]

This should be #[expect(dead_code)].

Quoted 11 lines
rust/kernel/alloc/allocator.rs +11 -0
+    #[repr(align(128))]
+    struct Blob([u8; TEST_SIZE]);
+    #[allow(dead_code)]
+    #[repr(align(8192))]
+    struct LargeAlignBlob([u8; TEST_LARGE_ALIGN_SIZE]);
+
+    struct TestAlign<T, A: Allocator>(Box<MaybeUninit<T>, A>);
+    impl<T, A: Allocator> TestAlign<T, A> {
+        fn new() -> Result<Self> {
+            Ok(Self(Box::<_, A>::new_uninit(GFP_KERNEL)?))
+        }

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 223

Quoted 10 lines
rust/kernel/alloc/allocator.rs +10 -0
+
+        fn alignment_valid(&self, align: usize) -> bool {
+            assert!(align.is_power_of_two());
+
+            let addr = self.0.as_ptr() as usize;
+            if addr & (align - 1) != 0 {
+                false
+            } else {
+                true
+            }

This can just be

	addr & (align - 1) == 0

instead of the conditional clause.

rust/kernel/alloc/allocator.rs unsafe fn realloc( · line 225

Quoted 2 lines
rust/kernel/alloc/allocator.rs +2 -0
+        }
+    }

We could move all the above into test_alignment() given that it's likely only needed from there.

Quoted 24 lines
rust/kernel/alloc/allocator.rs +22 -0
+
+    #[test]
+    fn test_alignment() -> Result<()> {
+        let ta = TestAlign::<Blob, Kmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        let ta = TestAlign::<LargeAlignBlob, Kmalloc>::new()?;
+        assert!(ta.alignment_valid(8192));
+
+        let ta = TestAlign::<Blob, Vmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        assert!(TestAlign::<LargeAlignBlob, Vmalloc>::new().is_err());
+
+        let ta = TestAlign::<Blob, KVmalloc>::new()?;
+        assert!(ta.alignment_valid(128));
+
+        assert!(TestAlign::<LargeAlignBlob, KVmalloc>::new().is_err());
+
+        Ok(())
+    }
+}
Signature · 1 line
2.43.0
author
#4 lore raw

Re: [PATCH v5 1/2] rust: allocator: add KUnit tests for alignment guarantees

2025年7月25日 18:02, "Danilo Krummrich" <[email protected] mailto:[email protected]?to=%22Danilo%20Krummrich%22%20%3Cdakr%40kernel.org%3E > 写到:

Quoted 33 lines

(Cc: Andrew)

Quoted 28 lines · Danilo Krummrich
Quoted 25 lines · Hui Zhu

From: Hui Zhu <[email protected]>

Add comprehensive tests to verify correct alignment handling in Rust allocator wrappers. The tests validate:

That kmalloc respects both standard (128-byte) and page-size (8192-byte) alignments when allocating structs with explicit alignment attributes.

That vmalloc correctly handles standard alignments but intentionally rejects allocations requiring alignments larger than its capabilities.

That kvmalloc mirrors vmalloc's constraints, accepting standard alignments but rejecting excessive alignment requirements.

The test infrastructure uses specialized aligned structs (Blob and LargeAlignBlob) and a test harness (TestAlign) to validate pointer alignment through different allocation paths. This ensures our Rust allocators correctly propagate kernel allocation constraints.

Quoted 83 lines
Quoted 3 lines

Thanks, this looks good. I think it would be good to rebase onto [1], since it will likely land in the same cycle. Additionally, two nits below.

Please also Cc: Andrew for subsequent submissions, since this will, due to the interaction with [1] likely go through his tree.

Quoted 77 lines

As a follow-up we could also test alignment in the context of
Allocator::realloc(), i.e. when growing and shrinking buffers or requesting a different NUMA node.

[1] https://lore.kernel.org/lkml/[email protected]/

Quoted 5 lines
---
 rust/kernel/alloc/allocator.rs | 58 ++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
Quoted 16 lines

diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index aa2dfa9dca4c..bcc916240f11 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -187,3 +187,61 @@ unsafe fn realloc(
unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, old_layout, flags) } }
}
+
+#[macros::kunit_tests(rust_allocator_kunit)]
+mod tests {
+ use super::*;
+ use core::mem::MaybeUninit;
+ use kernel::prelude::*;
+

--8<--

Quoted 8 lines

+ const TEST_SIZE: usize = 1024;
+ const TEST_LARGE_ALIGN_SIZE: usize = kernel::page::PAGE_SIZE * 4; +
+ // These two structs are used to test allocating aligned memory.
+ // they don't need to be accessed, so they're marked as dead_code.
+ #[allow(dead_code)]

This should be #[expect(dead_code)].

Quoted 14 lines

+ #[repr(align(128))]
+ struct Blob([u8; TEST_SIZE]);
+ #[allow(dead_code)]
+ #[repr(align(8192))]
+ struct LargeAlignBlob([u8; TEST_LARGE_ALIGN_SIZE]); +
+ struct TestAlign<T, A: Allocator>(Box<MaybeUninit<T>, A>);
+ impl<T, A: Allocator> TestAlign<T, A> {
+ fn new() -> Result<Self> {
+ Ok(Self(Box::<_, A>::new_uninit(GFP_KERNEL)?))
+ }
+
+ fn alignment_valid(&self, align: usize) -> bool {

Quoted 9 lines

+ assert!(align.is_power_of_two());
+
+ let addr = self.0.as_ptr() as usize;
+ if addr & (align - 1) != 0 {
+ false
+ } else {
+ true
+ }

This can just be

addr & (align - 1) == 0

instead of the conditional clause.

Quoted 4 lines

+ }
+ }

We could move all the above into test_alignment() given that it's likely only needed from there.

Quoted 1 line

Hi Danilo,

Thanks!

I sent v6 version that rebased on [1].

Best,
Hui

[1] https://lore.kernel.org/lkml/[email protected]/

Quoted 27 lines
Quoted 26 lines
Quoted 25 lines

+
+ #[test]
+ fn test_alignment() -> Result<()> {
+ let ta = TestAlign::<Blob, Kmalloc>::new()?;
+ assert!(ta.alignment_valid(128));
+
+ let ta = TestAlign::<LargeAlignBlob, Kmalloc>::new()?;
+ assert!(ta.alignment_valid(8192));
+
+ let ta = TestAlign::<Blob, Vmalloc>::new()?;
+ assert!(ta.alignment_valid(128));
+
+ assert!(TestAlign::<LargeAlignBlob, Vmalloc>::new().is_err()); +
+ let ta = TestAlign::<Blob, KVmalloc>::new()?;
+ assert!(ta.alignment_valid(128));
+
+ assert!(TestAlign::<LargeAlignBlob, KVmalloc>::new().is_err()); +
+ Ok(())
+ }
+}
--
2.43.0

author
#5 lore raw

PATCH v5 2/2 rust: alloc: kvec: add doc example for as_slice method

In reply to Hui Zhu

From: Hui Zhu <[email protected]>

Add a practical usage example to the documentation of KVec::as_slice() showing how to:
Create a new KVec.
Push elements into it.
Convert to a slice via as_slice().

---
 rust/kernel/alloc/kvec.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)
rust/kernel/alloc/kvec.rs +10 -0
index 3c72e0bdddb8..fa04cc0987d6 100644
@@ -224,6 +224,16 @@ unsafe fn dec_len(&mut self, count: usize) -> &mut [T] {
     }
 
     /// Returns a slice of the entire vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = KVec::new();
+    /// v.push(1, GFP_KERNEL)?;
+    /// v.push(2, GFP_KERNEL)?;
+    /// assert_eq!(v.as_slice(), &[1, 2]);
+    /// # Ok::<(), Error>(())
+    /// ```
     #[inline]
     pub fn as_slice(&self) -> &[T] {
         self
Signature · 1 line
2.43.0
maintainer Reviewed-by on the v5 series
#6 lore raw
In reply to Hui Zhu
Quoted 10 lines · Hui Zhu

From: Hui Zhu <[email protected]>

This series includes two Rust patches:

Patch 1 adds KUnit tests for alignment guarantees in Rust allocators. Validates kmalloc handling of standard (128B) and page-size (8KB) alignments.
Confirms vmalloc/kvmalloc reject oversized alignment requests. Ensures Rust allocators respect kernel allocation constraints.

Quoted 6 lines

Patch 2 improves the documentation for KVec::as_slice() by adding a code example. This shows how to use the method with push operations and assertions.

Both patches are co-developed with Geliang Tang. Tested on x86_64 using KUnit.