rust: alloc: Add realloc and alloc_zeroed to the GlobalAlloc impl
PATCH v2 1/1 rust: alloc: Add realloc and alloc_zeroed to the GlobalAlloc impl
While there are default impls for these methods, using the respective C api's is faster. Currently neither the existing nor these new GlobalAlloc method implementations are actually called. Instead the __rust_* function defined below the GlobalAlloc impl are used. With rustc 1.71 these functions will be gone and all allocation calls will go through the GlobalAlloc implementation.
---
Miguel, I fold my diff into Björn's original patch and make a v2, it relies on the other patch:
https://lore.kernel.org/rust-for-linux/[email protected]/
So this v2 (if all goes well) is targeted for v6.6, JFYI.
v1 -> v2:
* Add size adjustment for align requirement.
rust/kernel/allocator.rs | 59 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-)
rust/kernel/allocator.rs +54 -5
@@ -9,8 +9,17 @@struct KernelAllocator ; -unsafe impl GlobalAlloc for KernelAllocator { -unsafe fn alloc (&self, layout:Layout ) -> *mut u8 { +impl KernelAllocator { +/// # Safety +/// +/// * `ptr` can be either null or a pointer which has been allocated by this allocator. +/// * `layout` must have a non-zero size. +unsafe fn krealloc_with_flags ( + &self, + ptr: *mut u8 , + layout:Layout , + flags: bindings::gfp_t , + ) -> *mut u8 {// Customized layouts from `Layout::from_size_align()` can have size < align, so pads first. let layout = layout.pad_to_align ();
@@ -26,9 +35,22 @@ unsafe fn alloc(&self, layout: Layout) -> *mut u8 { size = size.next_power_of_two (); } -// `krealloc()` is used instead of `kmalloc()` because the latter is -// an inline function and cannot be bound to as a result. -unsafe { bindings::krealloc (ptr::null (), size, bindings::GFP_KERNEL )as *mut u8 } +// SAFETY: +// +// * `ptr` is either null or a pointer returned from a previous k{re}alloc() by the function +// safety requirement. +// +// * `size` is greater than 0 since it's either a `layout.size()` (which cannot be zero +// according to the function safety requirement) or a result from `next_power_of_two()`. +unsafe { bindings::krealloc (ptras *const core::ffi::c_void , size, flags)as *mut u8 } + } +} + +unsafe impl GlobalAlloc for KernelAllocator { +unsafe fn alloc (&self, layout:Layout ) -> *mut u8 { +// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety +// requirement. +unsafe { self.krealloc_with_flags (ptr::null_mut (), layout, bindings::GFP_KERNEL ) } }unsafe fn dealloc (&self, ptr: *mut u8 , _layout:Layout ) {
@@ -36,6 +58,33 @@ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { bindings::kfree (ptras *const core::ffi::c_void ); } } + +unsafe fn realloc (&self, ptr: *mut u8 , layout:Layout , new_size:usize ) -> *mut u8 { +// SAFETY: +// * `new_size` when rounded up to the nearest multiple of `layout.align()`, will not +// overflow `isize` by the function safety requirement. +// * `layout.align()` is a proper alignment (i.e. not zero and must be a power of two). +let layout =unsafe {Layout ::from_size_align_unchecked (new_size, layout.align ()) }; + +// SAFETY: +// * `ptr` is either null or a pointer allocated by this allocator by function safety +// requirement. +// * the size of `layout` is not zero because `new_size` is not zero by function safety +// requirement. +unsafe { self.krealloc_with_flags (ptr, layout, bindings::GFP_KERNEL ) } + } + +unsafe fn alloc_zeroed (&self, layout:Layout ) -> *mut u8 { +// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety +// requirement. +unsafe { + self.krealloc_with_flags ( + ptr::null_mut (), + layout, + bindings::GFP_KERNEL | bindings::__GFP_ZERO, + ) + } + } }#[global_allocator]
Signature · 1 line
2.39.2
Quoted 10 lines · Boqun Feng
While there are default impls for these methods, using the respective C api's is faster. Currently neither the existing nor these new GlobalAlloc method implementations are actually called. Instead the __rust_* function defined below the GlobalAlloc impl are used. With rustc 1.71 these functions will be gone and all allocation calls will go through the GlobalAlloc implementation.
Signed-off-by Björn Roy Baron <[email protected]>[boqun: add size adjustment for alignment requirement]
I think that this should go above Link and Signed-off-bys, although I'm not sure if maintainers do it when is merged.
Quoted 7 lines
Signed-off-by Boqun Feng <[email protected]>---
Miguel, I fold my diff into Björn's original patch and make a v2, it relies on the other patch:https://lore.kernel.org/rust-for-linux/[email protected]/
Quoted 7 lines
So this v2 (if all goes well) is targeted for v6.6, JFYI.
v1 -> v2:
* Add size adjustment for align requirement.
[...]
Newbie question, aren't tabs in the commit message verboten?
Aside from those two nits everything else LGTM.
Quoted 3 lines · Martin Rodriguez Reboredo
I think that this should go above Link and Signed-off-bys, although I'm not sure if maintainers do it when is merged.
Both styles are used, it is fine either way. Personally, I pick one or the other depending on the kind of comment.
Having said that, there seems to be a missing From:, but I can fix that on my side if Björn is the intended author.
Quoted 1 line
Newbie question, aren't tabs in the commit message verboten?
I am not aware of such a rule, and there are commits in the kernel with tabs, e.g. commit 9828ed3f695a ("module: error out early on concurrent load of the same module file").
In any case, that text doesn't go into the commit message, because it is after the --- line.
Cheers,
Miguel
Quoted 18 lines · Miguel Ojeda
Quoted 3 lines · Martin Rodriguez Reboredo
I think that this should go above Link and Signed-off-bys, although I'm not sure if maintainers do it when is merged.
Both styles are used, it is fine either way. Personally, I pick one or the other depending on the kind of comment.
Having said that, there seems to be a missing
From:, but I can fix that on my side if Björn is the intended author.Quoted 1 line
Newbie question, aren't tabs in the commit message verboten?
I am not aware of such a rule, and there are commits in the kernel with tabs, e.g. commit
9828ed3f695a("module: error out early on concurrent load of the same module file").
Quoted 5 lines
In any case, that text doesn't go into the commit message, because it is after the
---line.Cheers,
Miguel
Alrighty, both make sense to me, thanks for the explanations!
-> Martin
Quoted 11 lines · Boqun Feng
While there are default impls for these methods, using the respective C api's is faster. Currently neither the existing nor these new GlobalAlloc method implementations are actually called. Instead the __rust_* function defined below the GlobalAlloc impl are used. With rustc 1.71 these functions will be gone and all allocation calls will go through the GlobalAlloc implementation.
Signed-off-by Björn Roy Baron <[email protected]>[boqun: add size adjustment for alignment requirement]Signed-off-by Boqun Feng <[email protected]>
Quoted 102 lines
---
Miguel, I fold my diff into Björn's original patch and make a v2, it relies on the other patch:https://lore.kernel.org/rust-for-linux/[email protected]/So this v2 (if all goes well) is targeted for v6.6, JFYI.
v1 -> v2:
* Add size adjustment for align requirement.
rust/kernel/allocator.rs | 59 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-)rust/kernel/allocator.rs +54
-6@@ -9,8 +9,17 @@struct KernelAllocator ; -unsafe impl GlobalAlloc for KernelAllocator { -unsafe fn alloc (&self, layout:Layout ) -> *mut u8 { +impl KernelAllocator { +/// # Safety +/// +/// * `ptr` can be either null or a pointer which has been allocated by this allocator. +/// * `layout` must have a non-zero size. +unsafe fn krealloc_with_flags ( + &self, + ptr: *mut u8 , + layout:Layout , + flags: bindings::gfp_t , + ) -> *mut u8 {// Customized layouts from `Layout::from_size_align()` can have size < align, so pads first. let layout = layout.pad_to_align ();@@ -26,9 +35,22 @@ unsafe fn alloc(&self, layout: Layout) -> *mut u8 { size = size.next_power_of_two (); } -// `krealloc()` is used instead of `kmalloc()` because the latter is -// an inline function and cannot be bound to as a result. -unsafe { bindings::krealloc (ptr::null (), size, bindings::GFP_KERNEL )as *mut u8 } +// SAFETY: +// +// * `ptr` is either null or a pointer returned from a previous k{re}alloc() by the function +// safety requirement. +// +// * `size` is greater than 0 since it's either a `layout.size()` (which cannot be zero +// according to the function safety requirement) or a result from `next_power_of_two()`. +unsafe { bindings::krealloc (ptras *const core::ffi::c_void , size, flags)as *mut u8 } + } +} + +unsafe impl GlobalAlloc for KernelAllocator { +unsafe fn alloc (&self, layout:Layout ) -> *mut u8 { +// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety +// requirement. +unsafe { self.krealloc_with_flags (ptr::null_mut (), layout, bindings::GFP_KERNEL ) } }unsafe fn dealloc (&self, ptr: *mut u8 , _layout:Layout ) {@@ -36,6 +58,33 @@ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { bindings::kfree (ptras *const core::ffi::c_void ); } } + +unsafe fn realloc (&self, ptr: *mut u8 , layout:Layout , new_size:usize ) -> *mut u8 { +// SAFETY: +// * `new_size` when rounded up to the nearest multiple of `layout.align()`, will not +// overflow `isize` by the function safety requirement. +// * `layout.align()` is a proper alignment (i.e. not zero and must be a power of two). +let layout =unsafe {Layout ::from_size_align_unchecked (new_size, layout.align ()) }; + +// SAFETY: +// * `ptr` is either null or a pointer allocated by this allocator by function safety +// requirement. +// * the size of `layout` is not zero because `new_size` is not zero by function safety +// requirement. +unsafe { self.krealloc_with_flags (ptr, layout, bindings::GFP_KERNEL ) } + } + +unsafe fn alloc_zeroed (&self, layout:Layout ) -> *mut u8 { +// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety +// requirement. +unsafe { + self.krealloc_with_flags ( + ptr::null_mut (), + layout, + bindings::GFP_KERNEL | bindings::__GFP_ZERO, + ) + } + } }#[global_allocator] --2.39.2
Quoted 11 lines · On Sun, 25 Jun 2023 16:25:28 -0700 Boqun Feng <[email protected]> wrote:
While there are default impls for these methods, using the respective C api's is faster. Currently neither the existing nor these new GlobalAlloc method implementations are actually called. Instead the __rust_* function defined below the GlobalAlloc impl are used. With rustc 1.71 these functions will be gone and all allocation calls will go through the GlobalAlloc implementation.
Signed-off-by Björn Roy Baron <[email protected]>[boqun: add size adjustment for alignment requirement]Signed-off-by Boqun Feng <[email protected]>
Quoted 99 lines
---
Miguel, I fold my diff into Björn's original patch and make a v2, it relies on the other patch:https://lore.kernel.org/rust-for-linux/[email protected]/So this v2 (if all goes well) is targeted for v6.6, JFYI.
v1 -> v2:
* Add size adjustment for align requirement.
rust/kernel/allocator.rs | 59 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-)rust/kernel/allocator.rs +54
-5@@ -9,8 +9,17 @@struct KernelAllocator ; -unsafe impl GlobalAlloc for KernelAllocator { -unsafe fn alloc (&self, layout:Layout ) -> *mut u8 { +impl KernelAllocator { +/// # Safety +/// +/// * `ptr` can be either null or a pointer which has been allocated by this allocator. +/// * `layout` must have a non-zero size. +unsafe fn krealloc_with_flags ( + &self, + ptr: *mut u8 , + layout:Layout , + flags: bindings::gfp_t , + ) -> *mut u8 {// Customized layouts from `Layout::from_size_align()` can have size < align, so pads first. let layout = layout.pad_to_align ();@@ -26,9 +35,22 @@ unsafe fn alloc(&self, layout: Layout) -> *mut u8 { size = size.next_power_of_two (); } -// `krealloc()` is used instead of `kmalloc()` because the latter is -// an inline function and cannot be bound to as a result. -unsafe { bindings::krealloc (ptr::null (), size, bindings::GFP_KERNEL )as *mut u8 } +// SAFETY: +// +// * `ptr` is either null or a pointer returned from a previous k{re}alloc() by the function +// safety requirement. +// +// * `size` is greater than 0 since it's either a `layout.size()` (which cannot be zero +// according to the function safety requirement) or a result from `next_power_of_two()`. +unsafe { bindings::krealloc (ptras *const core::ffi::c_void , size, flags)as *mut u8 } + } +} + +unsafe impl GlobalAlloc for KernelAllocator { +unsafe fn alloc (&self, layout:Layout ) -> *mut u8 { +// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety +// requirement. +unsafe { self.krealloc_with_flags (ptr::null_mut (), layout, bindings::GFP_KERNEL ) } }unsafe fn dealloc (&self, ptr: *mut u8 , _layout:Layout ) {@@ -36,6 +58,33 @@ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { bindings::kfree (ptras *const core::ffi::c_void ); } } + +unsafe fn realloc (&self, ptr: *mut u8 , layout:Layout , new_size:usize ) -> *mut u8 { +// SAFETY: +// * `new_size` when rounded up to the nearest multiple of `layout.align()`, will not +// overflow `isize` by the function safety requirement. +// * `layout.align()` is a proper alignment (i.e. not zero and must be a power of two). +let layout =unsafe {Layout ::from_size_align_unchecked (new_size, layout.align ()) }; + +// SAFETY: +// * `ptr` is either null or a pointer allocated by this allocator by function safety +// requirement. +// * the size of `layout` is not zero because `new_size` is not zero by function safety +// requirement. +unsafe { self.krealloc_with_flags (ptr, layout, bindings::GFP_KERNEL ) } + } + +unsafe fn alloc_zeroed (&self, layout:Layout ) -> *mut u8 { +// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety +// requirement. +unsafe { + self.krealloc_with_flags ( + ptr::null_mut (), + layout, + bindings::GFP_KERNEL | bindings::__GFP_ZERO, + ) + } + } }#[global_allocator]
Miguel Ojeda
AppliedQuoted 8 lines · Boqun Feng
While there are default impls for these methods, using the respective C api's is faster. Currently neither the existing nor these new GlobalAlloc method implementations are actually called. Instead the __rust_* function defined below the GlobalAlloc impl are used. With rustc 1.71 these functions will be gone and all allocation calls will go through the GlobalAlloc implementation.
Quoted 4 lines
Signed-off-by Björn Roy Baron <[email protected]>[boqun: add size adjustment for alignment requirement]Signed-off-by Boqun Feng <[email protected]>
Applied to rust-next, thanks! I will use it as a base for the 1.71 upgrade.
Cheers,
Miguel