rust: alloc: kvec doc example and allocator unit tests
Subsystems (2)
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
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
@@ -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
Danilo Krummrich
maintainerRe: [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.
Co-developed-by Geliang Tang <[email protected]>Signed-off-by Geliang Tang <[email protected]>Signed-off-by Hui Zhu <[email protected]>
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
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
Danilo Krummrich
maintainerRe: [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
Co-developed-by Geliang Tang <[email protected]>Signed-off-by Geliang Tang <[email protected]>Signed-off-by Hui Zhu <[email protected]>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
-0rust/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) == 0instead 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
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.
Co-developed-by Geliang Tang <[email protected]>Signed-off-by Geliang Tang <[email protected]>Signed-off-by Hui Zhu <[email protected]>
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.rsb/rust/kernel/alloc/allocator.rsindexaa2dfa9dca4c..bcc916240f11100644
---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::*;
+ usecore::mem::MaybeUninit;
+ use kernel::prelude::*;
+--8<--
Quoted 8 lines
+ const
TEST_SIZE: usize = 1024;
+ constTEST_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 asdead_code.
+ #[allow(dead_code)]This should be #[expect(dead_code)].
Quoted 14 lines
+ #[repr(align(128))]
+ structBlob([u8; TEST_SIZE]);
+ #[allow(dead_code)]
+ #[repr(align(8192))]
+ structLargeAlignBlob([u8; TEST_LARGE_ALIGN_SIZE]); +
+ struct TestAlign<T, A: Allocator>(Box<MaybeUninit<T>, A>);
+ impl<T, A: Allocator> TestAlign<T, A> {
+ fnnew()-> Result<Self> {
+Ok(Self(Box::<_, A>::new_uninit(GFP_KERNEL)?))
+ }
+
+ fnalignment_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]
+ fntest_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
PATCH v5 2/2 rust: alloc: kvec: add doc example for as_slice method
In reply to Hui ZhuFrom: 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
@@ -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
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_64using KUnit.