linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/25] Generic `Allocator` support for Rust
@ 2024-08-01  0:01 Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 01/25] rust: alloc: add `Allocator` trait Danilo Krummrich
                   ` (24 more replies)
  0 siblings, 25 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:01 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Hi,

This patch series adds generic kernel allocator support for Rust, which so far
is limited to `kmalloc` allocations.

In order to abstain from (re-)adding unstable Rust features to the kernel, this
patch series does not extend the `Allocator` trait from Rust's `alloc` crate,
nor does it extend the `BoxExt` and `VecExt` extensions.

Instead, this series introduces a kernel specific `Allocator` trait, which is
implemented by the `Kmalloc`, `Vmalloc` and `KVmalloc` allocators, also
implemented in the context of this series.

As a consequence we need our own kernel `Box<T, A>` and `Vec<T, A>` types.
Additionally, this series adds the following type aliases:

```
pub type KBox<T> = Box<T, Kmalloc>;
pub type VBox<T> = Box<T, Vmalloc>;
pub type KVBox<T> = Box<T, KVmalloc>;


pub type KVec<T> = Vec<T, Kmalloc>;
pub type VVec<T> = Vec<T, Vmalloc>;
pub type KVVec<T> = Vec<T, KVmalloc>;
```

With that, we can start using the kernel `Box` and `Vec` types throughout the
tree and remove the now obolete extensions `BoxExt` and `VecExt`.

For a final cleanup, this series removes the last minor dependencies to Rust's
`alloc` crate and removes it from the entire kernel build.

The series ensures not to break the `rusttest` make target by implementing the
`allocator_test` module providing a stub implementation for all kernel
`Allocator`s.

This patch series passes all KUnit tests, including the ones added by this
series. Additionally, the tests were run with `kmemleak` and `KASAN` enabled,
without any issues.

This series is based on [1], which hit -mm/mm-unstable, and is also available
in [2].

[1] https://git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=mm/krealloc
[2] https://git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=rust/mm

Changes in v3:
 - Box:
   - minor documentation fixes
   - removed unnecessary imports in doc tests
   - dropeed `self` argument from some remaining `Box` methods 
   - implement `InPlaceInit` for Box<T, A> rather than specifically for `KBox<T>`
 - Vec:
   - minor documentation fixes
   - removed useless `Vec::allocator` method
   - in `Vec::extend_with` use `Vec::spare_capacity_mut` instead of raw pointer operations
   - added a few missing safety comments
   - pass GFP flags to `Vec::collect`
 - fixed a rustdoc warning in alloc.rs
 - fixed the allocator_test module to implement the `Allocator` trait correctly
 - rebased to rust-next

Changes in v2:
  - preserve `impl GlobalAlloc for Kmalloc` and remove it at the end (Benno)
  - remove `&self` parameter from all `Allocator` functions (Benno)
  - various documentation fixes for `Allocator` (Benno)
  - use `NonNull<u8>` for `Allocator::free` and `Option<NonNull<u8>>` for
    `Allocator::realloc` (Benno)
  - fix leak of `IntoIter` in `Vec::collect` (Boqun)
  - always realloc (try to shrink) in `Vec::collect`, it's up the the
    `Allocator` to provide a heuristic whether it makes sense to actually shrink
  - rename `KBox<T, A>` -> `Box<T, A>` and `KVec<T, A>` -> `Vec<T, A>` and
    provide type aliases `KBox<T>`, `VBox<T>`, `KVBox<T>`, etc.
    - This allows for much cleaner code and, in combination with removing
      `&self` parameters from `Allocator`s, gets us rid of the need for
      `Box::new` and `Box::new_alloc` and all other "_alloc" postfixed
      functions.
    - Before: `KBox::new_alloc(foo, Vmalloc)?`
    - After:  `VBox::new(foo)?`, which resolves to
              `Box::<Foo,  Vmalloc>::new(foo)?;

Danilo Krummrich (25):
  rust: alloc: add `Allocator` trait
  rust: alloc: separate `aligned_size` from `krealloc_aligned`
  rust: alloc: rename `KernelAllocator` to `Kmalloc`
  rust: alloc: implement `Allocator` for `Kmalloc`
  rust: alloc: add module `allocator_test`
  rust: alloc: implement `Vmalloc` allocator
  rust: alloc: implement `KVmalloc` allocator
  rust: types: implement `Unique<T>`
  rust: alloc: implement kernel `Box`
  rust: treewide: switch to our kernel `Box` type
  rust: alloc: remove `BoxExt` extension
  rust: alloc: add `Box` to prelude
  rust: alloc: import kernel `Box` type in types.rs
  rust: alloc: import kernel `Box` type in init.rs
  rust: alloc: implement kernel `Vec` type
  rust: alloc: implement `IntoIterator` for `Vec`
  rust: alloc: implement `collect` for `IntoIter`
  rust: treewide: switch to the kernel `Vec` type
  rust: alloc: remove `VecExt` extension
  rust: alloc: add `Vec` to prelude
  rust: alloc: remove `GlobalAlloc` and `krealloc_aligned`
  rust: error: use `core::alloc::LayoutError`
  rust: str: test: replace `alloc::format`
  rust: alloc: update module comment of alloc.rs
  kbuild: rust: remove the `alloc` crate

 rust/Makefile                       |  44 +-
 rust/exports.c                      |   1 -
 rust/helpers.c                      |  15 +
 rust/kernel/alloc.rs                | 101 +++-
 rust/kernel/alloc/allocator.rs      | 147 +++--
 rust/kernel/alloc/allocator_test.rs |  21 +
 rust/kernel/alloc/box_ext.rs        |  56 --
 rust/kernel/alloc/kbox.rs           | 340 +++++++++++
 rust/kernel/alloc/kvec.rs           | 847 ++++++++++++++++++++++++++++
 rust/kernel/alloc/vec_ext.rs        | 185 ------
 rust/kernel/error.rs                |   2 +-
 rust/kernel/init.rs                 |  56 +-
 rust/kernel/init/__internal.rs      |   2 +-
 rust/kernel/lib.rs                  |   1 -
 rust/kernel/prelude.rs              |   5 +-
 rust/kernel/str.rs                  |  78 ++-
 rust/kernel/sync/arc.rs             |  17 +-
 rust/kernel/sync/condvar.rs         |   4 +-
 rust/kernel/sync/lock/mutex.rs      |   2 +-
 rust/kernel/sync/lock/spinlock.rs   |   2 +-
 rust/kernel/sync/locked_by.rs       |   2 +-
 rust/kernel/types.rs                | 192 ++++++-
 rust/kernel/uaccess.rs              |  15 +-
 rust/kernel/workqueue.rs            |  20 +-
 samples/rust/rust_minimal.rs        |   4 +-
 scripts/Makefile.build              |   7 +-
 26 files changed, 1735 insertions(+), 431 deletions(-)
 create mode 100644 rust/kernel/alloc/allocator_test.rs
 delete mode 100644 rust/kernel/alloc/box_ext.rs
 create mode 100644 rust/kernel/alloc/kbox.rs
 create mode 100644 rust/kernel/alloc/kvec.rs
 delete mode 100644 rust/kernel/alloc/vec_ext.rs


base-commit: c0d669a6bbe161a3afa26dea3d8491863e352e59
-- 
2.45.2



^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v3 01/25] rust: alloc: add `Allocator` trait
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:19   ` Alice Ryhl
  2024-08-04  6:21   ` Boqun Feng
  2024-08-01  0:02 ` [PATCH v3 02/25] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
                   ` (23 subsequent siblings)
  24 siblings, 2 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Add a kernel specific `Allocator` trait, that in contrast to the one in
Rust's core library doesn't require unstable features and supports GFP
flags.

Subsequent patches add the following trait implementors: `Kmalloc`,
`Vmalloc` and `KVmalloc`.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index 1966bd407017..b79dd2c49277 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -11,6 +11,7 @@
 /// Indicates an allocation error.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct AllocError;
+use core::{alloc::Layout, ptr::NonNull};
 
 /// Flags to be used when allocating memory.
 ///
@@ -86,3 +87,75 @@ pub mod flags {
     /// small allocations.
     pub const GFP_NOWAIT: Flags = Flags(bindings::GFP_NOWAIT);
 }
+
+/// The kernel's [`Allocator`] trait.
+///
+/// An implementation of [`Allocator`] can allocate, re-allocate and free memory buffer described
+/// via [`Layout`].
+///
+/// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
+/// an object instance.
+///
+/// # Safety
+///
+/// Memory returned from an allocator must point to a valid memory buffer and remain valid until
+/// it is explicitly freed.
+///
+/// Any pointer to a memory buffer which is currently allocated must be valid to be passed to any
+/// other [`Allocator`] function. The same applies for a NULL pointer.
+///
+/// If `realloc` is called with:
+///   - a size of zero, the given memory allocation, if any, must be freed
+///   - a NULL pointer, a new memory allocation must be created
+pub unsafe trait Allocator {
+    /// Allocate memory based on `layout` and `flags`.
+    ///
+    /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
+    /// constraints (i.e. minimum size and alignment as specified by `layout`).
+    ///
+    /// This function is equivalent to `realloc` when called with a NULL pointer.
+    fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
+        // SAFETY: Passing a NULL pointer to `realloc` is valid by it's safety requirements and asks
+        // for a new memory allocation.
+        unsafe { Self::realloc(None, layout, flags) }
+    }
+
+    /// Re-allocate an existing memory allocation to satisfy the requested `layout`. If the
+    /// requested size is zero, `realloc` behaves equivalent to `free`.
+    ///
+    /// If the requested size is larger than the size of the existing allocation, a successful call
+    /// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
+    /// may also be larger.
+    ///
+    /// If the requested size is smaller than the size of the existing allocation, `realloc` may or
+    /// may not shrink the buffer; this is implementation specific to the allocator.
+    ///
+    /// On allocation failure, the existing buffer, if any, remains valid.
+    ///
+    /// The buffer is represented as `NonNull<[u8]>`.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must point to an existing and valid memory allocation created by this allocator
+    /// instance.
+    ///
+    /// Additionally, `ptr` is allowed to be a NULL pointer; in this case a new memory allocation is
+    /// created.
+    unsafe fn realloc(
+        ptr: Option<NonNull<u8>>,
+        layout: Layout,
+        flags: Flags,
+    ) -> Result<NonNull<[u8]>, AllocError>;
+
+    /// Free an existing memory allocation.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must point to an existing and valid memory allocation created by this `Allocator`
+    /// instance.
+    unsafe fn free(ptr: NonNull<u8>) {
+        // SAFETY: `ptr` is guaranteed to be previously allocated with this `Allocator` or NULL.
+        // Calling `realloc` with a buffer size of zero, frees the buffer `ptr` points to.
+        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
+    }
+}
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 02/25] rust: alloc: separate `aligned_size` from `krealloc_aligned`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 01/25] rust: alloc: add `Allocator` trait Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:21   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 03/25] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
                   ` (22 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Separate `aligned_size` from `krealloc_aligned`.

Subsequent patches implement `Allocator` derivates, such as `Kmalloc`,
that require `aligned_size` and replace the original `krealloc_aligned`.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc/allocator.rs | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index e6ea601f38c6..6e133780a4a1 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -8,27 +8,35 @@
 
 struct KernelAllocator;
 
-/// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment.
-///
-/// # Safety
-///
-/// - `ptr` can be either null or a pointer which has been allocated by this allocator.
-/// - `new_layout` must have a non-zero size.
-pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: Flags) -> *mut u8 {
+fn aligned_size(new_layout: Layout) -> usize {
     // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
     let layout = new_layout.pad_to_align();
 
     // Note that `layout.size()` (after padding) is guaranteed to be a multiple of `layout.align()`
     // which together with the slab guarantees means the `krealloc` will return a properly aligned
     // object (see comments in `kmalloc()` for more information).
-    let size = layout.size();
+    layout.size()
+}
 
+/// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment.
+///
+/// # Safety
+///
+/// - `ptr` can be either null or a pointer which has been allocated by this allocator.
+/// - `new_layout` must have a non-zero size.
+pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: Flags) -> *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 from `layout.size()` (which cannot be zero according
     //   to the function safety requirement)
-    unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 }
+    unsafe {
+        bindings::krealloc(
+            ptr as *const core::ffi::c_void,
+            aligned_size(new_layout),
+            flags.0,
+        ) as *mut u8
+    }
 }
 
 unsafe impl GlobalAlloc for KernelAllocator {
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 03/25] rust: alloc: rename `KernelAllocator` to `Kmalloc`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 01/25] rust: alloc: add `Allocator` trait Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 02/25] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:21   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
                   ` (21 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Subsequent patches implement `Vmalloc` and `KVmalloc` allocators, hence
align `KernelAllocator` to this naming scheme.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc/allocator.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index 6e133780a4a1..10774c51ae26 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -6,7 +6,7 @@
 use core::alloc::{GlobalAlloc, Layout};
 use core::ptr;
 
-struct KernelAllocator;
+struct Kmalloc;
 
 fn aligned_size(new_layout: Layout) -> usize {
     // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
@@ -39,7 +39,7 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F
     }
 }
 
-unsafe impl GlobalAlloc for KernelAllocator {
+unsafe impl GlobalAlloc for Kmalloc {
     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.
@@ -75,7 +75,7 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
 }
 
 #[global_allocator]
-static ALLOCATOR: KernelAllocator = KernelAllocator;
+static ALLOCATOR: Kmalloc = Kmalloc;
 
 // See <https://github.com/rust-lang/rust/pull/86844>.
 #[no_mangle]
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (2 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 03/25] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:28   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 05/25] rust: alloc: add module `allocator_test` Danilo Krummrich
                   ` (20 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Implement `Allocator` for `Kmalloc`, the kernel's default allocator,
typically used for objects smaller than page size.

All memory allocations made with `Kmalloc` end up in `krealloc()`.

It serves as allocator for the subsequently introduced types `KBox` and
`KVec`.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs           |  2 +-
 rust/kernel/alloc/allocator.rs | 66 ++++++++++++++++++++++++++++++++--
 2 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index b79dd2c49277..8cabc888393b 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -4,7 +4,7 @@
 
 #[cfg(not(test))]
 #[cfg(not(testlib))]
-mod allocator;
+pub mod allocator;
 pub mod box_ext;
 pub mod vec_ext;
 
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index 10774c51ae26..397ae5bcc043 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -5,9 +5,18 @@
 use super::{flags::*, Flags};
 use core::alloc::{GlobalAlloc, Layout};
 use core::ptr;
+use core::ptr::NonNull;
 
-struct Kmalloc;
+use crate::alloc::{AllocError, Allocator};
+use crate::bindings;
 
+/// The contiguous kernel allocator.
+///
+/// The contiguous kernel allocator only ever allocates physically contiguous memory through
+/// `bindings::krealloc`.
+pub struct Kmalloc;
+
+/// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
 fn aligned_size(new_layout: Layout) -> usize {
     // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
     let layout = new_layout.pad_to_align();
@@ -18,7 +27,7 @@ fn aligned_size(new_layout: Layout) -> usize {
     layout.size()
 }
 
-/// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment.
+/// Calls `krealloc` with a proper size to alloc a new object.
 ///
 /// # Safety
 ///
@@ -39,6 +48,59 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F
     }
 }
 
+struct ReallocFunc(
+    // INVARIANT: One of the following `krealloc`, `vrealloc`, `kvrealloc`.
+    unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void,
+);
+
+impl ReallocFunc {
+    fn krealloc() -> Self {
+        Self(bindings::krealloc)
+    }
+
+    // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
+    unsafe fn call(
+        &self,
+        ptr: Option<NonNull<u8>>,
+        layout: Layout,
+        flags: Flags,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        let size = aligned_size(layout);
+        let ptr = match ptr {
+            Some(ptr) => ptr.as_ptr(),
+            None => ptr::null(),
+        };
+
+        // SAFETY: `ptr` is valid by the safety requirements of this function.
+        let raw_ptr = unsafe {
+            // If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
+            self.0(ptr.cast(), size, flags.0).cast()
+        };
+
+        let ptr = if size == 0 {
+            NonNull::dangling()
+        } else {
+            NonNull::new(raw_ptr).ok_or(AllocError)?
+        };
+
+        Ok(NonNull::slice_from_raw_parts(ptr, size))
+    }
+}
+
+unsafe impl Allocator for Kmalloc {
+    unsafe fn realloc(
+        ptr: Option<NonNull<u8>>,
+        layout: Layout,
+        flags: Flags,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        let realloc = ReallocFunc::krealloc();
+
+        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
+        // allocated with this `Allocator`.
+        unsafe { realloc.call(ptr, layout, flags) }
+    }
+}
+
 unsafe impl GlobalAlloc for Kmalloc {
     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
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 05/25] rust: alloc: add module `allocator_test`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (3 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:41   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
                   ` (19 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

`Allocator`s, such as `Kmalloc`, will be used by e.g. `Box` and `Vec` in
subsequent patches, and hence this dependency propagates throughout the
whole kernel.

Add the `allocator_test` module that provides an empty implementation
for all `Allocator`s in the kernel, such that we don't break the
`rusttest` make target in subsequent patches.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs                |  9 +++++++--
 rust/kernel/alloc/allocator_test.rs | 19 +++++++++++++++++++
 2 files changed, 26 insertions(+), 2 deletions(-)
 create mode 100644 rust/kernel/alloc/allocator_test.rs

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index 8cabc888393b..90f4452b146a 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -2,12 +2,17 @@
 
 //! Extensions to the [`alloc`] crate.
 
-#[cfg(not(test))]
-#[cfg(not(testlib))]
+#[cfg(not(any(test, testlib)))]
 pub mod allocator;
 pub mod box_ext;
 pub mod vec_ext;
 
+#[cfg(any(test, testlib))]
+pub mod allocator_test;
+
+#[cfg(any(test, testlib))]
+pub use self::allocator_test as allocator;
+
 /// Indicates an allocation error.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct AllocError;
diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
new file mode 100644
index 000000000000..4785efc474a7
--- /dev/null
+++ b/rust/kernel/alloc/allocator_test.rs
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#![allow(missing_docs)]
+
+use super::{AllocError, Allocator, Flags};
+use core::alloc::Layout;
+use core::ptr::NonNull;
+
+pub struct Kmalloc;
+
+unsafe impl Allocator for Kmalloc {
+    unsafe fn realloc(
+        _ptr: Option<NonNull<u8>>,
+        _layout: Layout,
+        _flags: Flags,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        panic!();
+    }
+}
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (4 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 05/25] rust: alloc: add module `allocator_test` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:43   ` Alice Ryhl
  2024-08-04  6:44   ` Boqun Feng
  2024-08-01  0:02 ` [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
                   ` (18 subsequent siblings)
  24 siblings, 2 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous
allocator, typically used for larger objects, (much) larger than page
size.

All memory allocations made with `Vmalloc` end up in `vrealloc()`.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/helpers.c                      |  8 ++++++++
 rust/kernel/alloc/allocator.rs      | 24 ++++++++++++++++++++++++
 rust/kernel/alloc/allocator_test.rs |  1 +
 3 files changed, 33 insertions(+)

diff --git a/rust/helpers.c b/rust/helpers.c
index 92d3c03ae1bd..4c628986f0c9 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -33,6 +33,7 @@
 #include <linux/sched/signal.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 
@@ -200,6 +201,13 @@ rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags)
 }
 EXPORT_SYMBOL_GPL(rust_helper_krealloc);
 
+void * __must_check __realloc_size(2)
+rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
+{
+	return vrealloc(p, size, flags);
+}
+EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
+
 /*
  * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
  * use it in contexts where Rust expects a `usize` like slice (array) indices.
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index 397ae5bcc043..e9a3d0694f41 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -16,6 +16,12 @@
 /// `bindings::krealloc`.
 pub struct Kmalloc;
 
+/// The virtually contiguous kernel allocator.
+///
+/// The vmalloc allocator allocates pages from the page level allocator and maps them into the
+/// contiguous kernel virtual space.
+pub struct Vmalloc;
+
 /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
 fn aligned_size(new_layout: Layout) -> usize {
     // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
@@ -58,6 +64,10 @@ fn krealloc() -> Self {
         Self(bindings::krealloc)
     }
 
+    fn vrealloc() -> Self {
+        Self(bindings::vrealloc)
+    }
+
     // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
     unsafe fn call(
         &self,
@@ -136,6 +146,20 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
     }
 }
 
+unsafe impl Allocator for Vmalloc {
+    unsafe fn realloc(
+        ptr: Option<NonNull<u8>>,
+        layout: Layout,
+        flags: Flags,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        let realloc = ReallocFunc::vrealloc();
+
+        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
+        // allocated with this `Allocator`.
+        unsafe { realloc.call(ptr, layout, flags) }
+    }
+}
+
 #[global_allocator]
 static ALLOCATOR: Kmalloc = Kmalloc;
 
diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
index 4785efc474a7..e7bf2982f68f 100644
--- a/rust/kernel/alloc/allocator_test.rs
+++ b/rust/kernel/alloc/allocator_test.rs
@@ -7,6 +7,7 @@
 use core::ptr::NonNull;
 
 pub struct Kmalloc;
+pub type Vmalloc = Kmalloc;
 
 unsafe impl Allocator for Kmalloc {
     unsafe fn realloc(
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (5 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:43   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 08/25] rust: types: implement `Unique<T>` Danilo Krummrich
                   ` (17 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Implement `Allocator` for `KVmalloc`, an `Allocator` that tries to
allocate memory wth `kmalloc` first and, on failure, falls back to
`vmalloc`.

All memory allocations made with `KVmalloc` end up in
`kvrealloc_noprof()`; all frees in `kvfree()`.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/helpers.c                      |  7 +++++++
 rust/kernel/alloc/allocator.rs      | 24 ++++++++++++++++++++++++
 rust/kernel/alloc/allocator_test.rs |  1 +
 3 files changed, 32 insertions(+)

diff --git a/rust/helpers.c b/rust/helpers.c
index 4c628986f0c9..4ad7dc347523 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -208,6 +208,13 @@ rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
 }
 EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
 
+void * __must_check __realloc_size(2)
+rust_helper_kvrealloc(const void *p, size_t size, gfp_t flags)
+{
+	return kvrealloc(p, size, flags);
+}
+EXPORT_SYMBOL_GPL(rust_helper_kvrealloc);
+
 /*
  * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
  * use it in contexts where Rust expects a `usize` like slice (array) indices.
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index e9a3d0694f41..1e53f149db96 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -22,6 +22,12 @@
 /// contiguous kernel virtual space.
 pub struct Vmalloc;
 
+/// The kvmalloc kernel allocator.
+///
+/// Attempt to allocate physically contiguous memory, but upon failure, fall back to non-contiguous
+/// (vmalloc) allocation.
+pub struct KVmalloc;
+
 /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
 fn aligned_size(new_layout: Layout) -> usize {
     // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
@@ -68,6 +74,10 @@ fn vrealloc() -> Self {
         Self(bindings::vrealloc)
     }
 
+    fn kvrealloc() -> Self {
+        Self(bindings::kvrealloc)
+    }
+
     // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
     unsafe fn call(
         &self,
@@ -160,6 +170,20 @@ unsafe fn realloc(
     }
 }
 
+unsafe impl Allocator for KVmalloc {
+    unsafe fn realloc(
+        ptr: Option<NonNull<u8>>,
+        layout: Layout,
+        flags: Flags,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        let realloc = ReallocFunc::kvrealloc();
+
+        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
+        // allocated with this `Allocator`.
+        unsafe { realloc.call(ptr, layout, flags) }
+    }
+}
+
 #[global_allocator]
 static ALLOCATOR: Kmalloc = Kmalloc;
 
diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
index e7bf2982f68f..1b2642c547ec 100644
--- a/rust/kernel/alloc/allocator_test.rs
+++ b/rust/kernel/alloc/allocator_test.rs
@@ -8,6 +8,7 @@
 
 pub struct Kmalloc;
 pub type Vmalloc = Kmalloc;
+pub type KVmalloc = Kmalloc;
 
 unsafe impl Allocator for Kmalloc {
     unsafe fn realloc(
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 08/25] rust: types: implement `Unique<T>`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (6 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-04  6:54   ` Boqun Feng
  2024-08-01  0:02 ` [PATCH v3 09/25] rust: alloc: implement kernel `Box` Danilo Krummrich
                   ` (16 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Implement the `Unique` type as a prerequisite for `Box` and `Vec`
introduced in subsequent patches.

`Unique` serves as wrapper around a `NonNull`, but indicates that the
possessor of this wrapper owns the referent.

This type already exists in Rust's core library, but, unfortunately, is
exposed as unstable API and hence shouldn't be used in the kernel.

This implementation of `Unique` is almost identical, but mostly stripped
down to the functionality we need for `Box` and `Vec`. Additionally, all
unstable features are removed and / or replaced by stable ones.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/types.rs | 183 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 183 insertions(+)

diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index bd189d646adb..7cf89067b5fc 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -473,3 +473,186 @@ unsafe impl AsBytes for str {}
 // does not have any uninitialized portions either.
 unsafe impl<T: AsBytes> AsBytes for [T] {}
 unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
+
+/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
+/// of this wrapper owns the referent. Useful for building abstractions like
+/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
+///
+/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
+/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
+/// the kind of strong aliasing guarantees an instance of `T` can expect:
+/// the referent of the pointer should not be modified without a unique path to
+/// its owning Unique.
+///
+/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
+/// consider using `NonNull`, which has weaker semantics.
+///
+/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
+/// is never dereferenced. This is so that enums may use this forbidden value
+/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
+/// However the pointer may still dangle if it isn't dereferenced.
+///
+/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
+/// for any type which upholds Unique's aliasing requirements.
+#[repr(transparent)]
+pub struct Unique<T: ?Sized> {
+    pointer: NonNull<T>,
+    // NOTE: this marker has no consequences for variance, but is necessary
+    // for dropck to understand that we logically own a `T`.
+    //
+    // For details, see:
+    // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
+    _marker: PhantomData<T>,
+}
+
+/// `Unique` pointers are `Send` if `T` is `Send` because the data they
+/// reference is unaliased. Note that this aliasing invariant is
+/// unenforced by the type system; the abstraction using the
+/// `Unique` must enforce it.
+unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
+
+/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
+/// reference is unaliased. Note that this aliasing invariant is
+/// unenforced by the type system; the abstraction using the
+/// `Unique` must enforce it.
+unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
+
+impl<T: Sized> Unique<T> {
+    /// Creates a new `Unique` that is dangling, but well-aligned.
+    ///
+    /// This is useful for initializing types which lazily allocate, like
+    /// `Vec::new` does.
+    ///
+    /// Note that the pointer value may potentially represent a valid pointer to
+    /// a `T`, which means this must not be used as a "not yet initialized"
+    /// sentinel value. Types that lazily allocate must track initialization by
+    /// some other means.
+    #[must_use]
+    #[inline]
+    pub const fn dangling() -> Self {
+        Unique {
+            pointer: NonNull::dangling(),
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl<T: ?Sized> Unique<T> {
+    /// Creates a new `Unique`.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be non-null.
+    #[inline]
+    pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
+        // SAFETY: the caller must guarantee that `ptr` is non-null.
+        unsafe {
+            Unique {
+                pointer: NonNull::new_unchecked(ptr),
+                _marker: PhantomData,
+            }
+        }
+    }
+
+    /// Creates a new `Unique` if `ptr` is non-null.
+    #[allow(clippy::manual_map)]
+    #[inline]
+    pub fn new(ptr: *mut T) -> Option<Self> {
+        if let Some(pointer) = NonNull::new(ptr) {
+            Some(Unique {
+                pointer,
+                _marker: PhantomData,
+            })
+        } else {
+            None
+        }
+    }
+
+    /// Acquires the underlying `*mut` pointer.
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[inline]
+    pub const fn as_ptr(self) -> *mut T {
+        self.pointer.as_ptr()
+    }
+
+    /// Dereferences the content.
+    ///
+    /// The resulting lifetime is bound to self so this behaves "as if"
+    /// it were actually an instance of T that is getting borrowed. If a longer
+    /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
+    ///
+    /// # Safety
+    ///
+    /// Safety requirements for this function are inherited from [NonNull::as_ref].
+    ///
+    #[must_use]
+    #[inline]
+    pub const unsafe fn as_ref(&self) -> &T {
+        // SAFETY: the caller must guarantee that `self` meets all the
+        // requirements for a reference.
+        unsafe { self.pointer.as_ref() }
+    }
+
+    /// Mutably dereferences the content.
+    ///
+    /// The resulting lifetime is bound to self so this behaves "as if"
+    /// it were actually an instance of T that is getting borrowed. If a longer
+    /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
+    ///
+    /// # Safety
+    ///
+    /// Safety requirements for this function are inherited from [NonNull::as_mut].
+    #[must_use]
+    #[inline]
+    pub unsafe fn as_mut(&mut self) -> &mut T {
+        // SAFETY: the caller must guarantee that `self` meets all the
+        // requirements for a mutable reference.
+        unsafe { self.pointer.as_mut() }
+    }
+
+    /// Casts to a pointer of another type.
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[inline]
+    pub fn cast<U>(self) -> Unique<U> {
+        Unique::from(self.pointer.cast())
+    }
+
+    /// Acquires the underlying `*mut` pointer.
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[inline]
+    pub const fn as_non_null(self) -> NonNull<T> {
+        self.pointer
+    }
+}
+
+impl<T: ?Sized> Clone for Unique<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T: ?Sized> Copy for Unique<T> {}
+
+impl<T: ?Sized> From<&mut T> for Unique<T> {
+    /// Converts a `&mut T` to a `Unique<T>`.
+    ///
+    /// This conversion is infallible since references cannot be null.
+    #[inline]
+    fn from(reference: &mut T) -> Self {
+        Self::from(NonNull::from(reference))
+    }
+}
+
+impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
+    /// Converts a `NonNull<T>` to a `Unique<T>`.
+    ///
+    /// This conversion is infallible since `NonNull` cannot be null.
+    #[inline]
+    fn from(pointer: NonNull<T>) -> Self {
+        Unique {
+            pointer,
+            _marker: PhantomData,
+        }
+    }
+}
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 09/25] rust: alloc: implement kernel `Box`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (7 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 08/25] rust: types: implement `Unique<T>` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  8:55   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 10/25] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
                   ` (15 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

`Box` provides the simplest way to allocate memory for a generic type
with one of the kernel's allocators, e.g. `Kmalloc`, `Vmalloc` or
`KVmalloc`.

In contrast to Rust's `Box` type, the kernel `Box` type considers the
kernel's GFP flags for all appropriate functions, always reports
allocation failures through `Result<_, AllocError>` and remains
independent from unstable features.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs      |   6 +
 rust/kernel/alloc/kbox.rs | 326 ++++++++++++++++++++++++++++++++++++++
 rust/kernel/init.rs       |  35 +++-
 rust/kernel/prelude.rs    |   2 +-
 rust/kernel/types.rs      |  26 +++
 5 files changed, 393 insertions(+), 2 deletions(-)
 create mode 100644 rust/kernel/alloc/kbox.rs

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index 90f4452b146a..4e99eef26156 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -5,6 +5,7 @@
 #[cfg(not(any(test, testlib)))]
 pub mod allocator;
 pub mod box_ext;
+pub mod kbox;
 pub mod vec_ext;
 
 #[cfg(any(test, testlib))]
@@ -13,6 +14,11 @@
 #[cfg(any(test, testlib))]
 pub use self::allocator_test as allocator;
 
+pub use self::kbox::Box;
+pub use self::kbox::KBox;
+pub use self::kbox::KVBox;
+pub use self::kbox::VBox;
+
 /// Indicates an allocation error.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct AllocError;
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
new file mode 100644
index 000000000000..7074f00e07bc
--- /dev/null
+++ b/rust/kernel/alloc/kbox.rs
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Implementation of [`Box`].
+
+use super::{AllocError, Allocator, Flags};
+use core::fmt;
+use core::marker::PhantomData;
+use core::mem::ManuallyDrop;
+use core::mem::MaybeUninit;
+use core::ops::{Deref, DerefMut};
+use core::pin::Pin;
+use core::ptr;
+use core::result::Result;
+
+use crate::types::Unique;
+
+/// The kernel's [`Box`] type.
+///
+/// `Box` provides the simplest way to allocate memory for a generic type with one of the kernel's
+/// allocators, e.g. `Kmalloc`, `Vmalloc` or `KVmalloc`.
+///
+/// For non-zero-sized values, a [`Box`] will use the given allocator `A` for its allocation. For
+/// the most common allocators the type aliases `KBox`, `VBox` and `KVBox` exist.
+///
+/// It is valid to convert both ways between a [`Box`] and a raw pointer allocated with any
+/// `Allocator`, given that the `Layout` used with the allocator is correct for the type.
+///
+/// For zero-sized values the [`Box`]' pointer must be `dangling_mut::<T>`; no memory is allocated.
+///
+/// So long as `T: Sized`, a `Box<T>` is guaranteed to be represented as a single pointer and is
+/// also ABI-compatible with C pointers (i.e. the C type `T*`).
+///
+/// # Invariants
+///
+/// The [`Box`]' pointer always properly aligned and either points to memory allocated with `A` or,
+/// for zero-sized types, is a dangling pointer.
+///
+/// # Examples
+///
+/// ```
+/// let b = KBox::<u64>::new(24_u64, GFP_KERNEL)?;
+///
+/// assert_eq!(*b, 24_u64);
+///
+/// # Ok::<(), Error>(())
+/// ```
+///
+/// ```
+/// struct Huge([u8; 1 << 24]);
+///
+/// assert!(KVBox::<Huge>::new_uninit(GFP_KERNEL).is_ok());
+/// ```
+pub struct Box<T: ?Sized, A: Allocator>(Unique<T>, PhantomData<A>);
+
+/// Type alias for `Box` with a `Kmalloc` allocator.
+///
+/// # Examples
+///
+/// ```
+/// let b = KBox::new(24_u64, GFP_KERNEL)?;
+///
+/// assert_eq!(*b, 24_u64);
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub type KBox<T> = Box<T, super::allocator::Kmalloc>;
+
+/// Type alias for `Box` with a `Vmalloc` allocator.
+///
+/// # Examples
+///
+/// ```
+/// let b = VBox::new(24_u64, GFP_KERNEL)?;
+///
+/// assert_eq!(*b, 24_u64);
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub type VBox<T> = Box<T, super::allocator::Vmalloc>;
+
+/// Type alias for `Box` with a `KVmalloc` allocator.
+///
+/// # Examples
+///
+/// ```
+/// let b = KVBox::new(24_u64, GFP_KERNEL)?;
+///
+/// assert_eq!(*b, 24_u64);
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub type KVBox<T> = Box<T, super::allocator::KVmalloc>;
+
+impl<T, A> Box<T, A>
+where
+    T: ?Sized,
+    A: Allocator,
+{
+    /// Constructs a `Box<T, A>` from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// `raw` must point to valid memory, previously allocated with `A`, and at least the size of
+    /// type `T`.
+    #[inline]
+    pub const unsafe fn from_raw_alloc(raw: *mut T, alloc: PhantomData<A>) -> Self {
+        // SAFETY: Safe by the requirements of this function.
+        Box(unsafe { Unique::new_unchecked(raw) }, alloc)
+    }
+
+    /// Consumes the `Box<T, A>`, returning a wrapped raw pointer and `PhantomData` of the allocator
+    /// it was allocated with.
+    pub fn into_raw_alloc(b: Self) -> (*mut T, PhantomData<A>) {
+        let b = ManuallyDrop::new(b);
+        let alloc = unsafe { ptr::read(&b.1) };
+        (b.0.as_ptr(), alloc)
+    }
+
+    /// Constructs a `Box<T, A>` from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// `raw` must point to valid memory, previously allocated with `A`, and at least the size of
+    /// type `T`.
+    #[inline]
+    pub const unsafe fn from_raw(raw: *mut T) -> Self {
+        // SAFETY: Validity of `raw` is guaranteed by the safety preconditions of this function.
+        unsafe { Box::from_raw_alloc(raw, PhantomData::<A>) }
+    }
+
+    /// Consumes the `Box<T>`, returning a wrapped raw pointer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let x = KBox::new(24, GFP_KERNEL)?;
+    /// let ptr = KBox::into_raw(x);
+    /// let x = unsafe { KBox::from_raw(ptr) };
+    ///
+    /// assert_eq!(*x, 24);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    #[inline]
+    pub fn into_raw(b: Self) -> *mut T {
+        Self::into_raw_alloc(b).0
+    }
+
+    /// Consumes and leaks the `Box<T>`, returning a mutable reference, &'a mut T.
+    #[inline]
+    pub fn leak<'a>(b: Self) -> &'a mut T
+    where
+        T: 'a,
+    {
+        // SAFETY: `Box::into_raw` always returns a properly aligned and dereferenceable pointer
+        // which points to an initialized instance of `T`.
+        unsafe { &mut *Box::into_raw(b) }
+    }
+
+    /// Converts a `Box<T>` into a `Pin<Box<T>>`.
+    #[inline]
+    pub fn into_pin(b: Self) -> Pin<Self>
+    where
+        A: 'static,
+    {
+        // SAFETY: It's not possible to move or replace the insides of a `Pin<Box<T>>` when
+        // `T: !Unpin`, so it's safe to pin it directly without any additional requirements.
+        unsafe { Pin::new_unchecked(b) }
+    }
+}
+
+impl<T, A> Box<MaybeUninit<T>, A>
+where
+    A: Allocator,
+{
+    /// Converts to `Box<T, A>`.
+    ///
+    /// # Safety
+    ///
+    /// As with MaybeUninit::assume_init, it is up to the caller to guarantee that the value really
+    /// is in an initialized state. Calling this when the content is not yet fully initialized
+    /// causes immediate undefined behavior.
+    pub unsafe fn assume_init(b: Self) -> Box<T, A> {
+        let raw = Self::into_raw(b);
+        // SAFETY: Reconstruct the `Box<MaybeUninit<T>, A>` as Box<T, A> now that has been
+        // initialized. `raw` and `alloc` are safe by the invariants of `Box`.
+        unsafe { Box::from_raw(raw as *mut T) }
+    }
+
+    /// Writes the value and converts to `Box<T, A>`.
+    pub fn write(mut b: Self, value: T) -> Box<T, A> {
+        (*b).write(value);
+        // SAFETY: We've just initialized `boxed`'s value.
+        unsafe { Self::assume_init(b) }
+    }
+}
+
+impl<T, A> Box<T, A>
+where
+    A: Allocator,
+{
+    fn is_zst() -> bool {
+        core::mem::size_of::<T>() == 0
+    }
+
+    /// Allocates memory with the allocator `A` and then places `x` into it.
+    ///
+    /// This doesn’t actually allocate if T is zero-sized.
+    pub fn new(x: T, flags: Flags) -> Result<Self, AllocError> {
+        let b = Self::new_uninit(flags)?;
+        Ok(Box::write(b, x))
+    }
+
+    /// Constructs a new `Box<T, A>` with uninitialized contents.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let b = KBox::<u64>::new_uninit(GFP_KERNEL)?;
+    /// let b = KBox::write(b, 24);
+    ///
+    /// assert_eq!(*b, 24_u64);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>, A>, AllocError> {
+        let ptr = if Self::is_zst() {
+            Unique::dangling()
+        } else {
+            let layout = core::alloc::Layout::new::<MaybeUninit<T>>();
+            let ptr = A::alloc(layout, flags)?;
+
+            ptr.cast().into()
+        };
+
+        Ok(Box(ptr, PhantomData::<A>))
+    }
+
+    /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then `x` will be
+    /// pinned in memory and unable to be moved.
+    #[inline]
+    pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
+    where
+        A: 'static,
+    {
+        Ok(Self::new(x, flags)?.into())
+    }
+}
+
+impl<T, A> From<Box<T, A>> for Pin<Box<T, A>>
+where
+    T: ?Sized,
+    A: Allocator,
+    A: 'static,
+{
+    /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
+    /// `*boxed` will be pinned in memory and unable to be moved.
+    ///
+    /// This conversion does not allocate on the heap and happens in place.
+    ///
+    /// This is also available via [`Box::into_pin`].
+    ///
+    /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
+    /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
+    /// This `From` implementation is useful if you already have a `Box<T>`, or you are
+    /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
+    fn from(b: Box<T, A>) -> Self {
+        Box::into_pin(b)
+    }
+}
+
+impl<T, A> Deref for Box<T, A>
+where
+    T: ?Sized,
+    A: Allocator,
+{
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // SAFETY: `self.0` is always properly aligned, dereferenceable and points to an initialized
+        // instance of `T`.
+        unsafe { self.0.as_ref() }
+    }
+}
+
+impl<T, A> DerefMut for Box<T, A>
+where
+    T: ?Sized,
+    A: Allocator,
+{
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: `self.0` is always properly aligned, dereferenceable and points to an initialized
+        // instance of `T`.
+        unsafe { self.0.as_mut() }
+    }
+}
+
+impl<T, A> fmt::Debug for Box<T, A>
+where
+    T: ?Sized + fmt::Debug,
+    A: Allocator,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+impl<T, A> Drop for Box<T, A>
+where
+    T: ?Sized,
+    A: Allocator,
+{
+    fn drop(&mut self) {
+        let ptr = self.0.as_ptr();
+
+        // SAFETY: We need to drop `self.0` in place, before we free the backing memory.
+        unsafe { core::ptr::drop_in_place(ptr) };
+
+        // SAFETY: `ptr` is always properly aligned, dereferenceable and points to an initialized
+        // instance of `T`.
+        if unsafe { core::mem::size_of_val(&*ptr) } != 0 {
+            // SAFETY: `ptr` was previously allocated with `A`.
+            unsafe { A::free(self.0.as_non_null().cast()) };
+        }
+    }
+}
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 495c09ebe3a3..5fd7a0ffabd2 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -211,7 +211,7 @@
 //! [`pin_init!`]: crate::pin_init!
 
 use crate::{
-    alloc::{box_ext::BoxExt, AllocError, Flags},
+    alloc::{box_ext::BoxExt, AllocError, Allocator, Flags},
     error::{self, Error},
     sync::UniqueArc,
     types::{Opaque, ScopeGuard},
@@ -1178,6 +1178,39 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
     }
 }
 
+impl<T, A> InPlaceInit<T> for crate::alloc::Box<T, A>
+where
+    A: Allocator + 'static,
+{
+    #[inline]
+    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
+    where
+        E: From<AllocError>,
+    {
+        let mut this = crate::alloc::Box::<_, A>::new_uninit(flags)?;
+        let slot = this.as_mut_ptr();
+        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
+        // slot is valid and will not be moved, because we pin it later.
+        unsafe { init.__pinned_init(slot)? };
+        // SAFETY: All fields have been initialized.
+        Ok(unsafe { crate::alloc::Box::assume_init(this) }.into())
+    }
+
+    #[inline]
+    fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
+    where
+        E: From<AllocError>,
+    {
+        let mut this = crate::alloc::Box::<_, A>::new_uninit(flags)?;
+        let slot = this.as_mut_ptr();
+        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
+        // slot is valid.
+        unsafe { init.__init(slot)? };
+        // SAFETY: All fields have been initialized.
+        Ok(unsafe { crate::alloc::Box::assume_init(this) })
+    }
+}
+
 impl<T> InPlaceInit<T> for UniqueArc<T> {
     #[inline]
     fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index b37a0b3180fb..39f9331a48e2 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -14,7 +14,7 @@
 #[doc(no_inline)]
 pub use core::pin::Pin;
 
-pub use crate::alloc::{box_ext::BoxExt, flags::*, vec_ext::VecExt};
+pub use crate::alloc::{box_ext::BoxExt, flags::*, vec_ext::VecExt, KBox, KVBox, VBox};
 
 #[doc(no_inline)]
 pub use alloc::{boxed::Box, vec::Vec};
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 7cf89067b5fc..a60d59c377bd 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -2,6 +2,7 @@
 
 //! Kernel types.
 
+use crate::alloc::Allocator;
 use crate::init::{self, PinInit};
 use alloc::boxed::Box;
 use core::{
@@ -89,6 +90,31 @@ unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
     }
 }
 
+impl<T: 'static, A> ForeignOwnable for crate::alloc::Box<T, A>
+where
+    A: Allocator,
+{
+    type Borrowed<'a> = &'a T;
+
+    fn into_foreign(self) -> *const core::ffi::c_void {
+        crate::alloc::Box::into_raw(self) as _
+    }
+
+    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
+        // SAFETY: The safety requirements for this function ensure that the object is still alive,
+        // so it is safe to dereference the raw pointer.
+        // The safety requirements of `from_foreign` also ensure that the object remains alive for
+        // the lifetime of the returned value.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
+        // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
+        // call to `Self::into_foreign`.
+        unsafe { crate::alloc::Box::from_raw(ptr as _) }
+    }
+}
+
 impl ForeignOwnable for () {
     type Borrowed<'a> = ();
 
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 10/25] rust: treewide: switch to our kernel `Box` type
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (8 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 09/25] rust: alloc: implement kernel `Box` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 11/25] rust: alloc: remove `BoxExt` extension Danilo Krummrich
                   ` (14 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we got the kernel `Box` type in place, convert all existing
`Box` users to make use of it.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/init.rs               | 41 ++++++++++++++++---------------
 rust/kernel/init/__internal.rs    |  2 +-
 rust/kernel/sync/arc.rs           | 17 ++++++-------
 rust/kernel/sync/condvar.rs       |  4 +--
 rust/kernel/sync/lock/mutex.rs    |  2 +-
 rust/kernel/sync/lock/spinlock.rs |  2 +-
 rust/kernel/workqueue.rs          | 20 +++++++--------
 7 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 5fd7a0ffabd2..b3159eb1eb02 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -68,7 +68,7 @@
 //! #     a <- new_mutex!(42, "Foo::a"),
 //! #     b: 24,
 //! # });
-//! let foo: Result<Pin<Box<Foo>>> = Box::pin_init(foo, GFP_KERNEL);
+//! let foo: Result<Pin<KBox<Foo>>> = KBox::pin_init(foo, GFP_KERNEL);
 //! ```
 //!
 //! For more information see the [`pin_init!`] macro.
@@ -93,14 +93,14 @@
 //! struct DriverData {
 //!     #[pin]
 //!     status: Mutex<i32>,
-//!     buffer: Box<[u8; 1_000_000]>,
+//!     buffer: KBox<[u8; 1_000_000]>,
 //! }
 //!
 //! impl DriverData {
 //!     fn new() -> impl PinInit<Self, Error> {
 //!         try_pin_init!(Self {
 //!             status <- new_mutex!(0, "DriverData::status"),
-//!             buffer: Box::init(kernel::init::zeroed(), GFP_KERNEL)?,
+//!             buffer: KBox::init(kernel::init::zeroed(), GFP_KERNEL)?,
 //!         })
 //!     }
 //! }
@@ -211,7 +211,7 @@
 //! [`pin_init!`]: crate::pin_init!
 
 use crate::{
-    alloc::{box_ext::BoxExt, AllocError, Allocator, Flags},
+    alloc::{box_ext::BoxExt, AllocError, Allocator, Flags, KBox},
     error::{self, Error},
     sync::UniqueArc,
     types::{Opaque, ScopeGuard},
@@ -297,7 +297,7 @@ macro_rules! stack_pin_init {
 /// struct Foo {
 ///     #[pin]
 ///     a: Mutex<usize>,
-///     b: Box<Bar>,
+///     b: KBox<Bar>,
 /// }
 ///
 /// struct Bar {
@@ -306,7 +306,7 @@ macro_rules! stack_pin_init {
 ///
 /// stack_try_pin_init!(let foo: Result<Pin<&mut Foo>, AllocError> = pin_init!(Foo {
 ///     a <- new_mutex!(42),
-///     b: Box::new(Bar {
+///     b: KBox::new(Bar {
 ///         x: 64,
 ///     }, GFP_KERNEL)?,
 /// }));
@@ -323,7 +323,7 @@ macro_rules! stack_pin_init {
 /// struct Foo {
 ///     #[pin]
 ///     a: Mutex<usize>,
-///     b: Box<Bar>,
+///     b: KBox<Bar>,
 /// }
 ///
 /// struct Bar {
@@ -332,7 +332,7 @@ macro_rules! stack_pin_init {
 ///
 /// stack_try_pin_init!(let foo: Pin<&mut Foo> =? pin_init!(Foo {
 ///     a <- new_mutex!(42),
-///     b: Box::new(Bar {
+///     b: KBox::new(Bar {
 ///         x: 64,
 ///     }, GFP_KERNEL)?,
 /// }));
@@ -391,7 +391,7 @@ macro_rules! stack_try_pin_init {
 ///     },
 /// });
 /// # initializer }
-/// # Box::pin_init(demo(), GFP_KERNEL).unwrap();
+/// # KBox::pin_init(demo(), GFP_KERNEL).unwrap();
 /// ```
 ///
 /// Arbitrary Rust expressions can be used to set the value of a variable.
@@ -461,7 +461,7 @@ macro_rules! stack_try_pin_init {
 /// #         })
 /// #     }
 /// # }
-/// let foo = Box::pin_init(Foo::new(), GFP_KERNEL);
+/// let foo = KBox::pin_init(Foo::new(), GFP_KERNEL);
 /// ```
 ///
 /// They can also easily embed it into their own `struct`s:
@@ -593,7 +593,7 @@ macro_rules! pin_init {
 /// use kernel::{init::{self, PinInit}, error::Error};
 /// #[pin_data]
 /// struct BigBuf {
-///     big: Box<[u8; 1024 * 1024 * 1024]>,
+///     big: KBox<[u8; 1024 * 1024 * 1024]>,
 ///     small: [u8; 1024 * 1024],
 ///     ptr: *mut u8,
 /// }
@@ -601,7 +601,7 @@ macro_rules! pin_init {
 /// impl BigBuf {
 ///     fn new() -> impl PinInit<Self, Error> {
 ///         try_pin_init!(Self {
-///             big: Box::init(init::zeroed(), GFP_KERNEL)?,
+///             big: KBox::init(init::zeroed(), GFP_KERNEL)?,
 ///             small: [0; 1024 * 1024],
 ///             ptr: core::ptr::null_mut(),
 ///         }? Error)
@@ -693,16 +693,16 @@ macro_rules! init {
 /// # Examples
 ///
 /// ```rust
-/// use kernel::{init::{PinInit, zeroed}, error::Error};
+/// use kernel::{alloc::KBox, init::{PinInit, zeroed}, error::Error};
 /// struct BigBuf {
-///     big: Box<[u8; 1024 * 1024 * 1024]>,
+///     big: KBox<[u8; 1024 * 1024 * 1024]>,
 ///     small: [u8; 1024 * 1024],
 /// }
 ///
 /// impl BigBuf {
 ///     fn new() -> impl Init<Self, Error> {
 ///         try_init!(Self {
-///             big: Box::init(zeroed(), GFP_KERNEL)?,
+///             big: KBox::init(zeroed(), GFP_KERNEL)?,
 ///             small: [0; 1024 * 1024],
 ///         }? Error)
 ///     }
@@ -825,7 +825,7 @@ fn pin_chain<F>(self, f: F) -> ChainPinInit<Self, F, T, E>
 }
 
 /// An initializer returned by [`PinInit::pin_chain`].
-pub struct ChainPinInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, Box<T>)>);
+pub struct ChainPinInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, KBox<T>)>);
 
 // SAFETY: The `__pinned_init` function is implemented such that it
 // - returns `Ok(())` on successful initialization,
@@ -924,7 +924,7 @@ fn chain<F>(self, f: F) -> ChainInit<Self, F, T, E>
 }
 
 /// An initializer returned by [`Init::chain`].
-pub struct ChainInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, Box<T>)>);
+pub struct ChainInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, KBox<T>)>);
 
 // SAFETY: The `__init` function is implemented such that it
 // - returns `Ok(())` on successful initialization,
@@ -1008,8 +1008,9 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
 /// # Examples
 ///
 /// ```rust
-/// use kernel::{error::Error, init::init_array_from_fn};
-/// let array: Box<[usize; 1_000]> = Box::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL).unwrap();
+/// use kernel::{alloc::KBox, error::Error, init::init_array_from_fn};
+/// let array: KBox<[usize; 1_000]> =
+///     KBox::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL).unwrap();
 /// assert_eq!(array.len(), 1_000);
 /// ```
 pub fn init_array_from_fn<I, const N: usize, T, E>(
@@ -1349,7 +1350,7 @@ macro_rules! impl_zeroable {
     //
     // In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant.
     {<T: ?Sized>} Option<NonNull<T>>,
-    {<T: ?Sized>} Option<Box<T>>,
+    {<T: ?Sized>} Option<KBox<T>>,
 
     // SAFETY: `null` pointer is valid.
     //
diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs
index db3372619ecd..dfb2204918c7 100644
--- a/rust/kernel/init/__internal.rs
+++ b/rust/kernel/init/__internal.rs
@@ -102,7 +102,7 @@ fn make_closure<F, O, E>(self, f: F) -> F
     }
 }
 
-pub struct AllData<T: ?Sized>(PhantomData<fn(Box<T>) -> Box<T>>);
+pub struct AllData<T: ?Sized>(PhantomData<fn(KBox<T>) -> KBox<T>>);
 
 impl<T: ?Sized> Clone for AllData<T> {
     fn clone(&self) -> Self {
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index 3673496c2363..b5c84995d7d2 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -16,13 +16,12 @@
 //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
 
 use crate::{
-    alloc::{box_ext::BoxExt, AllocError, Flags},
+    alloc::{AllocError, Flags, KBox},
     error::{self, Error},
     init::{self, InPlaceInit, Init, PinInit},
     try_init,
     types::{ForeignOwnable, Opaque},
 };
-use alloc::boxed::Box;
 use core::{
     alloc::Layout,
     fmt,
@@ -203,11 +202,11 @@ pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
             data: contents,
         };
 
-        let inner = <Box<_> as BoxExt<_>>::new(value, flags)?;
+        let inner = KBox::new(value, flags)?;
 
         // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
         // `Arc` object.
-        Ok(unsafe { Self::from_inner(Box::leak(inner).into()) })
+        Ok(unsafe { Self::from_inner(KBox::leak(inner).into()) })
     }
 
     /// Use the given initializer to in-place initialize a `T`.
@@ -422,8 +421,8 @@ fn drop(&mut self) {
         if is_zero {
             // The count reached zero, we must free the memory.
             //
-            // SAFETY: The pointer was initialised from the result of `Box::leak`.
-            unsafe { drop(Box::from_raw(self.ptr.as_ptr())) };
+            // SAFETY: The pointer was initialised from the result of `KBox::leak`.
+            unsafe { drop(KBox::from_raw(self.ptr.as_ptr())) };
         }
     }
 }
@@ -668,7 +667,7 @@ pub fn new(value: T, flags: Flags) -> Result<Self, AllocError> {
     /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet.
     pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError> {
         // INVARIANT: The refcount is initialised to a non-zero value.
-        let inner = Box::try_init::<AllocError>(
+        let inner = KBox::try_init::<AllocError>(
             try_init!(ArcInner {
                 // SAFETY: There are no safety requirements for this FFI call.
                 refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
@@ -678,8 +677,8 @@ pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError>
         )?;
         Ok(UniqueArc {
             // INVARIANT: The newly-created object has a refcount of 1.
-            // SAFETY: The pointer from the `Box` is valid.
-            inner: unsafe { Arc::from_inner(Box::leak(inner).into()) },
+            // SAFETY: The pointer from the `KBox` is valid.
+            inner: unsafe { Arc::from_inner(KBox::leak(inner).into()) },
         })
     }
 }
diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs
index 2b306afbe56d..2081932bb4b9 100644
--- a/rust/kernel/sync/condvar.rs
+++ b/rust/kernel/sync/condvar.rs
@@ -70,8 +70,8 @@ macro_rules! new_condvar {
 /// }
 ///
 /// /// Allocates a new boxed `Example`.
-/// fn new_example() -> Result<Pin<Box<Example>>> {
-///     Box::pin_init(pin_init!(Example {
+/// fn new_example() -> Result<Pin<KBox<Example>>> {
+///     KBox::pin_init(pin_init!(Example {
 ///         value <- new_mutex!(0),
 ///         value_changed <- new_condvar!(),
 ///     }), GFP_KERNEL)
diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs
index 30632070ee67..f8f6d530db7d 100644
--- a/rust/kernel/sync/lock/mutex.rs
+++ b/rust/kernel/sync/lock/mutex.rs
@@ -58,7 +58,7 @@ macro_rules! new_mutex {
 /// }
 ///
 /// // Allocate a boxed `Example`.
-/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?;
+/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
 /// assert_eq!(e.c, 10);
 /// assert_eq!(e.d.lock().a, 20);
 /// assert_eq!(e.d.lock().b, 30);
diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs
index ea5c5bc1ce12..a9096a4dc42a 100644
--- a/rust/kernel/sync/lock/spinlock.rs
+++ b/rust/kernel/sync/lock/spinlock.rs
@@ -56,7 +56,7 @@ macro_rules! new_spinlock {
 /// }
 ///
 /// // Allocate a boxed `Example`.
-/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?;
+/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
 /// assert_eq!(e.c, 10);
 /// assert_eq!(e.d.lock().a, 20);
 /// assert_eq!(e.d.lock().b, 30);
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index 553a5cba2adc..94318472507f 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -216,7 +216,7 @@ pub fn try_spawn<T: 'static + Send + FnOnce()>(
             func: Some(func),
         });
 
-        self.enqueue(Box::pin_init(init, flags).map_err(|_| AllocError)?);
+        self.enqueue(KBox::pin_init(init, flags).map_err(|_| AllocError)?);
         Ok(())
     }
 }
@@ -239,9 +239,9 @@ fn project(self: Pin<&mut Self>) -> &mut Option<T> {
 }
 
 impl<T: FnOnce()> WorkItem for ClosureWork<T> {
-    type Pointer = Pin<Box<Self>>;
+    type Pointer = Pin<KBox<Self>>;
 
-    fn run(mut this: Pin<Box<Self>>) {
+    fn run(mut this: Pin<KBox<Self>>) {
         if let Some(func) = this.as_mut().project().take() {
             (func)()
         }
@@ -297,7 +297,7 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
 
 /// Defines the method that should be called directly when a work item is executed.
 ///
-/// This trait is implemented by `Pin<Box<T>>` and [`Arc<T>`], and is mainly intended to be
+/// This trait is implemented by `Pin<KBox<T>>` and [`Arc<T>`], and is mainly intended to be
 /// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`]
 /// instead. The [`run`] method on this trait will usually just perform the appropriate
 /// `container_of` translation and then call into the [`run`][WorkItem::run] method from the
@@ -329,7 +329,7 @@ pub unsafe trait WorkItemPointer<const ID: u64>: RawWorkItem<ID> {
 /// This trait is used when the `work_struct` field is defined using the [`Work`] helper.
 pub trait WorkItem<const ID: u64 = 0> {
     /// The pointer type that this struct is wrapped in. This will typically be `Arc<Self>` or
-    /// `Pin<Box<Self>>`.
+    /// `Pin<KBox<Self>>`.
     type Pointer: WorkItemPointer<ID>;
 
     /// The method that should be called when this work item is executed.
@@ -565,7 +565,7 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
     }
 }
 
-unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>>
+unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<KBox<T>>
 where
     T: WorkItem<ID, Pointer = Self>,
     T: HasWork<T, ID>,
@@ -576,7 +576,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>>
         // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`.
         let ptr = unsafe { T::work_container_of(ptr) };
         // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership.
-        let boxed = unsafe { Box::from_raw(ptr) };
+        let boxed = unsafe { KBox::from_raw(ptr) };
         // SAFETY: The box was already pinned when it was enqueued.
         let pinned = unsafe { Pin::new_unchecked(boxed) };
 
@@ -584,7 +584,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>>
     }
 }
 
-unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<Box<T>>
+unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<KBox<T>>
 where
     T: WorkItem<ID, Pointer = Self>,
     T: HasWork<T, ID>,
@@ -598,9 +598,9 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
         // SAFETY: We're not going to move `self` or any of its fields, so its okay to temporarily
         // remove the `Pin` wrapper.
         let boxed = unsafe { Pin::into_inner_unchecked(self) };
-        let ptr = Box::into_raw(boxed);
+        let ptr = KBox::into_raw(boxed);
 
-        // SAFETY: Pointers into a `Box` point at a valid value.
+        // SAFETY: Pointers into a `KBox` point at a valid value.
         let work_ptr = unsafe { T::raw_get_work(ptr) };
         // SAFETY: `raw_get_work` returns a pointer to a valid value.
         let work_ptr = unsafe { Work::raw_get(work_ptr) };
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 11/25] rust: alloc: remove `BoxExt` extension
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (9 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 10/25] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01 14:53   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 12/25] rust: alloc: add `Box` to prelude Danilo Krummrich
                   ` (13 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that all existing `Box` users were moved to the kernel `Box` type,
remove the `BoxExt` extension.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs         |  1 -
 rust/kernel/alloc/box_ext.rs | 56 ------------------------------------
 rust/kernel/init.rs          | 34 +---------------------
 rust/kernel/lib.rs           |  1 -
 rust/kernel/prelude.rs       |  4 +--
 rust/kernel/types.rs         | 23 ---------------
 6 files changed, 3 insertions(+), 116 deletions(-)
 delete mode 100644 rust/kernel/alloc/box_ext.rs

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index 4e99eef26156..4bddd023aa7f 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -4,7 +4,6 @@
 
 #[cfg(not(any(test, testlib)))]
 pub mod allocator;
-pub mod box_ext;
 pub mod kbox;
 pub mod vec_ext;
 
diff --git a/rust/kernel/alloc/box_ext.rs b/rust/kernel/alloc/box_ext.rs
deleted file mode 100644
index 829cb1c1cf9e..000000000000
--- a/rust/kernel/alloc/box_ext.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Extensions to [`Box`] for fallible allocations.
-
-use super::{AllocError, Flags};
-use alloc::boxed::Box;
-use core::mem::MaybeUninit;
-
-/// Extensions to [`Box`].
-pub trait BoxExt<T>: Sized {
-    /// Allocates a new box.
-    ///
-    /// The allocation may fail, in which case an error is returned.
-    fn new(x: T, flags: Flags) -> Result<Self, AllocError>;
-
-    /// Allocates a new uninitialised box.
-    ///
-    /// The allocation may fail, in which case an error is returned.
-    fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>;
-}
-
-impl<T> BoxExt<T> for Box<T> {
-    fn new(x: T, flags: Flags) -> Result<Self, AllocError> {
-        let b = <Self as BoxExt<_>>::new_uninit(flags)?;
-        Ok(Box::write(b, x))
-    }
-
-    #[cfg(any(test, testlib))]
-    fn new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> {
-        Ok(Box::new_uninit())
-    }
-
-    #[cfg(not(any(test, testlib)))]
-    fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> {
-        let ptr = if core::mem::size_of::<MaybeUninit<T>>() == 0 {
-            core::ptr::NonNull::<_>::dangling().as_ptr()
-        } else {
-            let layout = core::alloc::Layout::new::<MaybeUninit<T>>();
-
-            // SAFETY: Memory is being allocated (first arg is null). The only other source of
-            // safety issues is sleeping on atomic context, which is addressed by klint. Lastly,
-            // the type is not a SZT (checked above).
-            let ptr =
-                unsafe { super::allocator::krealloc_aligned(core::ptr::null_mut(), layout, flags) };
-            if ptr.is_null() {
-                return Err(AllocError);
-            }
-
-            ptr.cast::<MaybeUninit<T>>()
-        };
-
-        // SAFETY: For non-zero-sized types, we allocate above using the global allocator. For
-        // zero-sized types, we use `NonNull::dangling`.
-        Ok(unsafe { Box::from_raw(ptr) })
-    }
-}
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index b3159eb1eb02..ae533305d40e 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -211,12 +211,11 @@
 //! [`pin_init!`]: crate::pin_init!
 
 use crate::{
-    alloc::{box_ext::BoxExt, AllocError, Allocator, Flags, KBox},
+    alloc::{AllocError, Allocator, Flags, KBox},
     error::{self, Error},
     sync::UniqueArc,
     types::{Opaque, ScopeGuard},
 };
-use alloc::boxed::Box;
 use core::{
     cell::UnsafeCell,
     convert::Infallible,
@@ -589,7 +588,6 @@ macro_rules! pin_init {
 /// # Examples
 ///
 /// ```rust
-/// # #![feature(new_uninit)]
 /// use kernel::{init::{self, PinInit}, error::Error};
 /// #[pin_data]
 /// struct BigBuf {
@@ -1149,36 +1147,6 @@ fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
     }
 }
 
-impl<T> InPlaceInit<T> for Box<T> {
-    #[inline]
-    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
-    where
-        E: From<AllocError>,
-    {
-        let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?;
-        let slot = this.as_mut_ptr();
-        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
-        // slot is valid and will not be moved, because we pin it later.
-        unsafe { init.__pinned_init(slot)? };
-        // SAFETY: All fields have been initialized.
-        Ok(unsafe { this.assume_init() }.into())
-    }
-
-    #[inline]
-    fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
-    where
-        E: From<AllocError>,
-    {
-        let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?;
-        let slot = this.as_mut_ptr();
-        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
-        // slot is valid.
-        unsafe { init.__init(slot)? };
-        // SAFETY: All fields have been initialized.
-        Ok(unsafe { this.assume_init() })
-    }
-}
-
 impl<T, A> InPlaceInit<T> for crate::alloc::Box<T, A>
 where
     A: Allocator + 'static,
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 274bdc1b0a82..042f05c45214 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -14,7 +14,6 @@
 #![no_std]
 #![feature(coerce_unsized)]
 #![feature(dispatch_from_dyn)]
-#![feature(new_uninit)]
 #![feature(receiver_trait)]
 #![feature(unsize)]
 
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 39f9331a48e2..a8018ef2e691 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -14,10 +14,10 @@
 #[doc(no_inline)]
 pub use core::pin::Pin;
 
-pub use crate::alloc::{box_ext::BoxExt, flags::*, vec_ext::VecExt, KBox, KVBox, VBox};
+pub use crate::alloc::{flags::*, vec_ext::VecExt, KBox, KVBox, VBox};
 
 #[doc(no_inline)]
-pub use alloc::{boxed::Box, vec::Vec};
+pub use alloc::vec::Vec;
 
 #[doc(no_inline)]
 pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index a60d59c377bd..2aadf715b336 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -4,7 +4,6 @@
 
 use crate::alloc::Allocator;
 use crate::init::{self, PinInit};
-use alloc::boxed::Box;
 use core::{
     cell::UnsafeCell,
     marker::{PhantomData, PhantomPinned},
@@ -68,28 +67,6 @@ unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option<Self> {
     }
 }
 
-impl<T: 'static> ForeignOwnable for Box<T> {
-    type Borrowed<'a> = &'a T;
-
-    fn into_foreign(self) -> *const core::ffi::c_void {
-        Box::into_raw(self) as _
-    }
-
-    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
-        // SAFETY: The safety requirements for this function ensure that the object is still alive,
-        // so it is safe to dereference the raw pointer.
-        // The safety requirements of `from_foreign` also ensure that the object remains alive for
-        // the lifetime of the returned value.
-        unsafe { &*ptr.cast() }
-    }
-
-    unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
-        // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
-        // call to `Self::into_foreign`.
-        unsafe { Box::from_raw(ptr as _) }
-    }
-}
-
 impl<T: 'static, A> ForeignOwnable for crate::alloc::Box<T, A>
 where
     A: Allocator,
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 12/25] rust: alloc: add `Box` to prelude
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (10 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 11/25] rust: alloc: remove `BoxExt` extension Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 13/25] rust: alloc: import kernel `Box` type in types.rs Danilo Krummrich
                   ` (12 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we removed `BoxExt` and the corresponding includes in
prelude.rs, add the new kernel `Box` type instead.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/prelude.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index a8018ef2e691..6bf77577eae7 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -14,7 +14,7 @@
 #[doc(no_inline)]
 pub use core::pin::Pin;
 
-pub use crate::alloc::{flags::*, vec_ext::VecExt, KBox, KVBox, VBox};
+pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox};
 
 #[doc(no_inline)]
 pub use alloc::vec::Vec;
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 13/25] rust: alloc: import kernel `Box` type in types.rs
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (11 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 12/25] rust: alloc: add `Box` to prelude Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 14/25] rust: alloc: import kernel `Box` type in init.rs Danilo Krummrich
                   ` (11 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we removed `BoxExt` and the corresponding includes in
types.rs, add the new kernel `Box` type instead.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/types.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 2aadf715b336..809653b9d945 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -2,7 +2,7 @@
 
 //! Kernel types.
 
-use crate::alloc::Allocator;
+use crate::alloc::{Allocator, Box};
 use crate::init::{self, PinInit};
 use core::{
     cell::UnsafeCell,
@@ -67,14 +67,14 @@ unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option<Self> {
     }
 }
 
-impl<T: 'static, A> ForeignOwnable for crate::alloc::Box<T, A>
+impl<T: 'static, A> ForeignOwnable for Box<T, A>
 where
     A: Allocator,
 {
     type Borrowed<'a> = &'a T;
 
     fn into_foreign(self) -> *const core::ffi::c_void {
-        crate::alloc::Box::into_raw(self) as _
+        Box::into_raw(self) as _
     }
 
     unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
@@ -88,7 +88,7 @@ unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
     unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
         // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
         // call to `Self::into_foreign`.
-        unsafe { crate::alloc::Box::from_raw(ptr as _) }
+        unsafe { Box::from_raw(ptr as _) }
     }
 }
 
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 14/25] rust: alloc: import kernel `Box` type in init.rs
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (12 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 13/25] rust: alloc: import kernel `Box` type in types.rs Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01 14:55   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type Danilo Krummrich
                   ` (10 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we removed `BoxExt` and the corresponding includes in
init.rs, add the new kernel `Box` type instead.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/init.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index ae533305d40e..350582662964 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -211,7 +211,7 @@
 //! [`pin_init!`]: crate::pin_init!
 
 use crate::{
-    alloc::{AllocError, Allocator, Flags, KBox},
+    alloc::{AllocError, Allocator, Box, Flags, KBox},
     error::{self, Error},
     sync::UniqueArc,
     types::{Opaque, ScopeGuard},
@@ -1147,7 +1147,7 @@ fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
     }
 }
 
-impl<T, A> InPlaceInit<T> for crate::alloc::Box<T, A>
+impl<T, A> InPlaceInit<T> for Box<T, A>
 where
     A: Allocator + 'static,
 {
@@ -1156,13 +1156,13 @@ fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>,
     where
         E: From<AllocError>,
     {
-        let mut this = crate::alloc::Box::<_, A>::new_uninit(flags)?;
+        let mut this = Box::<_, A>::new_uninit(flags)?;
         let slot = this.as_mut_ptr();
         // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
         // slot is valid and will not be moved, because we pin it later.
         unsafe { init.__pinned_init(slot)? };
         // SAFETY: All fields have been initialized.
-        Ok(unsafe { crate::alloc::Box::assume_init(this) }.into())
+        Ok(unsafe { Box::assume_init(this) }.into())
     }
 
     #[inline]
@@ -1170,13 +1170,13 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
     where
         E: From<AllocError>,
     {
-        let mut this = crate::alloc::Box::<_, A>::new_uninit(flags)?;
+        let mut this = Box::<_, A>::new_uninit(flags)?;
         let slot = this.as_mut_ptr();
         // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
         // slot is valid.
         unsafe { init.__init(slot)? };
         // SAFETY: All fields have been initialized.
-        Ok(unsafe { crate::alloc::Box::assume_init(this) })
+        Ok(unsafe { Box::assume_init(this) })
     }
 }
 
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (13 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 14/25] rust: alloc: import kernel `Box` type in init.rs Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01 15:05   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
                   ` (9 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

`Vec` provides a contiguous growable array type (such as `Vec`) with
contents allocated with the kernel's allocators (e.g. `Kmalloc`,
`Vmalloc` or `KVmalloc`).

In contrast to Rust's `Vec` type, the kernel `Vec` type considers the
kernel's GFP flags for all appropriate functions, always reports
allocation failures through `Result<_, AllocError>` and remains
independent from unstable features.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs      |   6 +
 rust/kernel/alloc/kbox.rs |  16 +-
 rust/kernel/alloc/kvec.rs | 583 ++++++++++++++++++++++++++++++++++++++
 rust/kernel/prelude.rs    |   2 +-
 4 files changed, 605 insertions(+), 2 deletions(-)
 create mode 100644 rust/kernel/alloc/kvec.rs

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index 4bddd023aa7f..bd93140f3094 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -5,6 +5,7 @@
 #[cfg(not(any(test, testlib)))]
 pub mod allocator;
 pub mod kbox;
+pub mod kvec;
 pub mod vec_ext;
 
 #[cfg(any(test, testlib))]
@@ -18,6 +19,11 @@
 pub use self::kbox::KVBox;
 pub use self::kbox::VBox;
 
+pub use self::kvec::KVVec;
+pub use self::kvec::KVec;
+pub use self::kvec::VVec;
+pub use self::kvec::Vec;
+
 /// Indicates an allocation error.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct AllocError;
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index 7074f00e07bc..39feaed4a8f8 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -2,7 +2,7 @@
 
 //! Implementation of [`Box`].
 
-use super::{AllocError, Allocator, Flags};
+use super::{AllocError, Allocator, Flags, Vec};
 use core::fmt;
 use core::marker::PhantomData;
 use core::mem::ManuallyDrop;
@@ -169,6 +169,20 @@ pub fn into_pin(b: Self) -> Pin<Self>
     }
 }
 
+impl<T, A, const N: usize> Box<[T; N], A>
+where
+    A: Allocator,
+{
+    /// Convert a `Box<[T], A>` to a `Vec<T, A>`.
+    pub fn into_vec(b: Self) -> Vec<T, A> {
+        let len = b.len();
+        unsafe {
+            let ptr = Self::into_raw(b);
+            Vec::from_raw_parts(ptr as _, len, len)
+        }
+    }
+}
+
 impl<T, A> Box<MaybeUninit<T>, A>
 where
     A: Allocator,
diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
new file mode 100644
index 000000000000..04cc85f7d92c
--- /dev/null
+++ b/rust/kernel/alloc/kvec.rs
@@ -0,0 +1,583 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Implementation of [`Vec`].
+
+use super::{AllocError, Allocator, Flags};
+use crate::types::Unique;
+use core::{
+    fmt,
+    marker::PhantomData,
+    mem::{ManuallyDrop, MaybeUninit},
+    ops::Deref,
+    ops::DerefMut,
+    ops::Index,
+    ops::IndexMut,
+    slice,
+    slice::SliceIndex,
+};
+
+/// Create a [`Vec`] containing the arguments.
+///
+/// # Examples
+///
+/// ```
+/// let mut v = kernel::kvec![];
+/// v.push(1, GFP_KERNEL)?;
+/// assert_eq!(v, [1]);
+///
+/// let mut v = kernel::kvec![1; 3]?;
+/// v.push(4, GFP_KERNEL)?;
+/// assert_eq!(v, [1, 1, 1, 4]);
+///
+/// let mut v = kernel::kvec![1, 2, 3]?;
+/// v.push(4, GFP_KERNEL)?;
+/// assert_eq!(v, [1, 2, 3, 4]);
+///
+/// # Ok::<(), Error>(())
+/// ```
+#[macro_export]
+macro_rules! kvec {
+    () => (
+        {
+            $crate::alloc::KVec::new()
+        }
+    );
+    ($elem:expr; $n:expr) => (
+        {
+            $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL)
+        }
+    );
+    ($($x:expr),+ $(,)?) => (
+        {
+            match $crate::alloc::KBox::new([$($x),+], GFP_KERNEL) {
+                Ok(b) => Ok($crate::alloc::KBox::into_vec(b)),
+                Err(e) => Err(e),
+            }
+        }
+    );
+}
+
+/// The kernel's [`Vec`] type.
+///
+/// A contiguous growable array type with contents allocated with the kernel's allocators (e.g.
+/// `Kmalloc`, `Vmalloc` or `KVmalloc`, written `Vec<T, A>`.
+///
+/// For non-zero-sized values, a [`Vec`] will use the given allocator `A` for its allocation. For
+/// the most common allocators the type aliases `KVec`, `VVec` and `KVVec` exist.
+///
+/// For zero-sized types the [`Vec`]'s pointer must be `dangling_mut::<T>`; no memory is allocated.
+///
+/// Generally, [`Vec`] consists of a pointer that represents the vector's backing buffer, the
+/// capacity of the vector (the number of elements that currently fit into the vector), it's length
+/// (the number of elements that are currently stored in the vector) and the `Allocator` used to
+/// allocate (and free) the backing buffer.
+///
+/// A [`Vec`] can be deconstructed into and (re-)constructed from it's previously named raw parts
+/// and manually modified.
+///
+/// [`Vec`]'s backing buffer gets, if required, automatically increased (re-allocated) when elements
+/// are added to the vector.
+///
+/// # Invariants
+///
+/// The [`Vec`] backing buffer's pointer always properly aligned and either points to memory
+/// allocated with `A` or, for zero-sized types, is a dangling pointer.
+///
+/// The length of the vector always represents the exact number of elements stored in the vector.
+///
+/// The capacity of the vector always represents the absolute number of elements that can be stored
+/// within the vector without re-allocation. However, it is legal for the backing buffer to be
+/// larger than `size_of<T>` times the capacity.
+///
+/// The `Allocator` of the vector is the exact allocator the backing buffer was allocated with (and
+/// must be freed with).
+pub struct Vec<T, A: Allocator> {
+    ptr: Unique<T>,
+    /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
+    ///
+    /// # Safety
+    ///
+    /// `cap` must be in the `0..=isize::MAX` range.
+    cap: usize,
+    len: usize,
+    _p: PhantomData<A>,
+}
+
+/// Type alias for `Vec` with a `Kmalloc` allocator.
+///
+/// # Examples
+///
+/// ```
+/// let mut v = KVec::new();
+/// v.push(1, GFP_KERNEL)?;
+/// assert_eq!(&v, &[1]);
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub type KVec<T> = Vec<T, super::allocator::Kmalloc>;
+
+/// Type alias for `Vec` with a `Vmalloc` allocator.
+///
+/// # Examples
+///
+/// ```
+/// let mut v = VVec::new();
+/// v.push(1, GFP_KERNEL)?;
+/// assert_eq!(&v, &[1]);
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub type VVec<T> = Vec<T, super::allocator::Vmalloc>;
+
+/// Type alias for `Vec` with a `KVmalloc` allocator.
+///
+/// # Examples
+///
+/// ```
+/// let mut v = KVVec::new();
+/// v.push(1, GFP_KERNEL)?;
+/// assert_eq!(&v, &[1]);
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub type KVVec<T> = Vec<T, super::allocator::KVmalloc>;
+
+impl<T, A> Vec<T, A>
+where
+    A: Allocator,
+{
+    #[inline]
+    fn is_zst() -> bool {
+        core::mem::size_of::<T>() == 0
+    }
+
+    /// Returns the total number of elements the vector can hold without
+    /// reallocating.
+    pub fn capacity(&self) -> usize {
+        if Self::is_zst() {
+            usize::MAX
+        } else {
+            self.cap
+        }
+    }
+
+    /// Returns the number of elements in the vector, also referred to
+    /// as its 'length'.
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.len
+    }
+
+    /// Forces the length of the vector to new_len.
+    ///
+    /// # Safety
+    ///
+    /// - `new_len` must be less than or equal to [`Self::capacity()`].
+    /// - The elements at `old_len..new_len` must be initialized.
+    #[inline]
+    pub unsafe fn set_len(&mut self, new_len: usize) {
+        self.len = new_len;
+    }
+
+    /// Extracts a slice containing the entire vector.
+    ///
+    /// Equivalent to `&s[..]`.
+    #[inline]
+    pub fn as_slice(&self) -> &[T] {
+        self
+    }
+
+    /// Extracts a mutable slice of the entire vector.
+    ///
+    /// Equivalent to `&mut s[..]`.
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [T] {
+        self
+    }
+
+    /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
+    /// raw pointer valid for zero sized reads if the vector didn't allocate.
+    #[inline]
+    pub fn as_mut_ptr(&self) -> *mut T {
+        self.ptr.as_ptr()
+    }
+
+    /// Returns a raw pointer to the slice's buffer.
+    #[inline]
+    pub fn as_ptr(&self) -> *const T {
+        self.as_mut_ptr()
+    }
+
+    /// Returns `true` if the vector contains no elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = KVec::new();
+    /// assert!(v.is_empty());
+    ///
+    /// v.push(1, GFP_KERNEL);
+    /// assert!(!v.is_empty());
+    /// ```
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Constructs a new, empty Vec<T, A>.
+    ///
+    /// This method does not allocate by itself.
+    #[inline]
+    pub const fn new() -> Self {
+        Self {
+            ptr: Unique::dangling(),
+            cap: 0,
+            len: 0,
+            _p: PhantomData::<A>,
+        }
+    }
+
+    /// Returns the remaining spare capacity of the vector as a slice of `MaybeUninit<T>`.
+    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
+        // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated
+        // and valid, but uninitialized.
+        unsafe {
+            slice::from_raw_parts_mut(
+                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
+                self.capacity() - self.len,
+            )
+        }
+    }
+
+    /// Appends an element to the back of the [`Vec`] instance.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = KVec::new();
+    /// v.push(1, GFP_KERNEL)?;
+    /// assert_eq!(&v, &[1]);
+    ///
+    /// v.push(2, GFP_KERNEL)?;
+    /// assert_eq!(&v, &[1, 2]);
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> {
+        Vec::reserve(self, 1, flags)?;
+        let s = self.spare_capacity_mut();
+        s[0].write(v);
+
+        // SAFETY: We just initialised the first spare entry, so it is safe to increase the length
+        // by 1. We also know that the new length is <= capacity because of the previous call to
+        // `reserve` above.
+        unsafe { self.set_len(self.len() + 1) };
+        Ok(())
+    }
+
+    /// Creates a new [`Vec`] instance with at least the given capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let v = KVec::<u32>::with_capacity(20, GFP_KERNEL)?;
+    ///
+    /// assert!(v.capacity() >= 20);
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> {
+        let mut v = Vec::new();
+
+        Self::reserve(&mut v, capacity, flags)?;
+
+        Ok(v)
+    }
+
+    /// Pushes clones of the elements of slice into the [`Vec`] instance.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = KVec::new();
+    /// v.push(1, GFP_KERNEL)?;
+    ///
+    /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?;
+    /// assert_eq!(&v, &[1, 20, 30, 40]);
+    ///
+    /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?;
+    /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]);
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
+    where
+        T: Clone,
+    {
+        self.reserve(other.len(), flags)?;
+        for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) {
+            slot.write(item.clone());
+        }
+
+        // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase
+        // the length by the same amount. We also know that the new length is <= capacity because
+        // of the previous call to `reserve` above.
+        unsafe { self.set_len(self.len() + other.len()) };
+        Ok(())
+    }
+
+    /// Creates a Vec<T, A> directly from a pointer, a length, a capacity, and an allocator.
+    ///
+    /// # Safety
+    ///
+    /// This is highly unsafe, due to the number of invariants that aren’t checked:
+    ///
+    /// - `ptr` must be currently allocated via the given allocator `A`.
+    /// - `T` needs to have the same alignment as what `ptr` was allocated with. (`T` having a less
+    ///   strict alignment is not sufficient, the alignment really needs to be equal to satisfy the
+    ///   `dealloc` requirement that memory must be allocated and deallocated with the same layout.)
+    /// - The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs to be
+    ///   smaller or equal the size the pointer was allocated with.
+    /// - `length` needs to be less than or equal to `capacity`.
+    /// - The first `length` values must be properly initialized values of type `T`.
+    /// - The allocated size in bytes must be no larger than `isize::MAX`. See the safety
+    ///   documentation of `pointer::offset`.
+    ///
+    /// It is also valid to create an empty `Vec` passing a dangling pointer for `ptr` and zero for
+    /// `cap` and `len`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = kernel::kvec![1, 2, 3]?;
+    /// v.reserve(1, GFP_KERNEL)?;
+    ///
+    /// let (mut ptr, mut len, cap) = v.into_raw_parts();
+    ///
+    /// // SAFETY: We've just reserved memory for another element.
+    /// unsafe { ptr.add(len).write(4) };
+    /// len += 1;
+    ///
+    /// // SAFETY: We only wrote an additional element at the end of the `KVec`'s buffer and
+    /// // correspondingly increased the length of the `KVec` by one. Otherwise, we construct it
+    /// // from the exact same raw parts.
+    /// let v = unsafe { KVec::from_raw_parts(ptr, len, cap) };
+    ///
+    /// assert_eq!(v, [1, 2, 3, 4]);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
+        let cap = if Self::is_zst() { 0 } else { capacity };
+
+        Self {
+            // SAFETY: By the safety requirements, `ptr` is either dangling or pointing to a valid
+            // memory allocation, allocated with `A`.
+            ptr: unsafe { Unique::new_unchecked(ptr) },
+            cap,
+            len: length,
+            _p: PhantomData::<A>,
+        }
+    }
+
+    /// Decomposes a `Vec<T, A>` into its raw components: (`pointer`, `length`, `capacity`).
+    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
+        let me = ManuallyDrop::new(self);
+        let len = me.len();
+        let capacity = me.capacity();
+        let ptr = me.as_mut_ptr();
+        (ptr, len, capacity)
+    }
+
+    /// Ensures that the capacity exceeds the length by at least `additional` elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = KVec::new();
+    /// v.push(1, GFP_KERNEL)?;
+    ///
+    /// v.reserve(10, GFP_KERNEL)?;
+    /// let cap = v.capacity();
+    /// assert!(cap >= 10);
+    ///
+    /// v.reserve(10, GFP_KERNEL)?;
+    /// let new_cap = v.capacity();
+    /// assert_eq!(new_cap, cap);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> {
+        let len = self.len();
+        let cap = self.capacity();
+
+        if cap - len >= additional {
+            return Ok(());
+        }
+
+        if Self::is_zst() {
+            // The capacity is already `usize::MAX` for SZTs, we can't go higher.
+            return Err(AllocError);
+        }
+
+        // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size
+        // is greater than `isize::MAX`. So the multiplication by two won't overflow.
+        let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
+        let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
+
+        // We need to make sure that `ptr` is either NULL or comes from a previous call to
+        // `realloc_flags`. A `Vec<T, A>`'s `ptr` value is not guaranteed to be NULL and might be
+        // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T, A>`'s
+        // capacity to be zero if no memory has been allocated yet.
+        let ptr = if cap == 0 {
+            None
+        } else {
+            Some(self.ptr.as_non_null().cast())
+        };
+
+        // SAFETY: `ptr` is valid because it's either `None` or comes from a previous call to
+        // `A::realloc`. We also verified that the type is not a ZST.
+        let ptr = unsafe { A::realloc(ptr, layout, flags)? };
+
+        self.ptr = ptr.cast().into();
+        self.cap = new_cap;
+
+        Ok(())
+    }
+}
+
+impl<T: Clone, A: Allocator> Vec<T, A> {
+    /// Extend the vector by `n` clones of value.
+    pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> {
+        self.reserve(n, flags)?;
+
+        let spare = self.spare_capacity_mut();
+
+        for i in 0..spare.len() - 1 {
+            spare[i].write(value.clone());
+        }
+
+        // We can write the last element directly without cloning needlessly
+        spare[spare.len() - 1].write(value);
+
+        // SAFETY: `self.reserve` not bailing out with an error guarantees that we're not
+        // exceeding the capacity of this `Vec`.
+        unsafe { self.set_len(self.len() + n) };
+
+        Ok(())
+    }
+
+    /// Create a new `Vec<T, A> and extend it by `n` clones of `value`.
+    pub fn from_elem(value: T, n: usize, flags: Flags) -> Result<Self, AllocError> {
+        let mut v = Self::with_capacity(n, flags)?;
+
+        v.extend_with(n, value, flags)?;
+
+        Ok(v)
+    }
+}
+
+impl<T, A> Drop for Vec<T, A>
+where
+    A: Allocator,
+{
+    fn drop(&mut self) {
+        // SAFETY: We need to drop the vector's elements in place, before we free the backing
+        // memory.
+        unsafe {
+            core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
+                self.as_mut_ptr(),
+                self.len,
+            ))
+        };
+
+        // If `cap == 0` we never allocated any memory in the first place.
+        if self.cap != 0 {
+            // SAFETY: `self.ptr` was previously allocated with `A`.
+            unsafe { A::free(self.ptr.as_non_null().cast()) };
+        }
+    }
+}
+
+impl<T> Default for KVec<T> {
+    #[inline]
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+impl<T, A> Deref for Vec<T, A>
+where
+    A: Allocator,
+{
+    type Target = [T];
+
+    #[inline]
+    fn deref(&self) -> &[T] {
+        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
+        // initialized elements of type `T`.
+        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
+    }
+}
+
+impl<T, A> DerefMut for Vec<T, A>
+where
+    A: Allocator,
+{
+    #[inline]
+    fn deref_mut(&mut self) -> &mut [T] {
+        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
+        // initialized elements of type `T`.
+        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
+    }
+}
+
+impl<T: Eq, A> Eq for Vec<T, A> where A: Allocator {}
+
+impl<T, I: SliceIndex<[T]>, A> Index<I> for Vec<T, A>
+where
+    A: Allocator,
+{
+    type Output = I::Output;
+
+    #[inline]
+    fn index(&self, index: I) -> &Self::Output {
+        Index::index(&**self, index)
+    }
+}
+
+impl<T, I: SliceIndex<[T]>, A> IndexMut<I> for Vec<T, A>
+where
+    A: Allocator,
+{
+    #[inline]
+    fn index_mut(&mut self, index: I) -> &mut Self::Output {
+        IndexMut::index_mut(&mut **self, index)
+    }
+}
+
+macro_rules! __impl_slice_eq {
+    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
+        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
+        where
+            T: PartialEq<U>,
+            $($ty: $bound)?
+        {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
+        }
+    }
+}
+
+__impl_slice_eq! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> }
+__impl_slice_eq! { [A: Allocator] Vec<T, A>, &[U] }
+__impl_slice_eq! { [A: Allocator] Vec<T, A>, &mut [U] }
+__impl_slice_eq! { [A: Allocator] &[T], Vec<U, A> }
+__impl_slice_eq! { [A: Allocator] &mut [T], Vec<U, A> }
+__impl_slice_eq! { [A: Allocator] Vec<T, A>, [U] }
+__impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
+__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
+__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 6bf77577eae7..bb80a43d20fb 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -14,7 +14,7 @@
 #[doc(no_inline)]
 pub use core::pin::Pin;
 
-pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox};
+pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
 
 #[doc(no_inline)]
 pub use alloc::vec::Vec;
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (14 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01 15:07   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
                   ` (8 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Implement `IntoIterator` for `Vec`, `Vec`'s `IntoIter` type, as well as
`Iterator` for `IntoIter`.

`Vec::into_iter` disassembles the `Vec` into its raw parts; additionally,
`IntoIter` keeps track of a separate pointer, which is incremented
correspondingsly as the iterator advances, while the length, or the count
of elements, is decremented.

This also means that `IntoIter` takes the ownership of the backing
buffer and is responsible to drop the remaining elements and free the
backing buffer, if it's dropped.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs      |   1 +
 rust/kernel/alloc/kvec.rs | 186 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 187 insertions(+)

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index bd93140f3094..f2998ad57456 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -19,6 +19,7 @@
 pub use self::kbox::KVBox;
 pub use self::kbox::VBox;
 
+pub use self::kvec::IntoIter;
 pub use self::kvec::KVVec;
 pub use self::kvec::KVec;
 pub use self::kvec::VVec;
diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
index 04cc85f7d92c..50e7705e5686 100644
--- a/rust/kernel/alloc/kvec.rs
+++ b/rust/kernel/alloc/kvec.rs
@@ -12,6 +12,8 @@
     ops::DerefMut,
     ops::Index,
     ops::IndexMut,
+    ptr,
+    ptr::NonNull,
     slice,
     slice::SliceIndex,
 };
@@ -581,3 +583,187 @@ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
 __impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
 __impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
 __impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
+
+impl<'a, T, A> IntoIterator for &'a Vec<T, A>
+where
+    A: Allocator,
+{
+    type Item = &'a T;
+    type IntoIter = slice::Iter<'a, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A>
+where
+    A: Allocator,
+{
+    type Item = &'a mut T;
+    type IntoIter = slice::IterMut<'a, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+/// An iterator that moves out of a vector.
+///
+/// This `struct` is created by the `into_iter` method on [`Vec`] (provided by the [`IntoIterator`]
+/// trait).
+///
+/// # Examples
+///
+/// ```
+/// let v = kernel::kvec![0, 1, 2]?;
+/// let iter = v.into_iter();
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub struct IntoIter<T, A: Allocator> {
+    ptr: *mut T,
+    buf: NonNull<T>,
+    len: usize,
+    cap: usize,
+    _p: PhantomData<A>,
+}
+
+impl<T, A> IntoIter<T, A>
+where
+    A: Allocator,
+{
+    fn as_raw_mut_slice(&mut self) -> *mut [T] {
+        ptr::slice_from_raw_parts_mut(self.ptr, self.len)
+    }
+}
+
+impl<T, A> Iterator for IntoIter<T, A>
+where
+    A: Allocator,
+{
+    type Item = T;
+
+    /// # Examples
+    ///
+    /// ```
+    /// let v = kernel::kvec![1, 2, 3]?;
+    /// let mut it = v.into_iter();
+    ///
+    /// assert_eq!(it.next(), Some(1));
+    /// assert_eq!(it.next(), Some(2));
+    /// assert_eq!(it.next(), Some(3));
+    /// assert_eq!(it.next(), None);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    fn next(&mut self) -> Option<T> {
+        if self.len == 0 {
+            return None;
+        }
+
+        let ptr = self.ptr;
+        if !Vec::<T, A>::is_zst() {
+            // SAFETY: We can't overflow; `end` is guaranteed to mark the end of the buffer.
+            unsafe { self.ptr = self.ptr.add(1) };
+        } else {
+            // For ZST `ptr` has to stay where it is to remain aligned, so we just reduce `self.len`
+            // by 1.
+        }
+        self.len -= 1;
+
+        // SAFETY: `ptr` is guaranteed to point at a valid element within the buffer.
+        Some(unsafe { ptr.read() })
+    }
+
+    /// # Examples
+    ///
+    /// ```
+    /// let v: KVec<u32> = kernel::kvec![1, 2, 3]?;
+    /// let mut iter = v.into_iter();
+    /// let size = iter.size_hint().0;
+    ///
+    /// iter.next();
+    /// assert_eq!(iter.size_hint().0, size - 1);
+    ///
+    /// iter.next();
+    /// assert_eq!(iter.size_hint().0, size - 2);
+    ///
+    /// iter.next();
+    /// assert_eq!(iter.size_hint().0, size - 3);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.len, Some(self.len))
+    }
+}
+
+impl<T, A> Drop for IntoIter<T, A>
+where
+    A: Allocator,
+{
+    fn drop(&mut self) {
+        // SAFETY: Drop the remaining vector's elements in place, before we free the backing
+        // memory.
+        unsafe { ptr::drop_in_place(self.as_raw_mut_slice()) };
+
+        // If `cap == 0` we never allocated any memory in the first place.
+        if self.cap != 0 {
+            // SAFETY: `self.buf` was previously allocated with `A`.
+            unsafe { A::free(self.buf.cast()) };
+        }
+    }
+}
+
+impl<T, A> IntoIterator for Vec<T, A>
+where
+    A: Allocator,
+{
+    type Item = T;
+    type IntoIter = IntoIter<T, A>;
+
+    /// Creates a consuming iterator, that is, one that moves each value out of
+    /// the vector (from start to end). The vector cannot be used after calling
+    /// this.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let v = kernel::kvec![1, 2]?;
+    /// let mut v_iter = v.into_iter();
+    ///
+    /// let first_element: Option<u32> = v_iter.next();
+    ///
+    /// assert_eq!(first_element, Some(1));
+    /// assert_eq!(v_iter.next(), Some(2));
+    /// assert_eq!(v_iter.next(), None);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    ///
+    /// ```
+    /// let v = kernel::kvec![];
+    /// let mut v_iter = v.into_iter();
+    ///
+    /// let first_element: Option<u32> = v_iter.next();
+    ///
+    /// assert_eq!(first_element, None);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        let (ptr, len, cap) = self.into_raw_parts();
+
+        IntoIter {
+            ptr,
+            // SAFETY: `ptr` is either a dangling pointer or a pointer to a valid memory
+            // allocation, allocated with `A`.
+            buf: unsafe { NonNull::new_unchecked(ptr) },
+            len,
+            cap,
+            _p: PhantomData::<A>,
+        }
+    }
+}
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (15 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01 15:10   ` Alice Ryhl
  2024-08-01  0:02 ` [PATCH v3 18/25] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
                   ` (7 subsequent siblings)
  24 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Currently, we can't implement `FromIterator`. There are a couple of
issues with this trait in the kernel, namely:

  - Rust's specialization feature is unstable. This prevents us to
    optimze for the special case where `I::IntoIter` equals `Vec`'s
    `IntoIter` type.
  - We also can't use `I::IntoIter`'s type ID either to work around this,
    since `FromIterator` doesn't require this type to be `'static`.
  - `FromIterator::from_iter` does return `Self` instead of
    `Result<Self, AllocError>`, hence we can't properly handle allocation
    failures.
  - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle
    additional allocation flags.

Instead, provide `IntoIter::collect`, such that we can at least convert
`IntoIter` into a `Vec` again.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc/kvec.rs | 78 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
index 50e7705e5686..6f151ef5c988 100644
--- a/rust/kernel/alloc/kvec.rs
+++ b/rust/kernel/alloc/kvec.rs
@@ -636,6 +636,84 @@ impl<T, A> IntoIter<T, A>
     fn as_raw_mut_slice(&mut self) -> *mut [T] {
         ptr::slice_from_raw_parts_mut(self.ptr, self.len)
     }
+
+    fn into_raw_parts(self) -> (*mut T, NonNull<T>, usize, usize) {
+        let me = ManuallyDrop::new(self);
+        let ptr = me.ptr;
+        let buf = me.buf;
+        let len = me.len;
+        let cap = me.cap;
+        (ptr, buf, len, cap)
+    }
+
+    /// Same as `Iterator::collect` but specialized for `Vec`'s `IntoIter`.
+    ///
+    /// Currently, we can't implement `FromIterator`. There are a couple of issues with this trait
+    /// in the kernel, namely:
+    ///
+    /// - Rust's specialization feature is unstable. This prevents us to optimze for the special
+    ///   case where `I::IntoIter` equals `Vec`'s `IntoIter` type.
+    /// - We also can't use `I::IntoIter`'s type ID either to work around this, since `FromIterator`
+    ///   doesn't require this type to be `'static`.
+    /// - `FromIterator::from_iter` does return `Self` instead of `Result<Self, AllocError>`, hence
+    ///   we can't properly handle allocation failures.
+    /// - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle additional allocation
+    ///   flags.
+    ///
+    /// Instead, provide `IntoIter::collect`, such that we can at least convert a `IntoIter` into a
+    /// `Vec` again.
+    ///
+    /// Note that `IntoIter::collect` doesn't require `Flags`, since it re-uses the existing backing
+    /// buffer. However, this backing buffer may be shrunk to the actual count of elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let v = kernel::kvec![1, 2, 3]?;
+    /// let mut it = v.into_iter();
+    ///
+    /// assert_eq!(it.next(), Some(1));
+    ///
+    /// let v = it.collect(GFP_KERNEL);
+    /// assert_eq!(v, [2, 3]);
+    ///
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn collect(self, flags: Flags) -> Vec<T, A> {
+        let (mut ptr, buf, len, mut cap) = self.into_raw_parts();
+        let has_advanced = ptr != buf.as_ptr();
+
+        if has_advanced {
+            // SAFETY: Copy the contents we have advanced to at the beginning of the buffer.
+            // `ptr` is guaranteed to be between `buf` and `buf.add(cap)` and `ptr.add(len)` is
+            // guaranteed to be smaller than `buf.add(cap)`.
+            unsafe { ptr::copy(ptr, buf.as_ptr(), len) };
+            ptr = buf.as_ptr();
+        }
+
+        // This can never fail, `len` is guaranteed to be smaller than `cap`.
+        let layout = core::alloc::Layout::array::<T>(len).unwrap();
+
+        // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be
+        // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves
+        // it as it is.
+        ptr = match unsafe { A::realloc(Some(buf.cast()), layout, flags) } {
+            // If we fail to shrink, which likely can't even happen, continue with the existing
+            // buffer.
+            Err(_) => ptr,
+            Ok(ptr) => {
+                cap = len;
+                ptr.as_ptr().cast()
+            }
+        };
+
+        // SAFETY: If the iterator has been advanced, the advanced elements have been copied to
+        // the beginning of the buffer and `len` has been adjusted accordingly. `ptr` is guaranteed
+        // to point to the start of the backing buffer. `cap` is either the original capacity or,
+        // after shrinking the buffer, equal to `len`. `alloc` is guaranteed to be unchanged since
+        // `into_iter` has been called on the original `Vec`.
+        unsafe { Vec::from_raw_parts(ptr, len, cap) }
+    }
 }
 
 impl<T, A> Iterator for IntoIter<T, A>
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 18/25] rust: treewide: switch to the kernel `Vec` type
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (16 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 19/25] rust: alloc: remove `VecExt` extension Danilo Krummrich
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we got the kernel `Vec` in place, convert all existing `Vec`
users to make use of it.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/str.rs            | 12 +++++-------
 rust/kernel/sync/locked_by.rs |  2 +-
 rust/kernel/types.rs          |  2 +-
 rust/kernel/uaccess.rs        | 15 ++++++---------
 samples/rust/rust_minimal.rs  |  4 ++--
 5 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index bb8d4f41475b..0b6ffbade521 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -2,8 +2,7 @@
 
 //! String representations.
 
-use crate::alloc::{flags::*, vec_ext::VecExt, AllocError};
-use alloc::vec::Vec;
+use crate::alloc::{flags::*, AllocError, KVec};
 use core::fmt::{self, Write};
 use core::ops::{self, Deref, DerefMut, Index};
 
@@ -790,7 +789,7 @@ fn write_str(&mut self, s: &str) -> fmt::Result {
 /// assert_eq!(s.is_ok(), false);
 /// ```
 pub struct CString {
-    buf: Vec<u8>,
+    buf: KVec<u8>,
 }
 
 impl CString {
@@ -803,7 +802,7 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
         let size = f.bytes_written();
 
         // Allocate a vector with the required number of bytes, and write to it.
-        let mut buf = <Vec<_> as VecExt<_>>::with_capacity(size, GFP_KERNEL)?;
+        let mut buf = KVec::with_capacity(size, GFP_KERNEL)?;
         // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
         let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
         f.write_fmt(args)?;
@@ -850,10 +849,9 @@ impl<'a> TryFrom<&'a CStr> for CString {
     type Error = AllocError;
 
     fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> {
-        let mut buf = Vec::new();
+        let mut buf = KVec::new();
 
-        <Vec<_> as VecExt<_>>::extend_from_slice(&mut buf, cstr.as_bytes_with_nul(), GFP_KERNEL)
-            .map_err(|_| AllocError)?;
+        KVec::extend_from_slice(&mut buf, cstr.as_bytes_with_nul(), GFP_KERNEL)?;
 
         // INVARIANT: The `CStr` and `CString` types have the same invariants for
         // the string data, and we copied it over without changes.
diff --git a/rust/kernel/sync/locked_by.rs b/rust/kernel/sync/locked_by.rs
index babc731bd5f6..b94517231fcc 100644
--- a/rust/kernel/sync/locked_by.rs
+++ b/rust/kernel/sync/locked_by.rs
@@ -43,7 +43,7 @@
 /// struct InnerDirectory {
 ///     /// The sum of the bytes used by all files.
 ///     bytes_used: u64,
-///     _files: Vec<File>,
+///     _files: KVec<File>,
 /// }
 ///
 /// struct Directory {
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 809653b9d945..1d90d2c68f74 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -158,7 +158,7 @@ unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {}
 /// # use kernel::types::ScopeGuard;
 /// fn example3(arg: bool) -> Result {
 ///     let mut vec =
-///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
+///         ScopeGuard::new_with_data(KVec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
 ///
 ///     vec.push(10u8, GFP_KERNEL)?;
 ///     if arg {
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index e9347cff99ab..d19002308636 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -11,7 +11,6 @@
     prelude::*,
     types::{AsBytes, FromBytes},
 };
-use alloc::vec::Vec;
 use core::ffi::{c_ulong, c_void};
 use core::mem::{size_of, MaybeUninit};
 
@@ -46,7 +45,6 @@
 /// every byte in the region.
 ///
 /// ```no_run
-/// use alloc::vec::Vec;
 /// use core::ffi::c_void;
 /// use kernel::error::Result;
 /// use kernel::uaccess::{UserPtr, UserSlice};
@@ -54,7 +52,7 @@
 /// fn bytes_add_one(uptr: UserPtr, len: usize) -> Result<()> {
 ///     let (read, mut write) = UserSlice::new(uptr, len).reader_writer();
 ///
-///     let mut buf = Vec::new();
+///     let mut buf = KVec::new();
 ///     read.read_all(&mut buf, GFP_KERNEL)?;
 ///
 ///     for b in &mut buf {
@@ -69,7 +67,6 @@
 /// Example illustrating a TOCTOU (time-of-check to time-of-use) bug.
 ///
 /// ```no_run
-/// use alloc::vec::Vec;
 /// use core::ffi::c_void;
 /// use kernel::error::{code::EINVAL, Result};
 /// use kernel::uaccess::{UserPtr, UserSlice};
@@ -78,14 +75,14 @@
 /// fn is_valid(uptr: UserPtr, len: usize) -> Result<bool> {
 ///     let read = UserSlice::new(uptr, len).reader();
 ///
-///     let mut buf = Vec::new();
+///     let mut buf = KVec::new();
 ///     read.read_all(&mut buf, GFP_KERNEL)?;
 ///
 ///     todo!()
 /// }
 ///
 /// /// Returns the bytes behind this user pointer if they are valid.
-/// fn get_bytes_if_valid(uptr: UserPtr, len: usize) -> Result<Vec<u8>> {
+/// fn get_bytes_if_valid(uptr: UserPtr, len: usize) -> Result<KVec<u8>> {
 ///     if !is_valid(uptr, len)? {
 ///         return Err(EINVAL);
 ///     }
@@ -130,7 +127,7 @@ pub fn new(ptr: UserPtr, length: usize) -> Self {
     /// Reads the entirety of the user slice, appending it to the end of the provided buffer.
     ///
     /// Fails with [`EFAULT`] if the read happens on a bad address.
-    pub fn read_all(self, buf: &mut Vec<u8>, flags: Flags) -> Result {
+    pub fn read_all(self, buf: &mut KVec<u8>, flags: Flags) -> Result {
         self.reader().read_all(buf, flags)
     }
 
@@ -291,9 +288,9 @@ pub fn read<T: FromBytes>(&mut self) -> Result<T> {
     /// Reads the entirety of the user slice, appending it to the end of the provided buffer.
     ///
     /// Fails with [`EFAULT`] if the read happens on a bad address.
-    pub fn read_all(mut self, buf: &mut Vec<u8>, flags: Flags) -> Result {
+    pub fn read_all(mut self, buf: &mut KVec<u8>, flags: Flags) -> Result {
         let len = self.length;
-        VecExt::<u8>::reserve(buf, len, flags)?;
+        KVec::<u8>::reserve(buf, len, flags)?;
 
         // The call to `try_reserve` was successful, so the spare capacity is at least `len` bytes
         // long.
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
index 2a9eaab62d1c..4aaf117bf8e3 100644
--- a/samples/rust/rust_minimal.rs
+++ b/samples/rust/rust_minimal.rs
@@ -13,7 +13,7 @@
 }
 
 struct RustMinimal {
-    numbers: Vec<i32>,
+    numbers: KVec<i32>,
 }
 
 impl kernel::Module for RustMinimal {
@@ -21,7 +21,7 @@ fn init(_module: &'static ThisModule) -> Result<Self> {
         pr_info!("Rust minimal sample (init)\n");
         pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
 
-        let mut numbers = Vec::new();
+        let mut numbers = KVec::new();
         numbers.push(72, GFP_KERNEL)?;
         numbers.push(108, GFP_KERNEL)?;
         numbers.push(200, GFP_KERNEL)?;
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 19/25] rust: alloc: remove `VecExt` extension
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (17 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 18/25] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 20/25] rust: alloc: add `Vec` to prelude Danilo Krummrich
                   ` (5 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that all existing `Vec` users were moved to the kernel `Vec` type,
remove the `VecExt` extension.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs         |   1 -
 rust/kernel/alloc/vec_ext.rs | 185 -----------------------------------
 rust/kernel/prelude.rs       |   5 +-
 3 files changed, 1 insertion(+), 190 deletions(-)
 delete mode 100644 rust/kernel/alloc/vec_ext.rs

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index f2998ad57456..fac9d3976657 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -6,7 +6,6 @@
 pub mod allocator;
 pub mod kbox;
 pub mod kvec;
-pub mod vec_ext;
 
 #[cfg(any(test, testlib))]
 pub mod allocator_test;
diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs
deleted file mode 100644
index 1297a4be32e8..000000000000
--- a/rust/kernel/alloc/vec_ext.rs
+++ /dev/null
@@ -1,185 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Extensions to [`Vec`] for fallible allocations.
-
-use super::{AllocError, Flags};
-use alloc::vec::Vec;
-
-/// Extensions to [`Vec`].
-pub trait VecExt<T>: Sized {
-    /// Creates a new [`Vec`] instance with at least the given capacity.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let v = Vec::<u32>::with_capacity(20, GFP_KERNEL)?;
-    ///
-    /// assert!(v.capacity() >= 20);
-    /// # Ok::<(), Error>(())
-    /// ```
-    fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError>;
-
-    /// Appends an element to the back of the [`Vec`] instance.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = Vec::new();
-    /// v.push(1, GFP_KERNEL)?;
-    /// assert_eq!(&v, &[1]);
-    ///
-    /// v.push(2, GFP_KERNEL)?;
-    /// assert_eq!(&v, &[1, 2]);
-    /// # Ok::<(), Error>(())
-    /// ```
-    fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError>;
-
-    /// Pushes clones of the elements of slice into the [`Vec`] instance.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = Vec::new();
-    /// v.push(1, GFP_KERNEL)?;
-    ///
-    /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?;
-    /// assert_eq!(&v, &[1, 20, 30, 40]);
-    ///
-    /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?;
-    /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]);
-    /// # Ok::<(), Error>(())
-    /// ```
-    fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
-    where
-        T: Clone;
-
-    /// Ensures that the capacity exceeds the length by at least `additional` elements.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = Vec::new();
-    /// v.push(1, GFP_KERNEL)?;
-    ///
-    /// v.reserve(10, GFP_KERNEL)?;
-    /// let cap = v.capacity();
-    /// assert!(cap >= 10);
-    ///
-    /// v.reserve(10, GFP_KERNEL)?;
-    /// let new_cap = v.capacity();
-    /// assert_eq!(new_cap, cap);
-    ///
-    /// # Ok::<(), Error>(())
-    /// ```
-    fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError>;
-}
-
-impl<T> VecExt<T> for Vec<T> {
-    fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> {
-        let mut v = Vec::new();
-        <Self as VecExt<_>>::reserve(&mut v, capacity, flags)?;
-        Ok(v)
-    }
-
-    fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> {
-        <Self as VecExt<_>>::reserve(self, 1, flags)?;
-        let s = self.spare_capacity_mut();
-        s[0].write(v);
-
-        // SAFETY: We just initialised the first spare entry, so it is safe to increase the length
-        // by 1. We also know that the new length is <= capacity because of the previous call to
-        // `reserve` above.
-        unsafe { self.set_len(self.len() + 1) };
-        Ok(())
-    }
-
-    fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
-    where
-        T: Clone,
-    {
-        <Self as VecExt<_>>::reserve(self, other.len(), flags)?;
-        for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) {
-            slot.write(item.clone());
-        }
-
-        // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase
-        // the length by the same amount. We also know that the new length is <= capacity because
-        // of the previous call to `reserve` above.
-        unsafe { self.set_len(self.len() + other.len()) };
-        Ok(())
-    }
-
-    #[cfg(any(test, testlib))]
-    fn reserve(&mut self, additional: usize, _flags: Flags) -> Result<(), AllocError> {
-        Vec::reserve(self, additional);
-        Ok(())
-    }
-
-    #[cfg(not(any(test, testlib)))]
-    fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> {
-        let len = self.len();
-        let cap = self.capacity();
-
-        if cap - len >= additional {
-            return Ok(());
-        }
-
-        if core::mem::size_of::<T>() == 0 {
-            // The capacity is already `usize::MAX` for SZTs, we can't go higher.
-            return Err(AllocError);
-        }
-
-        // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size
-        // is greater than `isize::MAX`. So the multiplication by two won't overflow.
-        let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
-        let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
-
-        let (old_ptr, len, cap) = destructure(self);
-
-        // We need to make sure that `ptr` is either NULL or comes from a previous call to
-        // `krealloc_aligned`. A `Vec<T>`'s `ptr` value is not guaranteed to be NULL and might be
-        // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T>`'s capacity
-        // to be zero if no memory has been allocated yet.
-        let ptr = if cap == 0 {
-            core::ptr::null_mut()
-        } else {
-            old_ptr
-        };
-
-        // SAFETY: `ptr` is valid because it's either NULL or comes from a previous call to
-        // `krealloc_aligned`. We also verified that the type is not a ZST.
-        let new_ptr = unsafe { super::allocator::krealloc_aligned(ptr.cast(), layout, flags) };
-        if new_ptr.is_null() {
-            // SAFETY: We are just rebuilding the existing `Vec` with no changes.
-            unsafe { rebuild(self, old_ptr, len, cap) };
-            Err(AllocError)
-        } else {
-            // SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap
-            // is greater than `cap`, so it continues to be >= `len`.
-            unsafe { rebuild(self, new_ptr.cast::<T>(), len, new_cap) };
-            Ok(())
-        }
-    }
-}
-
-#[cfg(not(any(test, testlib)))]
-fn destructure<T>(v: &mut Vec<T>) -> (*mut T, usize, usize) {
-    let mut tmp = Vec::new();
-    core::mem::swap(&mut tmp, v);
-    let mut tmp = core::mem::ManuallyDrop::new(tmp);
-    let len = tmp.len();
-    let cap = tmp.capacity();
-    (tmp.as_mut_ptr(), len, cap)
-}
-
-/// Rebuilds a `Vec` from a pointer, length, and capacity.
-///
-/// # Safety
-///
-/// The same as [`Vec::from_raw_parts`].
-#[cfg(not(any(test, testlib)))]
-unsafe fn rebuild<T>(v: &mut Vec<T>, ptr: *mut T, len: usize, cap: usize) {
-    // SAFETY: The safety requirements from this function satisfy those of `from_raw_parts`.
-    let mut tmp = unsafe { Vec::from_raw_parts(ptr, len, cap) };
-    core::mem::swap(&mut tmp, v);
-}
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index bb80a43d20fb..fcc8656fdb51 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -14,10 +14,7 @@
 #[doc(no_inline)]
 pub use core::pin::Pin;
 
-pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
-
-#[doc(no_inline)]
-pub use alloc::vec::Vec;
+pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
 
 #[doc(no_inline)]
 pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 20/25] rust: alloc: add `Vec` to prelude
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (18 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 19/25] rust: alloc: remove `VecExt` extension Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 21/25] rust: alloc: remove `GlobalAlloc` and `krealloc_aligned` Danilo Krummrich
                   ` (4 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we removed `VecExt` and the corresponding includes in
prelude.rs, add the new kernel `Vec` type instead.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/prelude.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index fcc8656fdb51..b049ab96202e 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -14,7 +14,7 @@
 #[doc(no_inline)]
 pub use core::pin::Pin;
 
-pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
+pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec};
 
 #[doc(no_inline)]
 pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 21/25] rust: alloc: remove `GlobalAlloc` and `krealloc_aligned`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (19 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 20/25] rust: alloc: add `Vec` to prelude Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 22/25] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
                   ` (3 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we have all the `Allocator`s and the kernel `Box` and `Vec`
implementations in place, remove `GlobalAlloc` and `krealloc_aligned`.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc/allocator.rs | 63 ++--------------------------------
 1 file changed, 2 insertions(+), 61 deletions(-)

diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index 1e53f149db96..fbee89ac3be4 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -2,8 +2,8 @@
 
 //! Allocator support.
 
-use super::{flags::*, Flags};
-use core::alloc::{GlobalAlloc, Layout};
+use super::Flags;
+use core::alloc::Layout;
 use core::ptr;
 use core::ptr::NonNull;
 
@@ -39,27 +39,6 @@ fn aligned_size(new_layout: Layout) -> usize {
     layout.size()
 }
 
-/// Calls `krealloc` with a proper size to alloc a new object.
-///
-/// # Safety
-///
-/// - `ptr` can be either null or a pointer which has been allocated by this allocator.
-/// - `new_layout` must have a non-zero size.
-pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: Flags) -> *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 from `layout.size()` (which cannot be zero according
-    //   to the function safety requirement)
-    unsafe {
-        bindings::krealloc(
-            ptr as *const core::ffi::c_void,
-            aligned_size(new_layout),
-            flags.0,
-        ) as *mut u8
-    }
-}
-
 struct ReallocFunc(
     // INVARIANT: One of the following `krealloc`, `vrealloc`, `kvrealloc`.
     unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void,
@@ -121,41 +100,6 @@ unsafe fn realloc(
     }
 }
 
-unsafe impl GlobalAlloc for Kmalloc {
-    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 { krealloc_aligned(ptr::null_mut(), layout, GFP_KERNEL) }
-    }
-
-    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
-        unsafe {
-            bindings::kfree(ptr as *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 the function safety
-        //   requirement.
-        // - the size of `layout` is not zero because `new_size` is not zero by the function safety
-        //   requirement.
-        unsafe { krealloc_aligned(ptr, layout, 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 { krealloc_aligned(ptr::null_mut(), layout, GFP_KERNEL | __GFP_ZERO) }
-    }
-}
-
 unsafe impl Allocator for Vmalloc {
     unsafe fn realloc(
         ptr: Option<NonNull<u8>>,
@@ -184,9 +128,6 @@ unsafe fn realloc(
     }
 }
 
-#[global_allocator]
-static ALLOCATOR: Kmalloc = Kmalloc;
-
 // See <https://github.com/rust-lang/rust/pull/86844>.
 #[no_mangle]
 static __rust_no_alloc_shim_is_unstable: u8 = 0;
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 22/25] rust: error: use `core::alloc::LayoutError`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (20 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 21/25] rust: alloc: remove `GlobalAlloc` and `krealloc_aligned` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 23/25] rust: str: test: replace `alloc::format` Danilo Krummrich
                   ` (2 subsequent siblings)
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Use `core::alloc::LayoutError` instead of `alloc::alloc::LayoutError` in
preparation to get rid of Rust's alloc crate.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/error.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 145f5c397009..2d012cc3881a 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -6,7 +6,7 @@
 
 use crate::{alloc::AllocError, str::CStr};
 
-use alloc::alloc::LayoutError;
+use core::alloc::LayoutError;
 
 use core::fmt;
 use core::num::TryFromIntError;
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 23/25] rust: str: test: replace `alloc::format`
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (21 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 22/25] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 24/25] rust: alloc: update module comment of alloc.rs Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 25/25] kbuild: rust: remove the `alloc` crate Danilo Krummrich
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

The current implementation of tests in str.rs use `format!` to format
strings for comparison, which, internally, creates a new `String`.

In order to prepare for getting rid of Rust's alloc crate, we have to
cut this dependency. Instead, we could implement `format!` for
`CString`, however `CString` uses the kernel `Vec` type and hence the
kernel allocators, which can't be used for tests run in userspace.

Instead, implement `fmt_assert_eq`, which formats strings into a stack
allocated buffer for comparison with a `&str`.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/str.rs | 66 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 20 deletions(-)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 0b6ffbade521..539be40754f4 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -523,7 +523,6 @@ macro_rules! c_str {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use alloc::format;
 
     const ALL_ASCII_CHARS: &'static str =
         "\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\
@@ -539,6 +538,33 @@ mod tests {
         \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\
         \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff";
 
+    fn format_into_buf<'a>(args: fmt::Arguments<'_>, buf: &'a mut [u8]) -> Result<&'a str, Error> {
+        let mut f = RawFormatter::new();
+        f.write_fmt(args)?;
+        let size = f.bytes_written();
+
+        assert!(buf.len() >= size);
+
+        // SAFETY: `buf` has at least a size of `size` bytes and is valid for writes.
+        let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
+        f.write_fmt(args)?;
+
+        Ok(core::str::from_utf8(&buf[0..size])?)
+    }
+
+    macro_rules! fmt_assert_eq {
+        ($str:expr, $($f:tt)*) => ({
+            let mut buf = [0_u8; ALL_ASCII_CHARS.len()];
+
+            let s = match format_into_buf(kernel::fmt!($($f)*), &mut buf) {
+                Ok(s) => s,
+                Err(_) => panic!("Could not format into buffer."),
+            };
+
+            assert_eq!($str, s);
+        })
+    }
+
     #[test]
     fn test_cstr_to_str() {
         let good_bytes = b"\xf0\x9f\xa6\x80\0";
@@ -566,13 +592,13 @@ fn test_cstr_as_str_unchecked() {
     #[test]
     fn test_cstr_display() {
         let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap();
-        assert_eq!(format!("{}", hello_world), "hello, world!");
+        fmt_assert_eq!("hello, world!", "{}", hello_world);
         let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap();
-        assert_eq!(format!("{}", non_printables), "\\x01\\x09\\x0a");
+        fmt_assert_eq!("\\x01\\x09\\x0a", "{}", non_printables);
         let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap();
-        assert_eq!(format!("{}", non_ascii), "d\\xe9j\\xe0 vu");
+        fmt_assert_eq!("d\\xe9j\\xe0 vu", "{}", non_ascii);
         let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap();
-        assert_eq!(format!("{}", good_bytes), "\\xf0\\x9f\\xa6\\x80");
+        fmt_assert_eq!("\\xf0\\x9f\\xa6\\x80", "{}", good_bytes);
     }
 
     #[test]
@@ -583,47 +609,47 @@ fn test_cstr_display_all_bytes() {
             bytes[i as usize] = i.wrapping_add(1);
         }
         let cstr = CStr::from_bytes_with_nul(&bytes).unwrap();
-        assert_eq!(format!("{}", cstr), ALL_ASCII_CHARS);
+        fmt_assert_eq!(ALL_ASCII_CHARS, "{}", cstr);
     }
 
     #[test]
     fn test_cstr_debug() {
         let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap();
-        assert_eq!(format!("{:?}", hello_world), "\"hello, world!\"");
+        fmt_assert_eq!("\"hello, world!\"", "{:?}", hello_world);
         let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap();
-        assert_eq!(format!("{:?}", non_printables), "\"\\x01\\x09\\x0a\"");
+        fmt_assert_eq!("\"\\x01\\x09\\x0a\"", "{:?}", non_printables);
         let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap();
-        assert_eq!(format!("{:?}", non_ascii), "\"d\\xe9j\\xe0 vu\"");
+        fmt_assert_eq!("\"d\\xe9j\\xe0 vu\"", "{:?}", non_ascii);
         let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap();
-        assert_eq!(format!("{:?}", good_bytes), "\"\\xf0\\x9f\\xa6\\x80\"");
+        fmt_assert_eq!("\"\\xf0\\x9f\\xa6\\x80\"", "{:?}", good_bytes);
     }
 
     #[test]
     fn test_bstr_display() {
         let hello_world = BStr::from_bytes(b"hello, world!");
-        assert_eq!(format!("{}", hello_world), "hello, world!");
+        fmt_assert_eq!("hello, world!", "{}", hello_world);
         let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_");
-        assert_eq!(format!("{}", escapes), "_\\t_\\n_\\r_\\_'_\"_");
+        fmt_assert_eq!("_\\t_\\n_\\r_\\_'_\"_", "{}", escapes);
         let others = BStr::from_bytes(b"\x01");
-        assert_eq!(format!("{}", others), "\\x01");
+        fmt_assert_eq!("\\x01", "{}", others);
         let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu");
-        assert_eq!(format!("{}", non_ascii), "d\\xe9j\\xe0 vu");
+        fmt_assert_eq!("d\\xe9j\\xe0 vu", "{}", non_ascii);
         let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80");
-        assert_eq!(format!("{}", good_bytes), "\\xf0\\x9f\\xa6\\x80");
+        fmt_assert_eq!("\\xf0\\x9f\\xa6\\x80", "{}", good_bytes);
     }
 
     #[test]
     fn test_bstr_debug() {
         let hello_world = BStr::from_bytes(b"hello, world!");
-        assert_eq!(format!("{:?}", hello_world), "\"hello, world!\"");
+        fmt_assert_eq!("\"hello, world!\"", "{:?}", hello_world);
         let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_");
-        assert_eq!(format!("{:?}", escapes), "\"_\\t_\\n_\\r_\\\\_'_\\\"_\"");
+        fmt_assert_eq!("\"_\\t_\\n_\\r_\\\\_'_\\\"_\"", "{:?}", escapes);
         let others = BStr::from_bytes(b"\x01");
-        assert_eq!(format!("{:?}", others), "\"\\x01\"");
+        fmt_assert_eq!("\"\\x01\"", "{:?}", others);
         let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu");
-        assert_eq!(format!("{:?}", non_ascii), "\"d\\xe9j\\xe0 vu\"");
+        fmt_assert_eq!("\"d\\xe9j\\xe0 vu\"", "{:?}", non_ascii);
         let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80");
-        assert_eq!(format!("{:?}", good_bytes), "\"\\xf0\\x9f\\xa6\\x80\"");
+        fmt_assert_eq!("\"\\xf0\\x9f\\xa6\\x80\"", "{:?}", good_bytes);
     }
 }
 
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 24/25] rust: alloc: update module comment of alloc.rs
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (22 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 23/25] rust: str: test: replace `alloc::format` Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  2024-08-01  0:02 ` [PATCH v3 25/25] kbuild: rust: remove the `alloc` crate Danilo Krummrich
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Before we remove Rust's alloc crate, rewrite the module comment in
alloc.rs to avoid a rustdoc warning.

Besides that, the module comment in alloc.rs isn't correct anymore,
we're no longer extending Rust's alloc crate.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/alloc.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index fac9d3976657..903e2ba33491 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
-//! Extensions to the [`alloc`] crate.
+//! Implementation of the kernel's memory allocation infrastructure.
 
 #[cfg(not(any(test, testlib)))]
 pub mod allocator;
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v3 25/25] kbuild: rust: remove the `alloc` crate
  2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
                   ` (23 preceding siblings ...)
  2024-08-01  0:02 ` [PATCH v3 24/25] rust: alloc: update module comment of alloc.rs Danilo Krummrich
@ 2024-08-01  0:02 ` Danilo Krummrich
  24 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01  0:02 UTC (permalink / raw)
  To: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, aliceryhl, akpm
  Cc: daniel.almeida, faith.ekstrand, boris.brezillon, lina, mcanal,
	zhiw, acurrid, cjia, jhubbard, airlied, ajanulgu, lyude,
	linux-kernel, rust-for-linux, linux-mm, Danilo Krummrich

Now that we have our own `Allocator`, `Box` and `Vec` types we can remove
Rust's `alloc` crate and the corresponding unstable features.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/Makefile          | 44 ++++++++++--------------------------------
 rust/exports.c         |  1 -
 scripts/Makefile.build |  7 +------
 3 files changed, 11 insertions(+), 41 deletions(-)

diff --git a/rust/Makefile b/rust/Makefile
index 1f10f92737f2..8900c3d06573 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -15,9 +15,8 @@ always-$(CONFIG_RUST) += libmacros.so
 no-clean-files += libmacros.so
 
 always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
-obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
-always-$(CONFIG_RUST) += exports_alloc_generated.h exports_bindings_generated.h \
-    exports_kernel_generated.h
+obj-$(CONFIG_RUST) += bindings.o kernel.o
+always-$(CONFIG_RUST) += exports_bindings_generated.h exports_kernel_generated.h
 
 always-$(CONFIG_RUST) += uapi/uapi_generated.rs
 obj-$(CONFIG_RUST) += uapi.o
@@ -53,11 +52,6 @@ endif
 core-cfgs = \
     --cfg no_fp_fmt_parse
 
-alloc-cfgs = \
-    --cfg no_global_oom_handling \
-    --cfg no_rc \
-    --cfg no_sync
-
 quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
       cmd_rustdoc = \
 	OBJTREE=$(abspath $(objtree)) \
@@ -80,7 +74,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
 # command-like flags to solve the issue. Meanwhile, we use the non-custom case
 # and then retouch the generated files.
 rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
-    rustdoc-alloc rustdoc-kernel
+    rustdoc-kernel
 	$(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)/static.files/
 	$(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)/static.files/
 	$(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \
@@ -104,20 +98,11 @@ rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs FORCE
 rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE
 	+$(call if_changed,rustdoc)
 
-# We need to allow `rustdoc::broken_intra_doc_links` because some
-# `no_global_oom_handling` functions refer to non-`no_global_oom_handling`
-# functions. Ideally `rustdoc` would have a way to distinguish broken links
-# due to things that are "configured out" vs. entirely non-existing ones.
-rustdoc-alloc: private rustc_target_flags = $(alloc-cfgs) \
-    -Arustdoc::broken_intra_doc_links
-rustdoc-alloc: $(RUST_LIB_SRC)/alloc/src/lib.rs rustdoc-core rustdoc-compiler_builtins FORCE
-	+$(call if_changed,rustdoc)
-
-rustdoc-kernel: private rustc_target_flags = --extern alloc \
+rustdoc-kernel: private rustc_target_flags = \
     --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
     --extern bindings --extern uapi
 rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
-    rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
+    rustdoc-compiler_builtins $(obj)/libmacros.so \
     $(obj)/bindings.o FORCE
 	+$(call if_changed,rustdoc)
 
@@ -161,7 +146,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
 	mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
 	OBJTREE=$(abspath $(objtree)) \
 	$(RUSTDOC) --test $(rust_flags) \
-		-L$(objtree)/$(obj) --extern alloc --extern kernel \
+		-L$(objtree)/$(obj) --extern kernel \
 		--extern build_error --extern macros \
 		--extern bindings --extern uapi \
 		--no-run --crate-name kernel -Zunstable-options \
@@ -197,7 +182,7 @@ rusttest-macros: $(src)/macros/lib.rs FORCE
 	+$(call if_changed,rustc_test)
 	+$(call if_changed,rustdoc_test)
 
-rusttest-kernel: private rustc_target_flags = --extern alloc \
+rusttest-kernel: private rustc_target_flags = \
     --extern build_error --extern macros --extern bindings --extern uapi
 rusttest-kernel: $(src)/kernel/lib.rs \
     rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \
@@ -310,9 +295,6 @@ quiet_cmd_exports = EXPORTS $@
 $(obj)/exports_core_generated.h: $(obj)/core.o FORCE
 	$(call if_changed,exports)
 
-$(obj)/exports_alloc_generated.h: $(obj)/alloc.o FORCE
-	$(call if_changed,exports)
-
 $(obj)/exports_bindings_generated.h: $(obj)/bindings.o FORCE
 	$(call if_changed,exports)
 
@@ -348,7 +330,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
 
 rust-analyzer:
 	$(Q)$(srctree)/scripts/generate_rust_analyzer.py \
-		--cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-cfgs)' \
+		--cfgs='core=$(core-cfgs)' \
 		$(realpath $(srctree)) $(realpath $(objtree)) \
 		$(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \
 		$(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json
@@ -380,12 +362,6 @@ $(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
 $(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE
 	+$(call if_changed_dep,rustc_library)
 
-$(obj)/alloc.o: private skip_clippy = 1
-$(obj)/alloc.o: private skip_flags = -Wunreachable_pub
-$(obj)/alloc.o: private rustc_target_flags = $(alloc-cfgs)
-$(obj)/alloc.o: $(RUST_LIB_SRC)/alloc/src/lib.rs $(obj)/compiler_builtins.o FORCE
-	+$(call if_changed_dep,rustc_library)
-
 $(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
 	+$(call if_changed_dep,rustc_library)
 
@@ -400,9 +376,9 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
     $(obj)/uapi/uapi_generated.rs FORCE
 	+$(call if_changed_dep,rustc_library)
 
-$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
+$(obj)/kernel.o: private rustc_target_flags = \
     --extern build_error --extern macros --extern bindings --extern uapi
-$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
+$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \
     $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
 	+$(call if_changed_dep,rustc_library)
 
diff --git a/rust/exports.c b/rust/exports.c
index 3803c21d1403..1b870e8e83ea 100644
--- a/rust/exports.c
+++ b/rust/exports.c
@@ -16,7 +16,6 @@
 #define EXPORT_SYMBOL_RUST_GPL(sym) extern int sym; EXPORT_SYMBOL_GPL(sym)
 
 #include "exports_core_generated.h"
-#include "exports_alloc_generated.h"
 #include "exports_bindings_generated.h"
 #include "exports_kernel_generated.h"
 
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index efacca63c897..7e7b6b3d5bb9 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -262,18 +262,13 @@ $(obj)/%.lst: $(obj)/%.c FORCE
 
 # Compile Rust sources (.rs)
 # ---------------------------------------------------------------------------
-
-rust_allowed_features := new_uninit
-
 # `--out-dir` is required to avoid temporaries being created by `rustc` in the
 # current working directory, which may be not accessible in the out-of-tree
 # modules case.
 rust_common_cmd = \
 	RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
-	-Zallow-features=$(rust_allowed_features) \
 	-Zcrate-attr=no_std \
-	-Zcrate-attr='feature($(rust_allowed_features))' \
-	-Zunstable-options --extern force:alloc --extern kernel \
+	-Zunstable-options --extern kernel \
 	--crate-type rlib -L $(objtree)/rust/ \
 	--crate-name $(basename $(notdir $@)) \
 	--sysroot=/dev/null \
-- 
2.45.2



^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 01/25] rust: alloc: add `Allocator` trait
  2024-08-01  0:02 ` [PATCH v3 01/25] rust: alloc: add `Allocator` trait Danilo Krummrich
@ 2024-08-01  8:19   ` Alice Ryhl
  2024-08-01 12:26     ` Danilo Krummrich
  2024-08-04  6:21   ` Boqun Feng
  1 sibling, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:19 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Add a kernel specific `Allocator` trait, that in contrast to the one in
> Rust's core library doesn't require unstable features and supports GFP
> flags.
>
> Subsequent patches add the following trait implementors: `Kmalloc`,
> `Vmalloc` and `KVmalloc`.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

It could be nice to mention that the design without `self` parameters
is necessary for compatibility with #[derive(SmartPointer)].

>  rust/kernel/alloc.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 73 insertions(+)
>
> diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> index 1966bd407017..b79dd2c49277 100644
> --- a/rust/kernel/alloc.rs
> +++ b/rust/kernel/alloc.rs
> @@ -11,6 +11,7 @@
>  /// Indicates an allocation error.
>  #[derive(Copy, Clone, PartialEq, Eq, Debug)]
>  pub struct AllocError;
> +use core::{alloc::Layout, ptr::NonNull};
>
>  /// Flags to be used when allocating memory.
>  ///
> @@ -86,3 +87,75 @@ pub mod flags {
>      /// small allocations.
>      pub const GFP_NOWAIT: Flags = Flags(bindings::GFP_NOWAIT);
>  }
> +
> +/// The kernel's [`Allocator`] trait.
> +///
> +/// An implementation of [`Allocator`] can allocate, re-allocate and free memory buffer described
> +/// via [`Layout`].
> +///
> +/// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
> +/// an object instance.
> +///
> +/// # Safety
> +///
> +/// Memory returned from an allocator must point to a valid memory buffer and remain valid until
> +/// it is explicitly freed.
> +///
> +/// Any pointer to a memory buffer which is currently allocated must be valid to be passed to any
> +/// other [`Allocator`] function. The same applies for a NULL pointer.
> +///
> +/// If `realloc` is called with:
> +///   - a size of zero, the given memory allocation, if any, must be freed
> +///   - a NULL pointer, a new memory allocation must be created
> +pub unsafe trait Allocator {
> +    /// Allocate memory based on `layout` and `flags`.
> +    ///
> +    /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
> +    /// constraints (i.e. minimum size and alignment as specified by `layout`).
> +    ///
> +    /// This function is equivalent to `realloc` when called with a NULL pointer.
> +    fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
> +        // SAFETY: Passing a NULL pointer to `realloc` is valid by it's safety requirements and asks
> +        // for a new memory allocation.
> +        unsafe { Self::realloc(None, layout, flags) }
> +    }
> +
> +    /// Re-allocate an existing memory allocation to satisfy the requested `layout`. If the
> +    /// requested size is zero, `realloc` behaves equivalent to `free`.
> +    ///
> +    /// If the requested size is larger than the size of the existing allocation, a successful call
> +    /// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
> +    /// may also be larger.
> +    ///
> +    /// If the requested size is smaller than the size of the existing allocation, `realloc` may or
> +    /// may not shrink the buffer; this is implementation specific to the allocator.
> +    ///
> +    /// On allocation failure, the existing buffer, if any, remains valid.
> +    ///
> +    /// The buffer is represented as `NonNull<[u8]>`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must point to an existing and valid memory allocation created by this allocator
> +    /// instance.
> +    ///
> +    /// Additionally, `ptr` is allowed to be a NULL pointer; in this case a new memory allocation is
> +    /// created.
> +    unsafe fn realloc(
> +        ptr: Option<NonNull<u8>>,
> +        layout: Layout,
> +        flags: Flags,
> +    ) -> Result<NonNull<[u8]>, AllocError>;

Is it intentional that this allows you to change the alignment of an
allocation? If so, that could use a note in the docs.

> +    /// Free an existing memory allocation.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must point to an existing and valid memory allocation created by this `Allocator`
> +    /// instance.
> +    unsafe fn free(ptr: NonNull<u8>) {
> +        // SAFETY: `ptr` is guaranteed to be previously allocated with this `Allocator` or NULL.
> +        // Calling `realloc` with a buffer size of zero, frees the buffer `ptr` points to.
> +        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
> +    }

At the very least, the provided implementation of `free` changes the
alignment when it calls `realloc`.

Alice


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 02/25] rust: alloc: separate `aligned_size` from `krealloc_aligned`
  2024-08-01  0:02 ` [PATCH v3 02/25] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
@ 2024-08-01  8:21   ` Alice Ryhl
  0 siblings, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:21 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Separate `aligned_size` from `krealloc_aligned`.
>
> Subsequent patches implement `Allocator` derivates, such as `Kmalloc`,
> that require `aligned_size` and replace the original `krealloc_aligned`.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

Reviewed-by: Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 03/25] rust: alloc: rename `KernelAllocator` to `Kmalloc`
  2024-08-01  0:02 ` [PATCH v3 03/25] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
@ 2024-08-01  8:21   ` Alice Ryhl
  0 siblings, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:21 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Subsequent patches implement `Vmalloc` and `KVmalloc` allocators, hence
> align `KernelAllocator` to this naming scheme.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

Reviewed-by: Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc`
  2024-08-01  0:02 ` [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
@ 2024-08-01  8:28   ` Alice Ryhl
  2024-08-01 12:30     ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:28 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> +/// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
>  fn aligned_size(new_layout: Layout) -> usize {

This comment could potentially be moved to the previous patch that
defined the function.

> +struct ReallocFunc(
> +    // INVARIANT: One of the following `krealloc`, `vrealloc`, `kvrealloc`.
> +    unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void,
> +);

In this case, the comment would usually be formatted with markdown.

/// # Invariants
///
/// Must contain one of the following: `krealloc`, `vrealloc`, `kvrealloc`.

The // INVARIANT: syntax is used when constructing an instance to
argue why the documentented invariants are satisfied.

> +impl ReallocFunc {
> +    fn krealloc() -> Self {
> +        Self(bindings::krealloc)
> +    }

Technically this should have an // INVARIANT: explaining why the
invariants are satisfied by this new value.

> +
> +    // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
> +    unsafe fn call(

Similarly to the above, the // SAFETY: syntax is used when arguing why
the preconditions are satisfied, but when explaining what the
preconditions are, we usually use this syntax instead:

/// # Safety
///
/// This method has the same safety requirements as `Allocator::realloc`.

> +        &self,
> +        ptr: Option<NonNull<u8>>,
> +        layout: Layout,
> +        flags: Flags,
> +    ) -> Result<NonNull<[u8]>, AllocError> {
> +        let size = aligned_size(layout);
> +        let ptr = match ptr {
> +            Some(ptr) => ptr.as_ptr(),
> +            None => ptr::null(),
> +        };
> +
> +        // SAFETY: `ptr` is valid by the safety requirements of this function.
> +        let raw_ptr = unsafe {
> +            // If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
> +            self.0(ptr.cast(), size, flags.0).cast()
> +        };
> +
> +        let ptr = if size == 0 {
> +            NonNull::dangling()
> +        } else {
> +            NonNull::new(raw_ptr).ok_or(AllocError)?
> +        };
> +
> +        Ok(NonNull::slice_from_raw_parts(ptr, size))
> +    }
> +}
> +
> +unsafe impl Allocator for Kmalloc {
> +    unsafe fn realloc(
> +        ptr: Option<NonNull<u8>>,
> +        layout: Layout,
> +        flags: Flags,
> +    ) -> Result<NonNull<[u8]>, AllocError> {
> +        let realloc = ReallocFunc::krealloc();
> +
> +        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
> +        // allocated with this `Allocator`.
> +        unsafe { realloc.call(ptr, layout, flags) }
> +    }
> +}
> +
>  unsafe impl GlobalAlloc for Kmalloc {
>      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
> --
> 2.45.2
>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 05/25] rust: alloc: add module `allocator_test`
  2024-08-01  0:02 ` [PATCH v3 05/25] rust: alloc: add module `allocator_test` Danilo Krummrich
@ 2024-08-01  8:41   ` Alice Ryhl
  0 siblings, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:41 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> `Allocator`s, such as `Kmalloc`, will be used by e.g. `Box` and `Vec` in
> subsequent patches, and hence this dependency propagates throughout the
> whole kernel.
>
> Add the `allocator_test` module that provides an empty implementation
> for all `Allocator`s in the kernel, such that we don't break the
> `rusttest` make target in subsequent patches.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

Ah, yes, the rusttest target ...

Reviewed-by: Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-01  0:02 ` [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
@ 2024-08-01  8:43   ` Alice Ryhl
  2024-08-04  6:44   ` Boqun Feng
  1 sibling, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:43 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous
> allocator, typically used for larger objects, (much) larger than page
> size.
>
> All memory allocations made with `Vmalloc` end up in `vrealloc()`.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

One nit below, but.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>

>  rust/helpers.c                      |  8 ++++++++
>  rust/kernel/alloc/allocator.rs      | 24 ++++++++++++++++++++++++
>  rust/kernel/alloc/allocator_test.rs |  1 +
>  3 files changed, 33 insertions(+)
>
> diff --git a/rust/helpers.c b/rust/helpers.c
> index 92d3c03ae1bd..4c628986f0c9 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -33,6 +33,7 @@
>  #include <linux/sched/signal.h>
>  #include <linux/slab.h>
>  #include <linux/spinlock.h>
> +#include <linux/vmalloc.h>
>  #include <linux/wait.h>
>  #include <linux/workqueue.h>
>
> @@ -200,6 +201,13 @@ rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags)
>  }
>  EXPORT_SYMBOL_GPL(rust_helper_krealloc);
>
> +void * __must_check __realloc_size(2)
> +rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
> +{
> +       return vrealloc(p, size, flags);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
> +
>  /*
>   * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
>   * use it in contexts where Rust expects a `usize` like slice (array) indices.
> diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
> index 397ae5bcc043..e9a3d0694f41 100644
> --- a/rust/kernel/alloc/allocator.rs
> +++ b/rust/kernel/alloc/allocator.rs
> @@ -16,6 +16,12 @@
>  /// `bindings::krealloc`.
>  pub struct Kmalloc;
>
> +/// The virtually contiguous kernel allocator.
> +///
> +/// The vmalloc allocator allocates pages from the page level allocator and maps them into the
> +/// contiguous kernel virtual space.
> +pub struct Vmalloc;
> +
>  /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
>  fn aligned_size(new_layout: Layout) -> usize {
>      // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
> @@ -58,6 +64,10 @@ fn krealloc() -> Self {
>          Self(bindings::krealloc)
>      }
>
> +    fn vrealloc() -> Self {
> +        Self(bindings::vrealloc)
> +    }

Technically needs an

// INVARIANT: The function pointer is vrealloc.
Self(bindings::vrealloc)

> +
>      // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
>      unsafe fn call(
>          &self,
> @@ -136,6 +146,20 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
>      }
>  }
>
> +unsafe impl Allocator for Vmalloc {
> +    unsafe fn realloc(
> +        ptr: Option<NonNull<u8>>,
> +        layout: Layout,
> +        flags: Flags,
> +    ) -> Result<NonNull<[u8]>, AllocError> {
> +        let realloc = ReallocFunc::vrealloc();
> +
> +        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
> +        // allocated with this `Allocator`.
> +        unsafe { realloc.call(ptr, layout, flags) }
> +    }
> +}
> +
>  #[global_allocator]
>  static ALLOCATOR: Kmalloc = Kmalloc;
>
> diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
> index 4785efc474a7..e7bf2982f68f 100644
> --- a/rust/kernel/alloc/allocator_test.rs
> +++ b/rust/kernel/alloc/allocator_test.rs
> @@ -7,6 +7,7 @@
>  use core::ptr::NonNull;
>
>  pub struct Kmalloc;
> +pub type Vmalloc = Kmalloc;
>
>  unsafe impl Allocator for Kmalloc {
>      unsafe fn realloc(
> --
> 2.45.2
>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator
  2024-08-01  0:02 ` [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
@ 2024-08-01  8:43   ` Alice Ryhl
  2024-08-01 12:31     ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:43 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Implement `Allocator` for `KVmalloc`, an `Allocator` that tries to
> allocate memory wth `kmalloc` first and, on failure, falls back to
> `vmalloc`.
>
> All memory allocations made with `KVmalloc` end up in
> `kvrealloc_noprof()`; all frees in `kvfree()`.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

The nit from vrealloc also applies here, but:

Reviewed-by: Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 09/25] rust: alloc: implement kernel `Box`
  2024-08-01  0:02 ` [PATCH v3 09/25] rust: alloc: implement kernel `Box` Danilo Krummrich
@ 2024-08-01  8:55   ` Alice Ryhl
  2024-08-01 12:45     ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01  8:55 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> `Box` provides the simplest way to allocate memory for a generic type
> with one of the kernel's allocators, e.g. `Kmalloc`, `Vmalloc` or
> `KVmalloc`.
>
> In contrast to Rust's `Box` type, the kernel `Box` type considers the
> kernel's GFP flags for all appropriate functions, always reports
> allocation failures through `Result<_, AllocError>` and remains
> independent from unstable features.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
>
> [...]
>
> +    /// Constructs a `Box<T, A>` from a raw pointer.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `raw` must point to valid memory, previously allocated with `A`, and at least the size of
> +    /// type `T`.
> +    #[inline]
> +    pub const unsafe fn from_raw_alloc(raw: *mut T, alloc: PhantomData<A>) -> Self {
> +        // SAFETY: Safe by the requirements of this function.
> +        Box(unsafe { Unique::new_unchecked(raw) }, alloc)
> +    }

I don't think it makes sense to take the PhantomData as a parameter.
You can always create a PhantomData value out of thin air.

Box(unsafe { Unique::new_unchecked(raw) }, PhantomData)

> +    /// Consumes the `Box<T, A>`, returning a wrapped raw pointer and `PhantomData` of the allocator
> +    /// it was allocated with.
> +    pub fn into_raw_alloc(b: Self) -> (*mut T, PhantomData<A>) {
> +        let b = ManuallyDrop::new(b);
> +        let alloc = unsafe { ptr::read(&b.1) };
> +        (b.0.as_ptr(), alloc)
> +    }

I don't think there's any need to have this function. The caller can
always create the PhantomData themselves. I would just keep into_raw
only.

> +    /// Converts a `Box<T>` into a `Pin<Box<T>>`.
> +    #[inline]
> +    pub fn into_pin(b: Self) -> Pin<Self>
> +    where
> +        A: 'static,
> +    {
> +        // SAFETY: It's not possible to move or replace the insides of a `Pin<Box<T>>` when
> +        // `T: !Unpin`, so it's safe to pin it directly without any additional requirements.
> +        unsafe { Pin::new_unchecked(b) }
> +    }

In the standard library, this functionality is provided using the From
trait rather than an inherent method. I think it makes sense to match
std here.

> +impl<T, A> Drop for Box<T, A>
> +where
> +    T: ?Sized,
> +    A: Allocator,
> +{
> +    fn drop(&mut self) {
> +        let ptr = self.0.as_ptr();
> +
> +        // SAFETY: We need to drop `self.0` in place, before we free the backing memory.
> +        unsafe { core::ptr::drop_in_place(ptr) };
> +
> +        // SAFETY: `ptr` is always properly aligned, dereferenceable and points to an initialized
> +        // instance of `T`.
> +        if unsafe { core::mem::size_of_val(&*ptr) } != 0 {
> +            // SAFETY: `ptr` was previously allocated with `A`.
> +            unsafe { A::free(self.0.as_non_null().cast()) };
> +        }

You just destroyed the value by calling `drop_in_place`, so `ptr` no
longer points at an initialized instance of `T`. Please compute
whether the allocation has non-zero size before you call
`drop_in_place`.

Also, in normal Rust this code would leak the allocation on panic in
the destructor. We may not care, but it's worth taking into account if
anybody else copies this code to a different project with a different
panic configuration.

> +impl<T: 'static, A> ForeignOwnable for crate::alloc::Box<T, A>
> +where
> +    A: Allocator,
> +{
> +    type Borrowed<'a> = &'a T;
> +
> +    fn into_foreign(self) -> *const core::ffi::c_void {
> +        crate::alloc::Box::into_raw(self) as _
> +    }
> +
> +    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
> +        // SAFETY: The safety requirements for this function ensure that the object is still alive,
> +        // so it is safe to dereference the raw pointer.
> +        // The safety requirements of `from_foreign` also ensure that the object remains alive for
> +        // the lifetime of the returned value.
> +        unsafe { &*ptr.cast() }
> +    }
> +
> +    unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
> +        // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
> +        // call to `Self::into_foreign`.
> +        unsafe { crate::alloc::Box::from_raw(ptr as _) }
> +    }
> +}

You may want to also implement ForeignOwnable for Pin<Box<T>>. See:
https://lore.kernel.org/all/20240730-foreign-ownable-pin-box-v1-1-b1d70cdae541@google.com/

Alice


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 01/25] rust: alloc: add `Allocator` trait
  2024-08-01  8:19   ` Alice Ryhl
@ 2024-08-01 12:26     ` Danilo Krummrich
  2024-08-01 14:25       ` Alice Ryhl
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 12:26 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 10:19:41AM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > Add a kernel specific `Allocator` trait, that in contrast to the one in
> > Rust's core library doesn't require unstable features and supports GFP
> > flags.
> >
> > Subsequent patches add the following trait implementors: `Kmalloc`,
> > `Vmalloc` and `KVmalloc`.
> >
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> 
> It could be nice to mention that the design without `self` parameters
> is necessary for compatibility with #[derive(SmartPointer)].

Agreed, will do.

> 
> >  rust/kernel/alloc.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 73 insertions(+)
> >
> > diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> > index 1966bd407017..b79dd2c49277 100644
> > --- a/rust/kernel/alloc.rs
> > +++ b/rust/kernel/alloc.rs
> > @@ -11,6 +11,7 @@
> >  /// Indicates an allocation error.
> >  #[derive(Copy, Clone, PartialEq, Eq, Debug)]
> >  pub struct AllocError;
> > +use core::{alloc::Layout, ptr::NonNull};
> >
> >  /// Flags to be used when allocating memory.
> >  ///
> > @@ -86,3 +87,75 @@ pub mod flags {
> >      /// small allocations.
> >      pub const GFP_NOWAIT: Flags = Flags(bindings::GFP_NOWAIT);
> >  }
> > +
> > +/// The kernel's [`Allocator`] trait.
> > +///
> > +/// An implementation of [`Allocator`] can allocate, re-allocate and free memory buffer described
> > +/// via [`Layout`].
> > +///
> > +/// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
> > +/// an object instance.
> > +///
> > +/// # Safety
> > +///
> > +/// Memory returned from an allocator must point to a valid memory buffer and remain valid until
> > +/// it is explicitly freed.
> > +///
> > +/// Any pointer to a memory buffer which is currently allocated must be valid to be passed to any
> > +/// other [`Allocator`] function. The same applies for a NULL pointer.
> > +///
> > +/// If `realloc` is called with:
> > +///   - a size of zero, the given memory allocation, if any, must be freed
> > +///   - a NULL pointer, a new memory allocation must be created
> > +pub unsafe trait Allocator {
> > +    /// Allocate memory based on `layout` and `flags`.
> > +    ///
> > +    /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
> > +    /// constraints (i.e. minimum size and alignment as specified by `layout`).
> > +    ///
> > +    /// This function is equivalent to `realloc` when called with a NULL pointer.
> > +    fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
> > +        // SAFETY: Passing a NULL pointer to `realloc` is valid by it's safety requirements and asks
> > +        // for a new memory allocation.
> > +        unsafe { Self::realloc(None, layout, flags) }
> > +    }
> > +
> > +    /// Re-allocate an existing memory allocation to satisfy the requested `layout`. If the
> > +    /// requested size is zero, `realloc` behaves equivalent to `free`.
> > +    ///
> > +    /// If the requested size is larger than the size of the existing allocation, a successful call
> > +    /// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
> > +    /// may also be larger.
> > +    ///
> > +    /// If the requested size is smaller than the size of the existing allocation, `realloc` may or
> > +    /// may not shrink the buffer; this is implementation specific to the allocator.
> > +    ///
> > +    /// On allocation failure, the existing buffer, if any, remains valid.
> > +    ///
> > +    /// The buffer is represented as `NonNull<[u8]>`.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// `ptr` must point to an existing and valid memory allocation created by this allocator
> > +    /// instance.
> > +    ///
> > +    /// Additionally, `ptr` is allowed to be a NULL pointer; in this case a new memory allocation is
> > +    /// created.
> > +    unsafe fn realloc(
> > +        ptr: Option<NonNull<u8>>,
> > +        layout: Layout,
> > +        flags: Flags,
> > +    ) -> Result<NonNull<[u8]>, AllocError>;
> 
> Is it intentional that this allows you to change the alignment of an
> allocation? If so, that could use a note in the docs.

Yes, it's intentional and yes it really misses a note in the documentation.

The idea is to allow a change of alignment as long as the new alignment is
smaller than the old alignment.

In terms of safety, it is the callers responsibility to ensure constant
alignment throughout re-allocations (if required).

> 
> > +    /// Free an existing memory allocation.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// `ptr` must point to an existing and valid memory allocation created by this `Allocator`
> > +    /// instance.
> > +    unsafe fn free(ptr: NonNull<u8>) {
> > +        // SAFETY: `ptr` is guaranteed to be previously allocated with this `Allocator` or NULL.
> > +        // Calling `realloc` with a buffer size of zero, frees the buffer `ptr` points to.
> > +        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
> > +    }
> 
> At the very least, the provided implementation of `free` changes the
> alignment when it calls `realloc`.

Yes, I think that's fine though. Hopefully no one attempts to use the memory
anymore once `free` is being called.

> 
> Alice
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc`
  2024-08-01  8:28   ` Alice Ryhl
@ 2024-08-01 12:30     ` Danilo Krummrich
  0 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 12:30 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 10:28:09AM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > +/// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
> >  fn aligned_size(new_layout: Layout) -> usize {
> 
> This comment could potentially be moved to the previous patch that
> defined the function.
> 
> > +struct ReallocFunc(
> > +    // INVARIANT: One of the following `krealloc`, `vrealloc`, `kvrealloc`.
> > +    unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void,
> > +);
> 
> In this case, the comment would usually be formatted with markdown.
> 
> /// # Invariants
> ///
> /// Must contain one of the following: `krealloc`, `vrealloc`, `kvrealloc`.
> 
> The // INVARIANT: syntax is used when constructing an instance to
> argue why the documentented invariants are satisfied.
> 
> > +impl ReallocFunc {
> > +    fn krealloc() -> Self {
> > +        Self(bindings::krealloc)
> > +    }
> 
> Technically this should have an // INVARIANT: explaining why the
> invariants are satisfied by this new value.
> 
> > +
> > +    // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
> > +    unsafe fn call(
> 
> Similarly to the above, the // SAFETY: syntax is used when arguing why
> the preconditions are satisfied, but when explaining what the
> preconditions are, we usually use this syntax instead:
> 
> /// # Safety
> ///
> /// This method has the same safety requirements as `Allocator::realloc`.

Agreed, I will change this one and the above.

> 
> > +        &self,
> > +        ptr: Option<NonNull<u8>>,
> > +        layout: Layout,
> > +        flags: Flags,
> > +    ) -> Result<NonNull<[u8]>, AllocError> {
> > +        let size = aligned_size(layout);
> > +        let ptr = match ptr {
> > +            Some(ptr) => ptr.as_ptr(),
> > +            None => ptr::null(),
> > +        };
> > +
> > +        // SAFETY: `ptr` is valid by the safety requirements of this function.
> > +        let raw_ptr = unsafe {
> > +            // If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
> > +            self.0(ptr.cast(), size, flags.0).cast()
> > +        };
> > +
> > +        let ptr = if size == 0 {
> > +            NonNull::dangling()
> > +        } else {
> > +            NonNull::new(raw_ptr).ok_or(AllocError)?
> > +        };
> > +
> > +        Ok(NonNull::slice_from_raw_parts(ptr, size))
> > +    }
> > +}
> > +
> > +unsafe impl Allocator for Kmalloc {
> > +    unsafe fn realloc(
> > +        ptr: Option<NonNull<u8>>,
> > +        layout: Layout,
> > +        flags: Flags,
> > +    ) -> Result<NonNull<[u8]>, AllocError> {
> > +        let realloc = ReallocFunc::krealloc();
> > +
> > +        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
> > +        // allocated with this `Allocator`.
> > +        unsafe { realloc.call(ptr, layout, flags) }
> > +    }
> > +}
> > +
> >  unsafe impl GlobalAlloc for Kmalloc {
> >      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
> > --
> > 2.45.2
> >
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator
  2024-08-01  8:43   ` Alice Ryhl
@ 2024-08-01 12:31     ` Danilo Krummrich
  0 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 12:31 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 10:43:44AM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > Implement `Allocator` for `KVmalloc`, an `Allocator` that tries to
> > allocate memory wth `kmalloc` first and, on failure, falls back to
> > `vmalloc`.
> >
> > All memory allocations made with `KVmalloc` end up in
> > `kvrealloc_noprof()`; all frees in `kvfree()`.
> >
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> 
> The nit from vrealloc also applies here, but:

Yes, I will add the invariant comment for both.

> 
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 09/25] rust: alloc: implement kernel `Box`
  2024-08-01  8:55   ` Alice Ryhl
@ 2024-08-01 12:45     ` Danilo Krummrich
  2024-08-01 12:48       ` Alice Ryhl
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 12:45 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 10:55:51AM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > `Box` provides the simplest way to allocate memory for a generic type
> > with one of the kernel's allocators, e.g. `Kmalloc`, `Vmalloc` or
> > `KVmalloc`.
> >
> > In contrast to Rust's `Box` type, the kernel `Box` type considers the
> > kernel's GFP flags for all appropriate functions, always reports
> > allocation failures through `Result<_, AllocError>` and remains
> > independent from unstable features.
> >
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> >
> > [...]
> >
> > +    /// Constructs a `Box<T, A>` from a raw pointer.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// `raw` must point to valid memory, previously allocated with `A`, and at least the size of
> > +    /// type `T`.
> > +    #[inline]
> > +    pub const unsafe fn from_raw_alloc(raw: *mut T, alloc: PhantomData<A>) -> Self {
> > +        // SAFETY: Safe by the requirements of this function.
> > +        Box(unsafe { Unique::new_unchecked(raw) }, alloc)
> > +    }
> 
> I don't think it makes sense to take the PhantomData as a parameter.
> You can always create a PhantomData value out of thin air.
> 
> Box(unsafe { Unique::new_unchecked(raw) }, PhantomData)
> 
> > +    /// Consumes the `Box<T, A>`, returning a wrapped raw pointer and `PhantomData` of the allocator
> > +    /// it was allocated with.
> > +    pub fn into_raw_alloc(b: Self) -> (*mut T, PhantomData<A>) {
> > +        let b = ManuallyDrop::new(b);
> > +        let alloc = unsafe { ptr::read(&b.1) };
> > +        (b.0.as_ptr(), alloc)
> > +    }
> 
> I don't think there's any need to have this function. The caller can
> always create the PhantomData themselves. I would just keep into_raw
> only.

Agreed, I actually intended to remove this one and the above.

> 
> > +    /// Converts a `Box<T>` into a `Pin<Box<T>>`.
> > +    #[inline]
> > +    pub fn into_pin(b: Self) -> Pin<Self>
> > +    where
> > +        A: 'static,
> > +    {
> > +        // SAFETY: It's not possible to move or replace the insides of a `Pin<Box<T>>` when
> > +        // `T: !Unpin`, so it's safe to pin it directly without any additional requirements.
> > +        unsafe { Pin::new_unchecked(b) }
> > +    }
> 
> In the standard library, this functionality is provided using the From
> trait rather than an inherent method. I think it makes sense to match
> std here.

I already provide `impl<T, A> From<Box<T, A>> for Pin<Box<T, A>>` in this patch,
which just calls `Box::into_pin`.

> 
> > +impl<T, A> Drop for Box<T, A>
> > +where
> > +    T: ?Sized,
> > +    A: Allocator,
> > +{
> > +    fn drop(&mut self) {
> > +        let ptr = self.0.as_ptr();
> > +
> > +        // SAFETY: We need to drop `self.0` in place, before we free the backing memory.
> > +        unsafe { core::ptr::drop_in_place(ptr) };
> > +
> > +        // SAFETY: `ptr` is always properly aligned, dereferenceable and points to an initialized
> > +        // instance of `T`.
> > +        if unsafe { core::mem::size_of_val(&*ptr) } != 0 {
> > +            // SAFETY: `ptr` was previously allocated with `A`.
> > +            unsafe { A::free(self.0.as_non_null().cast()) };
> > +        }
> 
> You just destroyed the value by calling `drop_in_place`, so `ptr` no
> longer points at an initialized instance of `T`. Please compute
> whether the allocation has non-zero size before you call
> `drop_in_place`.

Huh! Good catch. No idea how I missed that.

> 
> Also, in normal Rust this code would leak the allocation on panic in
> the destructor. We may not care, but it's worth taking into account if
> anybody else copies this code to a different project with a different
> panic configuration.

I can add a corresponding note.

> 
> > +impl<T: 'static, A> ForeignOwnable for crate::alloc::Box<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    type Borrowed<'a> = &'a T;
> > +
> > +    fn into_foreign(self) -> *const core::ffi::c_void {
> > +        crate::alloc::Box::into_raw(self) as _
> > +    }
> > +
> > +    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
> > +        // SAFETY: The safety requirements for this function ensure that the object is still alive,
> > +        // so it is safe to dereference the raw pointer.
> > +        // The safety requirements of `from_foreign` also ensure that the object remains alive for
> > +        // the lifetime of the returned value.
> > +        unsafe { &*ptr.cast() }
> > +    }
> > +
> > +    unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
> > +        // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
> > +        // call to `Self::into_foreign`.
> > +        unsafe { crate::alloc::Box::from_raw(ptr as _) }
> > +    }
> > +}
> 
> You may want to also implement ForeignOwnable for Pin<Box<T>>. See:
> https://lore.kernel.org/all/20240730-foreign-ownable-pin-box-v1-1-b1d70cdae541@google.com/

Yeah, I think I've also seen another patch that it about to add a function to
convert a `Box` back into uninit state.

Depending how fast you need ForeignOwnable for Pin<Box<T>>, do you prefer to
contribute a corresponding patch to this series?

> 
> Alice
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 09/25] rust: alloc: implement kernel `Box`
  2024-08-01 12:45     ` Danilo Krummrich
@ 2024-08-01 12:48       ` Alice Ryhl
  0 siblings, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 12:48 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:45 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu, Aug 01, 2024 at 10:55:51AM +0200, Alice Ryhl wrote:
> > On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > +    /// Converts a `Box<T>` into a `Pin<Box<T>>`.
> > > +    #[inline]
> > > +    pub fn into_pin(b: Self) -> Pin<Self>
> > > +    where
> > > +        A: 'static,
> > > +    {
> > > +        // SAFETY: It's not possible to move or replace the insides of a `Pin<Box<T>>` when
> > > +        // `T: !Unpin`, so it's safe to pin it directly without any additional requirements.
> > > +        unsafe { Pin::new_unchecked(b) }
> > > +    }
> >
> > In the standard library, this functionality is provided using the From
> > trait rather than an inherent method. I think it makes sense to match
> > std here.
>
> I already provide `impl<T, A> From<Box<T, A>> for Pin<Box<T, A>>` in this patch,
> which just calls `Box::into_pin`.

Ah, ok, I might drop into_pin and only have From, but I'm ok either way.

> > > +impl<T: 'static, A> ForeignOwnable for crate::alloc::Box<T, A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    type Borrowed<'a> = &'a T;
> > > +
> > > +    fn into_foreign(self) -> *const core::ffi::c_void {
> > > +        crate::alloc::Box::into_raw(self) as _
> > > +    }
> > > +
> > > +    unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
> > > +        // SAFETY: The safety requirements for this function ensure that the object is still alive,
> > > +        // so it is safe to dereference the raw pointer.
> > > +        // The safety requirements of `from_foreign` also ensure that the object remains alive for
> > > +        // the lifetime of the returned value.
> > > +        unsafe { &*ptr.cast() }
> > > +    }
> > > +
> > > +    unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
> > > +        // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
> > > +        // call to `Self::into_foreign`.
> > > +        unsafe { crate::alloc::Box::from_raw(ptr as _) }
> > > +    }
> > > +}
> >
> > You may want to also implement ForeignOwnable for Pin<Box<T>>. See:
> > https://lore.kernel.org/all/20240730-foreign-ownable-pin-box-v1-1-b1d70cdae541@google.com/
>
> Yeah, I think I've also seen another patch that it about to add a function to
> convert a `Box` back into uninit state.
>
> Depending how fast you need ForeignOwnable for Pin<Box<T>>, do you prefer to
> contribute a corresponding patch to this series?

It's easiest for me if you just add it to this patch of your series. I
don't care about credit in this particular case.

Alice


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 01/25] rust: alloc: add `Allocator` trait
  2024-08-01 12:26     ` Danilo Krummrich
@ 2024-08-01 14:25       ` Alice Ryhl
  2024-08-01 15:09         ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 14:25 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:27 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu, Aug 01, 2024 at 10:19:41AM +0200, Alice Ryhl wrote:
> > On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > +    /// Free an existing memory allocation.
> > > +    ///
> > > +    /// # Safety
> > > +    ///
> > > +    /// `ptr` must point to an existing and valid memory allocation created by this `Allocator`
> > > +    /// instance.
> > > +    unsafe fn free(ptr: NonNull<u8>) {
> > > +        // SAFETY: `ptr` is guaranteed to be previously allocated with this `Allocator` or NULL.
> > > +        // Calling `realloc` with a buffer size of zero, frees the buffer `ptr` points to.
> > > +        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
> > > +    }
> >
> > At the very least, the provided implementation of `free` changes the
> > alignment when it calls `realloc`.
>
> Yes, I think that's fine though. Hopefully no one attempts to use the memory
> anymore once `free` is being called.

Sure, but if you require the alignment to remain constant throughout
calls to realloc, then you have to word it in a way that allows a
different alignment when the new size is zero.

Alice


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 11/25] rust: alloc: remove `BoxExt` extension
  2024-08-01  0:02 ` [PATCH v3 11/25] rust: alloc: remove `BoxExt` extension Danilo Krummrich
@ 2024-08-01 14:53   ` Alice Ryhl
  0 siblings, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 14:53 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Now that all existing `Box` users were moved to the kernel `Box` type,
> remove the `BoxExt` extension.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

Reviewed-by: Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 14/25] rust: alloc: import kernel `Box` type in init.rs
  2024-08-01  0:02 ` [PATCH v3 14/25] rust: alloc: import kernel `Box` type in init.rs Danilo Krummrich
@ 2024-08-01 14:55   ` Alice Ryhl
  0 siblings, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 14:55 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Now that we removed `BoxExt` and the corresponding includes in
> init.rs, add the new kernel `Box` type instead.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

Reviewed-by: Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type
  2024-08-01  0:02 ` [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type Danilo Krummrich
@ 2024-08-01 15:05   ` Alice Ryhl
  2024-08-01 15:27     ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 15:05 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> `Vec` provides a contiguous growable array type (such as `Vec`) with
> contents allocated with the kernel's allocators (e.g. `Kmalloc`,
> `Vmalloc` or `KVmalloc`).
>
> In contrast to Rust's `Vec` type, the kernel `Vec` type considers the
> kernel's GFP flags for all appropriate functions, always reports
> allocation failures through `Result<_, AllocError>` and remains
> independent from unstable features.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/alloc.rs      |   6 +
>  rust/kernel/alloc/kbox.rs |  16 +-
>  rust/kernel/alloc/kvec.rs | 583 ++++++++++++++++++++++++++++++++++++++
>  rust/kernel/prelude.rs    |   2 +-
>  4 files changed, 605 insertions(+), 2 deletions(-)
>  create mode 100644 rust/kernel/alloc/kvec.rs
>
> diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> index 4bddd023aa7f..bd93140f3094 100644
> --- a/rust/kernel/alloc.rs
> +++ b/rust/kernel/alloc.rs
> @@ -5,6 +5,7 @@
>  #[cfg(not(any(test, testlib)))]
>  pub mod allocator;
>  pub mod kbox;
> +pub mod kvec;
>  pub mod vec_ext;
>
>  #[cfg(any(test, testlib))]
> @@ -18,6 +19,11 @@
>  pub use self::kbox::KVBox;
>  pub use self::kbox::VBox;
>
> +pub use self::kvec::KVVec;
> +pub use self::kvec::KVec;
> +pub use self::kvec::VVec;
> +pub use self::kvec::Vec;
> +
>  /// Indicates an allocation error.
>  #[derive(Copy, Clone, PartialEq, Eq, Debug)]
>  pub struct AllocError;
> diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
> index 7074f00e07bc..39feaed4a8f8 100644
> --- a/rust/kernel/alloc/kbox.rs
> +++ b/rust/kernel/alloc/kbox.rs
> @@ -2,7 +2,7 @@
>
>  //! Implementation of [`Box`].
>
> -use super::{AllocError, Allocator, Flags};
> +use super::{AllocError, Allocator, Flags, Vec};
>  use core::fmt;
>  use core::marker::PhantomData;
>  use core::mem::ManuallyDrop;
> @@ -169,6 +169,20 @@ pub fn into_pin(b: Self) -> Pin<Self>
>      }
>  }
>
> +impl<T, A, const N: usize> Box<[T; N], A>
> +where
> +    A: Allocator,
> +{
> +    /// Convert a `Box<[T], A>` to a `Vec<T, A>`.
> +    pub fn into_vec(b: Self) -> Vec<T, A> {

This doc-comment seems wrong. [T] and [T; N] are not the same thing.

> +        let len = b.len();
> +        unsafe {
> +            let ptr = Self::into_raw(b);
> +            Vec::from_raw_parts(ptr as _, len, len)
> +        }
> +    }
> +}
> +
>  impl<T, A> Box<MaybeUninit<T>, A>
>  where
>      A: Allocator,
> diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> new file mode 100644
> index 000000000000..04cc85f7d92c
> --- /dev/null
> +++ b/rust/kernel/alloc/kvec.rs
> @@ -0,0 +1,583 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Implementation of [`Vec`].
> +
> +use super::{AllocError, Allocator, Flags};
> +use crate::types::Unique;
> +use core::{
> +    fmt,
> +    marker::PhantomData,
> +    mem::{ManuallyDrop, MaybeUninit},
> +    ops::Deref,
> +    ops::DerefMut,
> +    ops::Index,
> +    ops::IndexMut,
> +    slice,
> +    slice::SliceIndex,
> +};
> +
> +/// Create a [`Vec`] containing the arguments.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// let mut v = kernel::kvec![];
> +/// v.push(1, GFP_KERNEL)?;
> +/// assert_eq!(v, [1]);
> +///
> +/// let mut v = kernel::kvec![1; 3]?;
> +/// v.push(4, GFP_KERNEL)?;
> +/// assert_eq!(v, [1, 1, 1, 4]);
> +///
> +/// let mut v = kernel::kvec![1, 2, 3]?;
> +/// v.push(4, GFP_KERNEL)?;
> +/// assert_eq!(v, [1, 2, 3, 4]);
> +///
> +/// # Ok::<(), Error>(())
> +/// ```
> +#[macro_export]
> +macro_rules! kvec {
> +    () => (
> +        {
> +            $crate::alloc::KVec::new()
> +        }
> +    );
> +    ($elem:expr; $n:expr) => (
> +        {
> +            $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL)
> +        }
> +    );
> +    ($($x:expr),+ $(,)?) => (
> +        {
> +            match $crate::alloc::KBox::new([$($x),+], GFP_KERNEL) {
> +                Ok(b) => Ok($crate::alloc::KBox::into_vec(b)),
> +                Err(e) => Err(e),
> +            }
> +        }
> +    );
> +}
> +
> +/// The kernel's [`Vec`] type.
> +///
> +/// A contiguous growable array type with contents allocated with the kernel's allocators (e.g.
> +/// `Kmalloc`, `Vmalloc` or `KVmalloc`, written `Vec<T, A>`.

A closing bracket is missing in this sentence.

> +/// For non-zero-sized values, a [`Vec`] will use the given allocator `A` for its allocation. For
> +/// the most common allocators the type aliases `KVec`, `VVec` and `KVVec` exist.
> +///
> +/// For zero-sized types the [`Vec`]'s pointer must be `dangling_mut::<T>`; no memory is allocated.
> +///
> +/// Generally, [`Vec`] consists of a pointer that represents the vector's backing buffer, the
> +/// capacity of the vector (the number of elements that currently fit into the vector), it's length
> +/// (the number of elements that are currently stored in the vector) and the `Allocator` used to
> +/// allocate (and free) the backing buffer.
> +///
> +/// A [`Vec`] can be deconstructed into and (re-)constructed from it's previously named raw parts
> +/// and manually modified.
> +///
> +/// [`Vec`]'s backing buffer gets, if required, automatically increased (re-allocated) when elements
> +/// are added to the vector.
> +///
> +/// # Invariants
> +///
> +/// The [`Vec`] backing buffer's pointer always properly aligned and either points to memory
> +/// allocated with `A` or, for zero-sized types, is a dangling pointer.
> +///
> +/// The length of the vector always represents the exact number of elements stored in the vector.
> +///
> +/// The capacity of the vector always represents the absolute number of elements that can be stored
> +/// within the vector without re-allocation. However, it is legal for the backing buffer to be
> +/// larger than `size_of<T>` times the capacity.
> +///
> +/// The `Allocator` of the vector is the exact allocator the backing buffer was allocated with (and
> +/// must be freed with).
> +pub struct Vec<T, A: Allocator> {
> +    ptr: Unique<T>,
> +    /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `cap` must be in the `0..=isize::MAX` range.
> +    cap: usize,

This section header should say Invariants, not Safety.

> +    len: usize,
> +    _p: PhantomData<A>,
> +}
> +
> +/// Type alias for `Vec` with a `Kmalloc` allocator.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// let mut v = KVec::new();
> +/// v.push(1, GFP_KERNEL)?;
> +/// assert_eq!(&v, &[1]);
> +///
> +/// # Ok::<(), Error>(())
> +/// ```
> +pub type KVec<T> = Vec<T, super::allocator::Kmalloc>;
> +
> +/// Type alias for `Vec` with a `Vmalloc` allocator.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// let mut v = VVec::new();
> +/// v.push(1, GFP_KERNEL)?;
> +/// assert_eq!(&v, &[1]);
> +///
> +/// # Ok::<(), Error>(())
> +/// ```
> +pub type VVec<T> = Vec<T, super::allocator::Vmalloc>;
> +
> +/// Type alias for `Vec` with a `KVmalloc` allocator.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// let mut v = KVVec::new();
> +/// v.push(1, GFP_KERNEL)?;
> +/// assert_eq!(&v, &[1]);
> +///
> +/// # Ok::<(), Error>(())
> +/// ```
> +pub type KVVec<T> = Vec<T, super::allocator::KVmalloc>;
> +
> +impl<T, A> Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    #[inline]
> +    fn is_zst() -> bool {
> +        core::mem::size_of::<T>() == 0
> +    }
> +
> +    /// Returns the total number of elements the vector can hold without
> +    /// reallocating.
> +    pub fn capacity(&self) -> usize {
> +        if Self::is_zst() {
> +            usize::MAX
> +        } else {
> +            self.cap
> +        }
> +    }

I would consider always storing usize::MAX in the capacity field for zst types?

> +
> +    /// Returns the number of elements in the vector, also referred to
> +    /// as its 'length'.
> +    #[inline]
> +    pub fn len(&self) -> usize {
> +        self.len
> +    }
> +
> +    /// Forces the length of the vector to new_len.
> +    ///
> +    /// # Safety
> +    ///
> +    /// - `new_len` must be less than or equal to [`Self::capacity()`].
> +    /// - The elements at `old_len..new_len` must be initialized.
> +    #[inline]
> +    pub unsafe fn set_len(&mut self, new_len: usize) {
> +        self.len = new_len;
> +    }
> +
> +    /// Extracts a slice containing the entire vector.
> +    ///
> +    /// Equivalent to `&s[..]`.
> +    #[inline]
> +    pub fn as_slice(&self) -> &[T] {
> +        self
> +    }
> +
> +    /// Extracts a mutable slice of the entire vector.
> +    ///
> +    /// Equivalent to `&mut s[..]`.
> +    #[inline]
> +    pub fn as_mut_slice(&mut self) -> &mut [T] {
> +        self
> +    }
> +
> +    /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
> +    /// raw pointer valid for zero sized reads if the vector didn't allocate.
> +    #[inline]
> +    pub fn as_mut_ptr(&self) -> *mut T {
> +        self.ptr.as_ptr()
> +    }
> +
> +    /// Returns a raw pointer to the slice's buffer.
> +    #[inline]
> +    pub fn as_ptr(&self) -> *const T {
> +        self.as_mut_ptr()
> +    }
> +
> +    /// Returns `true` if the vector contains no elements.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let mut v = KVec::new();
> +    /// assert!(v.is_empty());
> +    ///
> +    /// v.push(1, GFP_KERNEL);
> +    /// assert!(!v.is_empty());
> +    /// ```
> +    #[inline]
> +    pub fn is_empty(&self) -> bool {
> +        self.len() == 0
> +    }
> +
> +    /// Constructs a new, empty Vec<T, A>.
> +    ///
> +    /// This method does not allocate by itself.
> +    #[inline]
> +    pub const fn new() -> Self {
> +        Self {
> +            ptr: Unique::dangling(),
> +            cap: 0,
> +            len: 0,
> +            _p: PhantomData::<A>,
> +        }
> +    }
> +
> +    /// Returns the remaining spare capacity of the vector as a slice of `MaybeUninit<T>`.
> +    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
> +        // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated
> +        // and valid, but uninitialized.
> +        unsafe {
> +            slice::from_raw_parts_mut(
> +                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
> +                self.capacity() - self.len,
> +            )
> +        }

Is this correct for ZSTs?

> +    }
> +
> +    /// Appends an element to the back of the [`Vec`] instance.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let mut v = KVec::new();
> +    /// v.push(1, GFP_KERNEL)?;
> +    /// assert_eq!(&v, &[1]);
> +    ///
> +    /// v.push(2, GFP_KERNEL)?;
> +    /// assert_eq!(&v, &[1, 2]);
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> {
> +        Vec::reserve(self, 1, flags)?;
> +        let s = self.spare_capacity_mut();
> +        s[0].write(v);
> +
> +        // SAFETY: We just initialised the first spare entry, so it is safe to increase the length
> +        // by 1. We also know that the new length is <= capacity because of the previous call to
> +        // `reserve` above.
> +        unsafe { self.set_len(self.len() + 1) };
> +        Ok(())
> +    }
> +
> +    /// Creates a new [`Vec`] instance with at least the given capacity.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let v = KVec::<u32>::with_capacity(20, GFP_KERNEL)?;
> +    ///
> +    /// assert!(v.capacity() >= 20);
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    pub fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> {
> +        let mut v = Vec::new();
> +
> +        Self::reserve(&mut v, capacity, flags)?;
> +
> +        Ok(v)
> +    }
> +
> +    /// Pushes clones of the elements of slice into the [`Vec`] instance.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let mut v = KVec::new();
> +    /// v.push(1, GFP_KERNEL)?;
> +    ///
> +    /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?;
> +    /// assert_eq!(&v, &[1, 20, 30, 40]);
> +    ///
> +    /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?;
> +    /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]);
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    pub fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
> +    where
> +        T: Clone,
> +    {
> +        self.reserve(other.len(), flags)?;
> +        for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) {
> +            slot.write(item.clone());
> +        }
> +
> +        // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase
> +        // the length by the same amount. We also know that the new length is <= capacity because
> +        // of the previous call to `reserve` above.
> +        unsafe { self.set_len(self.len() + other.len()) };
> +        Ok(())
> +    }
> +
> +    /// Creates a Vec<T, A> directly from a pointer, a length, a capacity, and an allocator.
> +    ///
> +    /// # Safety
> +    ///
> +    /// This is highly unsafe, due to the number of invariants that aren’t checked:
> +    ///
> +    /// - `ptr` must be currently allocated via the given allocator `A`.
> +    /// - `T` needs to have the same alignment as what `ptr` was allocated with. (`T` having a less
> +    ///   strict alignment is not sufficient, the alignment really needs to be equal to satisfy the
> +    ///   `dealloc` requirement that memory must be allocated and deallocated with the same layout.)
> +    /// - The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs to be
> +    ///   smaller or equal the size the pointer was allocated with.
> +    /// - `length` needs to be less than or equal to `capacity`.
> +    /// - The first `length` values must be properly initialized values of type `T`.
> +    /// - The allocated size in bytes must be no larger than `isize::MAX`. See the safety
> +    ///   documentation of `pointer::offset`.
> +    ///
> +    /// It is also valid to create an empty `Vec` passing a dangling pointer for `ptr` and zero for
> +    /// `cap` and `len`.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let mut v = kernel::kvec![1, 2, 3]?;
> +    /// v.reserve(1, GFP_KERNEL)?;
> +    ///
> +    /// let (mut ptr, mut len, cap) = v.into_raw_parts();
> +    ///
> +    /// // SAFETY: We've just reserved memory for another element.
> +    /// unsafe { ptr.add(len).write(4) };
> +    /// len += 1;
> +    ///
> +    /// // SAFETY: We only wrote an additional element at the end of the `KVec`'s buffer and
> +    /// // correspondingly increased the length of the `KVec` by one. Otherwise, we construct it
> +    /// // from the exact same raw parts.
> +    /// let v = unsafe { KVec::from_raw_parts(ptr, len, cap) };
> +    ///
> +    /// assert_eq!(v, [1, 2, 3, 4]);
> +    ///
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
> +        let cap = if Self::is_zst() { 0 } else { capacity };
> +
> +        Self {
> +            // SAFETY: By the safety requirements, `ptr` is either dangling or pointing to a valid
> +            // memory allocation, allocated with `A`.
> +            ptr: unsafe { Unique::new_unchecked(ptr) },
> +            cap,
> +            len: length,
> +            _p: PhantomData::<A>,
> +        }
> +    }
> +
> +    /// Decomposes a `Vec<T, A>` into its raw components: (`pointer`, `length`, `capacity`).
> +    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
> +        let me = ManuallyDrop::new(self);
> +        let len = me.len();
> +        let capacity = me.capacity();
> +        let ptr = me.as_mut_ptr();
> +        (ptr, len, capacity)
> +    }
> +
> +    /// Ensures that the capacity exceeds the length by at least `additional` elements.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let mut v = KVec::new();
> +    /// v.push(1, GFP_KERNEL)?;
> +    ///
> +    /// v.reserve(10, GFP_KERNEL)?;
> +    /// let cap = v.capacity();
> +    /// assert!(cap >= 10);
> +    ///
> +    /// v.reserve(10, GFP_KERNEL)?;
> +    /// let new_cap = v.capacity();
> +    /// assert_eq!(new_cap, cap);
> +    ///
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> {
> +        let len = self.len();
> +        let cap = self.capacity();
> +
> +        if cap - len >= additional {
> +            return Ok(());
> +        }
> +
> +        if Self::is_zst() {
> +            // The capacity is already `usize::MAX` for SZTs, we can't go higher.
> +            return Err(AllocError);
> +        }
> +
> +        // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size
> +        // is greater than `isize::MAX`. So the multiplication by two won't overflow.

You know it won't overflow because of the type invariants. The thing
about Layout::array should instead be used to argue why setting
self.cap below does not break the invariants.

> +        let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
> +        let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
> +
> +        // We need to make sure that `ptr` is either NULL or comes from a previous call to
> +        // `realloc_flags`. A `Vec<T, A>`'s `ptr` value is not guaranteed to be NULL and might be
> +        // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T, A>`'s
> +        // capacity to be zero if no memory has been allocated yet.
> +        let ptr = if cap == 0 {
> +            None
> +        } else {
> +            Some(self.ptr.as_non_null().cast())
> +        };
> +
> +        // SAFETY: `ptr` is valid because it's either `None` or comes from a previous call to
> +        // `A::realloc`. We also verified that the type is not a ZST.
> +        let ptr = unsafe { A::realloc(ptr, layout, flags)? };
> +
> +        self.ptr = ptr.cast().into();
> +        self.cap = new_cap;
> +
> +        Ok(())
> +    }
> +}
> +
> +impl<T: Clone, A: Allocator> Vec<T, A> {
> +    /// Extend the vector by `n` clones of value.
> +    pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> {
> +        self.reserve(n, flags)?;
> +
> +        let spare = self.spare_capacity_mut();
> +
> +        for i in 0..spare.len() - 1 {
> +            spare[i].write(value.clone());
> +        }

Minus one? Shouldn't this instead loop for `0..n`?

> +
> +        // We can write the last element directly without cloning needlessly
> +        spare[spare.len() - 1].write(value);

spare[n-1].write(value);

> +
> +        // SAFETY: `self.reserve` not bailing out with an error guarantees that we're not
> +        // exceeding the capacity of this `Vec`.
> +        unsafe { self.set_len(self.len() + n) };
> +
> +        Ok(())
> +    }
> +
> +    /// Create a new `Vec<T, A> and extend it by `n` clones of `value`.
> +    pub fn from_elem(value: T, n: usize, flags: Flags) -> Result<Self, AllocError> {
> +        let mut v = Self::with_capacity(n, flags)?;
> +
> +        v.extend_with(n, value, flags)?;
> +
> +        Ok(v)
> +    }
> +}
> +
> +impl<T, A> Drop for Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    fn drop(&mut self) {
> +        // SAFETY: We need to drop the vector's elements in place, before we free the backing
> +        // memory.
> +        unsafe {
> +            core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
> +                self.as_mut_ptr(),
> +                self.len,
> +            ))
> +        };
> +
> +        // If `cap == 0` we never allocated any memory in the first place.
> +        if self.cap != 0 {
> +            // SAFETY: `self.ptr` was previously allocated with `A`.
> +            unsafe { A::free(self.ptr.as_non_null().cast()) };

Do you need a ZST check here?

> +        }
> +    }
> +}
> +
> +impl<T> Default for KVec<T> {
> +    #[inline]
> +    fn default() -> Self {
> +        Self::new()
> +    }
> +}
> +
> +impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
> +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> +        fmt::Debug::fmt(&**self, f)
> +    }
> +}
> +
> +impl<T, A> Deref for Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    type Target = [T];
> +
> +    #[inline]
> +    fn deref(&self) -> &[T] {
> +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> +        // initialized elements of type `T`.
> +        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
> +    }
> +}
> +
> +impl<T, A> DerefMut for Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    #[inline]
> +    fn deref_mut(&mut self) -> &mut [T] {
> +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> +        // initialized elements of type `T`.
> +        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
> +    }
> +}
> +
> +impl<T: Eq, A> Eq for Vec<T, A> where A: Allocator {}
> +
> +impl<T, I: SliceIndex<[T]>, A> Index<I> for Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    type Output = I::Output;
> +
> +    #[inline]
> +    fn index(&self, index: I) -> &Self::Output {
> +        Index::index(&**self, index)
> +    }
> +}
> +
> +impl<T, I: SliceIndex<[T]>, A> IndexMut<I> for Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    #[inline]
> +    fn index_mut(&mut self, index: I) -> &mut Self::Output {
> +        IndexMut::index_mut(&mut **self, index)
> +    }
> +}
> +
> +macro_rules! __impl_slice_eq {
> +    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
> +        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
> +        where
> +            T: PartialEq<U>,
> +            $($ty: $bound)?
> +        {
> +            #[inline]
> +            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
> +        }
> +    }
> +}
> +
> +__impl_slice_eq! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> }
> +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &[U] }
> +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &mut [U] }
> +__impl_slice_eq! { [A: Allocator] &[T], Vec<U, A> }
> +__impl_slice_eq! { [A: Allocator] &mut [T], Vec<U, A> }
> +__impl_slice_eq! { [A: Allocator] Vec<T, A>, [U] }
> +__impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
> +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
> +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
> diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> index 6bf77577eae7..bb80a43d20fb 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -14,7 +14,7 @@
>  #[doc(no_inline)]
>  pub use core::pin::Pin;
>
> -pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox};
> +pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
>
>  #[doc(no_inline)]
>  pub use alloc::vec::Vec;
> --
> 2.45.2
>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec`
  2024-08-01  0:02 ` [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
@ 2024-08-01 15:07   ` Alice Ryhl
  2024-08-01 15:30     ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 15:07 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Implement `IntoIterator` for `Vec`, `Vec`'s `IntoIter` type, as well as
> `Iterator` for `IntoIter`.
>
> `Vec::into_iter` disassembles the `Vec` into its raw parts; additionally,
> `IntoIter` keeps track of a separate pointer, which is incremented
> correspondingsly as the iterator advances, while the length, or the count
> of elements, is decremented.
>
> This also means that `IntoIter` takes the ownership of the backing
> buffer and is responsible to drop the remaining elements and free the
> backing buffer, if it's dropped.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/alloc.rs      |   1 +
>  rust/kernel/alloc/kvec.rs | 186 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 187 insertions(+)
>
> diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> index bd93140f3094..f2998ad57456 100644
> --- a/rust/kernel/alloc.rs
> +++ b/rust/kernel/alloc.rs
> @@ -19,6 +19,7 @@
>  pub use self::kbox::KVBox;
>  pub use self::kbox::VBox;
>
> +pub use self::kvec::IntoIter;
>  pub use self::kvec::KVVec;
>  pub use self::kvec::KVec;
>  pub use self::kvec::VVec;
> diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> index 04cc85f7d92c..50e7705e5686 100644
> --- a/rust/kernel/alloc/kvec.rs
> +++ b/rust/kernel/alloc/kvec.rs
> @@ -12,6 +12,8 @@
>      ops::DerefMut,
>      ops::Index,
>      ops::IndexMut,
> +    ptr,
> +    ptr::NonNull,
>      slice,
>      slice::SliceIndex,
>  };
> @@ -581,3 +583,187 @@ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
>  __impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
>  __impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
>  __impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
> +
> +impl<'a, T, A> IntoIterator for &'a Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    type Item = &'a T;
> +    type IntoIter = slice::Iter<'a, T>;
> +
> +    fn into_iter(self) -> Self::IntoIter {
> +        self.iter()
> +    }
> +}
> +
> +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    type Item = &'a mut T;
> +    type IntoIter = slice::IterMut<'a, T>;
> +
> +    fn into_iter(self) -> Self::IntoIter {
> +        self.iter_mut()
> +    }
> +}
> +
> +/// An iterator that moves out of a vector.
> +///
> +/// This `struct` is created by the `into_iter` method on [`Vec`] (provided by the [`IntoIterator`]
> +/// trait).
> +///
> +/// # Examples
> +///
> +/// ```
> +/// let v = kernel::kvec![0, 1, 2]?;
> +/// let iter = v.into_iter();
> +///
> +/// # Ok::<(), Error>(())
> +/// ```
> +pub struct IntoIter<T, A: Allocator> {
> +    ptr: *mut T,
> +    buf: NonNull<T>,
> +    len: usize,
> +    cap: usize,
> +    _p: PhantomData<A>,
> +}
> +
> +impl<T, A> IntoIter<T, A>
> +where
> +    A: Allocator,
> +{
> +    fn as_raw_mut_slice(&mut self) -> *mut [T] {
> +        ptr::slice_from_raw_parts_mut(self.ptr, self.len)
> +    }
> +}
> +
> +impl<T, A> Iterator for IntoIter<T, A>
> +where
> +    A: Allocator,
> +{
> +    type Item = T;
> +
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let v = kernel::kvec![1, 2, 3]?;
> +    /// let mut it = v.into_iter();
> +    ///
> +    /// assert_eq!(it.next(), Some(1));
> +    /// assert_eq!(it.next(), Some(2));
> +    /// assert_eq!(it.next(), Some(3));
> +    /// assert_eq!(it.next(), None);
> +    ///
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    fn next(&mut self) -> Option<T> {
> +        if self.len == 0 {
> +            return None;
> +        }
> +
> +        let ptr = self.ptr;
> +        if !Vec::<T, A>::is_zst() {
> +            // SAFETY: We can't overflow; `end` is guaranteed to mark the end of the buffer.
> +            unsafe { self.ptr = self.ptr.add(1) };
> +        } else {
> +            // For ZST `ptr` has to stay where it is to remain aligned, so we just reduce `self.len`
> +            // by 1.
> +        }
> +        self.len -= 1;
> +
> +        // SAFETY: `ptr` is guaranteed to point at a valid element within the buffer.
> +        Some(unsafe { ptr.read() })
> +    }
> +
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let v: KVec<u32> = kernel::kvec![1, 2, 3]?;
> +    /// let mut iter = v.into_iter();
> +    /// let size = iter.size_hint().0;
> +    ///
> +    /// iter.next();
> +    /// assert_eq!(iter.size_hint().0, size - 1);
> +    ///
> +    /// iter.next();
> +    /// assert_eq!(iter.size_hint().0, size - 2);
> +    ///
> +    /// iter.next();
> +    /// assert_eq!(iter.size_hint().0, size - 3);
> +    ///
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    fn size_hint(&self) -> (usize, Option<usize>) {
> +        (self.len, Some(self.len))
> +    }
> +}
> +
> +impl<T, A> Drop for IntoIter<T, A>
> +where
> +    A: Allocator,
> +{
> +    fn drop(&mut self) {
> +        // SAFETY: Drop the remaining vector's elements in place, before we free the backing
> +        // memory.
> +        unsafe { ptr::drop_in_place(self.as_raw_mut_slice()) };
> +
> +        // If `cap == 0` we never allocated any memory in the first place.
> +        if self.cap != 0 {
> +            // SAFETY: `self.buf` was previously allocated with `A`.
> +            unsafe { A::free(self.buf.cast()) };
> +        }

Is this ok for ZST?

> +    }
> +}
> +
> +impl<T, A> IntoIterator for Vec<T, A>
> +where
> +    A: Allocator,
> +{
> +    type Item = T;
> +    type IntoIter = IntoIter<T, A>;
> +
> +    /// Creates a consuming iterator, that is, one that moves each value out of
> +    /// the vector (from start to end). The vector cannot be used after calling
> +    /// this.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let v = kernel::kvec![1, 2]?;
> +    /// let mut v_iter = v.into_iter();
> +    ///
> +    /// let first_element: Option<u32> = v_iter.next();
> +    ///
> +    /// assert_eq!(first_element, Some(1));
> +    /// assert_eq!(v_iter.next(), Some(2));
> +    /// assert_eq!(v_iter.next(), None);
> +    ///
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    ///
> +    /// ```
> +    /// let v = kernel::kvec![];
> +    /// let mut v_iter = v.into_iter();
> +    ///
> +    /// let first_element: Option<u32> = v_iter.next();
> +    ///
> +    /// assert_eq!(first_element, None);
> +    ///
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    #[inline]
> +    fn into_iter(self) -> Self::IntoIter {
> +        let (ptr, len, cap) = self.into_raw_parts();
> +
> +        IntoIter {
> +            ptr,
> +            // SAFETY: `ptr` is either a dangling pointer or a pointer to a valid memory
> +            // allocation, allocated with `A`.
> +            buf: unsafe { NonNull::new_unchecked(ptr) },
> +            len,
> +            cap,
> +            _p: PhantomData::<A>,
> +        }
> +    }
> +}
> --
> 2.45.2
>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 01/25] rust: alloc: add `Allocator` trait
  2024-08-01 14:25       ` Alice Ryhl
@ 2024-08-01 15:09         ` Danilo Krummrich
  0 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 15:09 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 04:25:25PM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:27 PM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > On Thu, Aug 01, 2024 at 10:19:41AM +0200, Alice Ryhl wrote:
> > > On Thu, Aug 1, 2024 at 2:07 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > > +    /// Free an existing memory allocation.
> > > > +    ///
> > > > +    /// # Safety
> > > > +    ///
> > > > +    /// `ptr` must point to an existing and valid memory allocation created by this `Allocator`
> > > > +    /// instance.
> > > > +    unsafe fn free(ptr: NonNull<u8>) {
> > > > +        // SAFETY: `ptr` is guaranteed to be previously allocated with this `Allocator` or NULL.
> > > > +        // Calling `realloc` with a buffer size of zero, frees the buffer `ptr` points to.
> > > > +        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
> > > > +    }
> > >
> > > At the very least, the provided implementation of `free` changes the
> > > alignment when it calls `realloc`.
> >
> > Yes, I think that's fine though. Hopefully no one attempts to use the memory
> > anymore once `free` is being called.
> 
> Sure, but if you require the alignment to remain constant throughout
> calls to realloc, then you have to word it in a way that allows a
> different alignment when the new size is zero.

Agreed, this case should be covered once I documented that the new alignment
must be equal to or smaller than the old alignment.

> 
> Alice
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter`
  2024-08-01  0:02 ` [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
@ 2024-08-01 15:10   ` Alice Ryhl
  2024-08-01 15:37     ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 15:10 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> Currently, we can't implement `FromIterator`. There are a couple of
> issues with this trait in the kernel, namely:
>
>   - Rust's specialization feature is unstable. This prevents us to
>     optimze for the special case where `I::IntoIter` equals `Vec`'s
>     `IntoIter` type.
>   - We also can't use `I::IntoIter`'s type ID either to work around this,
>     since `FromIterator` doesn't require this type to be `'static`.
>   - `FromIterator::from_iter` does return `Self` instead of
>     `Result<Self, AllocError>`, hence we can't properly handle allocation
>     failures.
>   - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle
>     additional allocation flags.
>
> Instead, provide `IntoIter::collect`, such that we can at least convert
> `IntoIter` into a `Vec` again.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

I'm not convinced a collect implementation specific to IntoIter is necessary?

> +
> +        // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be
> +        // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves
> +        // it as it is.
> +        ptr = match unsafe { A::realloc(Some(buf.cast()), layout, flags) } {

Why would you shrink it? You can just keep the capacity.

Alice


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type
  2024-08-01 15:05   ` Alice Ryhl
@ 2024-08-01 15:27     ` Danilo Krummrich
  2024-08-01 15:31       ` Alice Ryhl
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 15:27 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 05:05:41PM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > `Vec` provides a contiguous growable array type (such as `Vec`) with
> > contents allocated with the kernel's allocators (e.g. `Kmalloc`,
> > `Vmalloc` or `KVmalloc`).
> >
> > In contrast to Rust's `Vec` type, the kernel `Vec` type considers the
> > kernel's GFP flags for all appropriate functions, always reports
> > allocation failures through `Result<_, AllocError>` and remains
> > independent from unstable features.
> >
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > ---
> >  rust/kernel/alloc.rs      |   6 +
> >  rust/kernel/alloc/kbox.rs |  16 +-
> >  rust/kernel/alloc/kvec.rs | 583 ++++++++++++++++++++++++++++++++++++++
> >  rust/kernel/prelude.rs    |   2 +-
> >  4 files changed, 605 insertions(+), 2 deletions(-)
> >  create mode 100644 rust/kernel/alloc/kvec.rs
> >
> > diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> > index 4bddd023aa7f..bd93140f3094 100644
> > --- a/rust/kernel/alloc.rs
> > +++ b/rust/kernel/alloc.rs
> > @@ -5,6 +5,7 @@
> >  #[cfg(not(any(test, testlib)))]
> >  pub mod allocator;
> >  pub mod kbox;
> > +pub mod kvec;
> >  pub mod vec_ext;
> >
> >  #[cfg(any(test, testlib))]
> > @@ -18,6 +19,11 @@
> >  pub use self::kbox::KVBox;
> >  pub use self::kbox::VBox;
> >
> > +pub use self::kvec::KVVec;
> > +pub use self::kvec::KVec;
> > +pub use self::kvec::VVec;
> > +pub use self::kvec::Vec;
> > +
> >  /// Indicates an allocation error.
> >  #[derive(Copy, Clone, PartialEq, Eq, Debug)]
> >  pub struct AllocError;
> > diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
> > index 7074f00e07bc..39feaed4a8f8 100644
> > --- a/rust/kernel/alloc/kbox.rs
> > +++ b/rust/kernel/alloc/kbox.rs
> > @@ -2,7 +2,7 @@
> >
> >  //! Implementation of [`Box`].
> >
> > -use super::{AllocError, Allocator, Flags};
> > +use super::{AllocError, Allocator, Flags, Vec};
> >  use core::fmt;
> >  use core::marker::PhantomData;
> >  use core::mem::ManuallyDrop;
> > @@ -169,6 +169,20 @@ pub fn into_pin(b: Self) -> Pin<Self>
> >      }
> >  }
> >
> > +impl<T, A, const N: usize> Box<[T; N], A>
> > +where
> > +    A: Allocator,
> > +{
> > +    /// Convert a `Box<[T], A>` to a `Vec<T, A>`.
> > +    pub fn into_vec(b: Self) -> Vec<T, A> {
> 
> This doc-comment seems wrong. [T] and [T; N] are not the same thing.

Indeed, gonna fix.

> 
> > +        let len = b.len();
> > +        unsafe {
> > +            let ptr = Self::into_raw(b);
> > +            Vec::from_raw_parts(ptr as _, len, len)
> > +        }
> > +    }
> > +}
> > +
> >  impl<T, A> Box<MaybeUninit<T>, A>
> >  where
> >      A: Allocator,
> > diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> > new file mode 100644
> > index 000000000000..04cc85f7d92c
> > --- /dev/null
> > +++ b/rust/kernel/alloc/kvec.rs
> > @@ -0,0 +1,583 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +//! Implementation of [`Vec`].
> > +
> > +use super::{AllocError, Allocator, Flags};
> > +use crate::types::Unique;
> > +use core::{
> > +    fmt,
> > +    marker::PhantomData,
> > +    mem::{ManuallyDrop, MaybeUninit},
> > +    ops::Deref,
> > +    ops::DerefMut,
> > +    ops::Index,
> > +    ops::IndexMut,
> > +    slice,
> > +    slice::SliceIndex,
> > +};
> > +
> > +/// Create a [`Vec`] containing the arguments.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// let mut v = kernel::kvec![];
> > +/// v.push(1, GFP_KERNEL)?;
> > +/// assert_eq!(v, [1]);
> > +///
> > +/// let mut v = kernel::kvec![1; 3]?;
> > +/// v.push(4, GFP_KERNEL)?;
> > +/// assert_eq!(v, [1, 1, 1, 4]);
> > +///
> > +/// let mut v = kernel::kvec![1, 2, 3]?;
> > +/// v.push(4, GFP_KERNEL)?;
> > +/// assert_eq!(v, [1, 2, 3, 4]);
> > +///
> > +/// # Ok::<(), Error>(())
> > +/// ```
> > +#[macro_export]
> > +macro_rules! kvec {
> > +    () => (
> > +        {
> > +            $crate::alloc::KVec::new()
> > +        }
> > +    );
> > +    ($elem:expr; $n:expr) => (
> > +        {
> > +            $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL)
> > +        }
> > +    );
> > +    ($($x:expr),+ $(,)?) => (
> > +        {
> > +            match $crate::alloc::KBox::new([$($x),+], GFP_KERNEL) {
> > +                Ok(b) => Ok($crate::alloc::KBox::into_vec(b)),
> > +                Err(e) => Err(e),
> > +            }
> > +        }
> > +    );
> > +}
> > +
> > +/// The kernel's [`Vec`] type.
> > +///
> > +/// A contiguous growable array type with contents allocated with the kernel's allocators (e.g.
> > +/// `Kmalloc`, `Vmalloc` or `KVmalloc`, written `Vec<T, A>`.
> 
> A closing bracket is missing in this sentence.

Gonna fix.

> 
> > +/// For non-zero-sized values, a [`Vec`] will use the given allocator `A` for its allocation. For
> > +/// the most common allocators the type aliases `KVec`, `VVec` and `KVVec` exist.
> > +///
> > +/// For zero-sized types the [`Vec`]'s pointer must be `dangling_mut::<T>`; no memory is allocated.
> > +///
> > +/// Generally, [`Vec`] consists of a pointer that represents the vector's backing buffer, the
> > +/// capacity of the vector (the number of elements that currently fit into the vector), it's length
> > +/// (the number of elements that are currently stored in the vector) and the `Allocator` used to
> > +/// allocate (and free) the backing buffer.
> > +///
> > +/// A [`Vec`] can be deconstructed into and (re-)constructed from it's previously named raw parts
> > +/// and manually modified.
> > +///
> > +/// [`Vec`]'s backing buffer gets, if required, automatically increased (re-allocated) when elements
> > +/// are added to the vector.
> > +///
> > +/// # Invariants
> > +///
> > +/// The [`Vec`] backing buffer's pointer always properly aligned and either points to memory
> > +/// allocated with `A` or, for zero-sized types, is a dangling pointer.
> > +///
> > +/// The length of the vector always represents the exact number of elements stored in the vector.
> > +///
> > +/// The capacity of the vector always represents the absolute number of elements that can be stored
> > +/// within the vector without re-allocation. However, it is legal for the backing buffer to be
> > +/// larger than `size_of<T>` times the capacity.
> > +///
> > +/// The `Allocator` of the vector is the exact allocator the backing buffer was allocated with (and
> > +/// must be freed with).
> > +pub struct Vec<T, A: Allocator> {
> > +    ptr: Unique<T>,
> > +    /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// `cap` must be in the `0..=isize::MAX` range.
> > +    cap: usize,
> 
> This section header should say Invariants, not Safety.

Agreed.

> 
> > +    len: usize,
> > +    _p: PhantomData<A>,
> > +}
> > +
> > +/// Type alias for `Vec` with a `Kmalloc` allocator.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// let mut v = KVec::new();
> > +/// v.push(1, GFP_KERNEL)?;
> > +/// assert_eq!(&v, &[1]);
> > +///
> > +/// # Ok::<(), Error>(())
> > +/// ```
> > +pub type KVec<T> = Vec<T, super::allocator::Kmalloc>;
> > +
> > +/// Type alias for `Vec` with a `Vmalloc` allocator.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// let mut v = VVec::new();
> > +/// v.push(1, GFP_KERNEL)?;
> > +/// assert_eq!(&v, &[1]);
> > +///
> > +/// # Ok::<(), Error>(())
> > +/// ```
> > +pub type VVec<T> = Vec<T, super::allocator::Vmalloc>;
> > +
> > +/// Type alias for `Vec` with a `KVmalloc` allocator.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// let mut v = KVVec::new();
> > +/// v.push(1, GFP_KERNEL)?;
> > +/// assert_eq!(&v, &[1]);
> > +///
> > +/// # Ok::<(), Error>(())
> > +/// ```
> > +pub type KVVec<T> = Vec<T, super::allocator::KVmalloc>;
> > +
> > +impl<T, A> Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    #[inline]
> > +    fn is_zst() -> bool {
> > +        core::mem::size_of::<T>() == 0
> > +    }
> > +
> > +    /// Returns the total number of elements the vector can hold without
> > +    /// reallocating.
> > +    pub fn capacity(&self) -> usize {
> > +        if Self::is_zst() {
> > +            usize::MAX
> > +        } else {
> > +            self.cap
> > +        }
> > +    }
> 
> I would consider always storing usize::MAX in the capacity field for zst types?

This wouldn't work. `self.cap` is supposed to represent the actual capacity of
the vector, which for ZSTs is zero.

> 
> > +
> > +    /// Returns the number of elements in the vector, also referred to
> > +    /// as its 'length'.
> > +    #[inline]
> > +    pub fn len(&self) -> usize {
> > +        self.len
> > +    }
> > +
> > +    /// Forces the length of the vector to new_len.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// - `new_len` must be less than or equal to [`Self::capacity()`].
> > +    /// - The elements at `old_len..new_len` must be initialized.
> > +    #[inline]
> > +    pub unsafe fn set_len(&mut self, new_len: usize) {
> > +        self.len = new_len;
> > +    }
> > +
> > +    /// Extracts a slice containing the entire vector.
> > +    ///
> > +    /// Equivalent to `&s[..]`.
> > +    #[inline]
> > +    pub fn as_slice(&self) -> &[T] {
> > +        self
> > +    }
> > +
> > +    /// Extracts a mutable slice of the entire vector.
> > +    ///
> > +    /// Equivalent to `&mut s[..]`.
> > +    #[inline]
> > +    pub fn as_mut_slice(&mut self) -> &mut [T] {
> > +        self
> > +    }
> > +
> > +    /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
> > +    /// raw pointer valid for zero sized reads if the vector didn't allocate.
> > +    #[inline]
> > +    pub fn as_mut_ptr(&self) -> *mut T {
> > +        self.ptr.as_ptr()
> > +    }
> > +
> > +    /// Returns a raw pointer to the slice's buffer.
> > +    #[inline]
> > +    pub fn as_ptr(&self) -> *const T {
> > +        self.as_mut_ptr()
> > +    }
> > +
> > +    /// Returns `true` if the vector contains no elements.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let mut v = KVec::new();
> > +    /// assert!(v.is_empty());
> > +    ///
> > +    /// v.push(1, GFP_KERNEL);
> > +    /// assert!(!v.is_empty());
> > +    /// ```
> > +    #[inline]
> > +    pub fn is_empty(&self) -> bool {
> > +        self.len() == 0
> > +    }
> > +
> > +    /// Constructs a new, empty Vec<T, A>.
> > +    ///
> > +    /// This method does not allocate by itself.
> > +    #[inline]
> > +    pub const fn new() -> Self {
> > +        Self {
> > +            ptr: Unique::dangling(),
> > +            cap: 0,
> > +            len: 0,
> > +            _p: PhantomData::<A>,
> > +        }
> > +    }
> > +
> > +    /// Returns the remaining spare capacity of the vector as a slice of `MaybeUninit<T>`.
> > +    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
> > +        // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated
> > +        // and valid, but uninitialized.
> > +        unsafe {
> > +            slice::from_raw_parts_mut(
> > +                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
> > +                self.capacity() - self.len,
> > +            )
> > +        }
> 
> Is this correct for ZSTs?

Yes, it gives us a slice of ZSTs with the maximum possible length usize::MAX.

> 
> > +    }
> > +
> > +    /// Appends an element to the back of the [`Vec`] instance.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let mut v = KVec::new();
> > +    /// v.push(1, GFP_KERNEL)?;
> > +    /// assert_eq!(&v, &[1]);
> > +    ///
> > +    /// v.push(2, GFP_KERNEL)?;
> > +    /// assert_eq!(&v, &[1, 2]);
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> {
> > +        Vec::reserve(self, 1, flags)?;
> > +        let s = self.spare_capacity_mut();
> > +        s[0].write(v);
> > +
> > +        // SAFETY: We just initialised the first spare entry, so it is safe to increase the length
> > +        // by 1. We also know that the new length is <= capacity because of the previous call to
> > +        // `reserve` above.
> > +        unsafe { self.set_len(self.len() + 1) };
> > +        Ok(())
> > +    }
> > +
> > +    /// Creates a new [`Vec`] instance with at least the given capacity.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let v = KVec::<u32>::with_capacity(20, GFP_KERNEL)?;
> > +    ///
> > +    /// assert!(v.capacity() >= 20);
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    pub fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> {
> > +        let mut v = Vec::new();
> > +
> > +        Self::reserve(&mut v, capacity, flags)?;
> > +
> > +        Ok(v)
> > +    }
> > +
> > +    /// Pushes clones of the elements of slice into the [`Vec`] instance.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let mut v = KVec::new();
> > +    /// v.push(1, GFP_KERNEL)?;
> > +    ///
> > +    /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?;
> > +    /// assert_eq!(&v, &[1, 20, 30, 40]);
> > +    ///
> > +    /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?;
> > +    /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]);
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    pub fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
> > +    where
> > +        T: Clone,
> > +    {
> > +        self.reserve(other.len(), flags)?;
> > +        for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) {
> > +            slot.write(item.clone());
> > +        }
> > +
> > +        // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase
> > +        // the length by the same amount. We also know that the new length is <= capacity because
> > +        // of the previous call to `reserve` above.
> > +        unsafe { self.set_len(self.len() + other.len()) };
> > +        Ok(())
> > +    }
> > +
> > +    /// Creates a Vec<T, A> directly from a pointer, a length, a capacity, and an allocator.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// This is highly unsafe, due to the number of invariants that aren’t checked:
> > +    ///
> > +    /// - `ptr` must be currently allocated via the given allocator `A`.
> > +    /// - `T` needs to have the same alignment as what `ptr` was allocated with. (`T` having a less
> > +    ///   strict alignment is not sufficient, the alignment really needs to be equal to satisfy the
> > +    ///   `dealloc` requirement that memory must be allocated and deallocated with the same layout.)
> > +    /// - The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs to be
> > +    ///   smaller or equal the size the pointer was allocated with.
> > +    /// - `length` needs to be less than or equal to `capacity`.
> > +    /// - The first `length` values must be properly initialized values of type `T`.
> > +    /// - The allocated size in bytes must be no larger than `isize::MAX`. See the safety
> > +    ///   documentation of `pointer::offset`.
> > +    ///
> > +    /// It is also valid to create an empty `Vec` passing a dangling pointer for `ptr` and zero for
> > +    /// `cap` and `len`.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let mut v = kernel::kvec![1, 2, 3]?;
> > +    /// v.reserve(1, GFP_KERNEL)?;
> > +    ///
> > +    /// let (mut ptr, mut len, cap) = v.into_raw_parts();
> > +    ///
> > +    /// // SAFETY: We've just reserved memory for another element.
> > +    /// unsafe { ptr.add(len).write(4) };
> > +    /// len += 1;
> > +    ///
> > +    /// // SAFETY: We only wrote an additional element at the end of the `KVec`'s buffer and
> > +    /// // correspondingly increased the length of the `KVec` by one. Otherwise, we construct it
> > +    /// // from the exact same raw parts.
> > +    /// let v = unsafe { KVec::from_raw_parts(ptr, len, cap) };
> > +    ///
> > +    /// assert_eq!(v, [1, 2, 3, 4]);
> > +    ///
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
> > +        let cap = if Self::is_zst() { 0 } else { capacity };
> > +
> > +        Self {
> > +            // SAFETY: By the safety requirements, `ptr` is either dangling or pointing to a valid
> > +            // memory allocation, allocated with `A`.
> > +            ptr: unsafe { Unique::new_unchecked(ptr) },
> > +            cap,
> > +            len: length,
> > +            _p: PhantomData::<A>,
> > +        }
> > +    }
> > +
> > +    /// Decomposes a `Vec<T, A>` into its raw components: (`pointer`, `length`, `capacity`).
> > +    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
> > +        let me = ManuallyDrop::new(self);
> > +        let len = me.len();
> > +        let capacity = me.capacity();
> > +        let ptr = me.as_mut_ptr();
> > +        (ptr, len, capacity)
> > +    }
> > +
> > +    /// Ensures that the capacity exceeds the length by at least `additional` elements.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let mut v = KVec::new();
> > +    /// v.push(1, GFP_KERNEL)?;
> > +    ///
> > +    /// v.reserve(10, GFP_KERNEL)?;
> > +    /// let cap = v.capacity();
> > +    /// assert!(cap >= 10);
> > +    ///
> > +    /// v.reserve(10, GFP_KERNEL)?;
> > +    /// let new_cap = v.capacity();
> > +    /// assert_eq!(new_cap, cap);
> > +    ///
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> {
> > +        let len = self.len();
> > +        let cap = self.capacity();
> > +
> > +        if cap - len >= additional {
> > +            return Ok(());
> > +        }
> > +
> > +        if Self::is_zst() {
> > +            // The capacity is already `usize::MAX` for SZTs, we can't go higher.
> > +            return Err(AllocError);
> > +        }
> > +
> > +        // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size
> > +        // is greater than `isize::MAX`. So the multiplication by two won't overflow.
> 
> You know it won't overflow because of the type invariants. The thing
> about Layout::array should instead be used to argue why setting
> self.cap below does not break the invariants.

Good point, I will reword it.

> 
> > +        let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
> > +        let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
> > +
> > +        // We need to make sure that `ptr` is either NULL or comes from a previous call to
> > +        // `realloc_flags`. A `Vec<T, A>`'s `ptr` value is not guaranteed to be NULL and might be
> > +        // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T, A>`'s
> > +        // capacity to be zero if no memory has been allocated yet.
> > +        let ptr = if cap == 0 {
> > +            None
> > +        } else {
> > +            Some(self.ptr.as_non_null().cast())
> > +        };
> > +
> > +        // SAFETY: `ptr` is valid because it's either `None` or comes from a previous call to
> > +        // `A::realloc`. We also verified that the type is not a ZST.
> > +        let ptr = unsafe { A::realloc(ptr, layout, flags)? };
> > +
> > +        self.ptr = ptr.cast().into();
> > +        self.cap = new_cap;
> > +
> > +        Ok(())
> > +    }
> > +}
> > +
> > +impl<T: Clone, A: Allocator> Vec<T, A> {
> > +    /// Extend the vector by `n` clones of value.
> > +    pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> {
> > +        self.reserve(n, flags)?;
> > +
> > +        let spare = self.spare_capacity_mut();
> > +
> > +        for i in 0..spare.len() - 1 {
> > +            spare[i].write(value.clone());
> > +        }
> 
> Minus one? Shouldn't this instead loop for `0..n`?

We can indeed just use `n` instead of `slice::len` here.

Minus one, because we create clones for the first n - 1 elements and for the
last one we just use the value itself.

> 
> > +
> > +        // We can write the last element directly without cloning needlessly
> > +        spare[spare.len() - 1].write(value);
> 
> spare[n-1].write(value);

Yep, works too.

> 
> > +
> > +        // SAFETY: `self.reserve` not bailing out with an error guarantees that we're not
> > +        // exceeding the capacity of this `Vec`.
> > +        unsafe { self.set_len(self.len() + n) };
> > +
> > +        Ok(())
> > +    }
> > +
> > +    /// Create a new `Vec<T, A> and extend it by `n` clones of `value`.
> > +    pub fn from_elem(value: T, n: usize, flags: Flags) -> Result<Self, AllocError> {
> > +        let mut v = Self::with_capacity(n, flags)?;
> > +
> > +        v.extend_with(n, value, flags)?;
> > +
> > +        Ok(v)
> > +    }
> > +}
> > +
> > +impl<T, A> Drop for Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    fn drop(&mut self) {
> > +        // SAFETY: We need to drop the vector's elements in place, before we free the backing
> > +        // memory.
> > +        unsafe {
> > +            core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
> > +                self.as_mut_ptr(),
> > +                self.len,
> > +            ))
> > +        };
> > +
> > +        // If `cap == 0` we never allocated any memory in the first place.
> > +        if self.cap != 0 {
> > +            // SAFETY: `self.ptr` was previously allocated with `A`.
> > +            unsafe { A::free(self.ptr.as_non_null().cast()) };
> 
> Do you need a ZST check here?

No, for ZST `self.cap` is always zero.

> 
> > +        }
> > +    }
> > +}
> > +
> > +impl<T> Default for KVec<T> {
> > +    #[inline]
> > +    fn default() -> Self {
> > +        Self::new()
> > +    }
> > +}
> > +
> > +impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
> > +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> > +        fmt::Debug::fmt(&**self, f)
> > +    }
> > +}
> > +
> > +impl<T, A> Deref for Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    type Target = [T];
> > +
> > +    #[inline]
> > +    fn deref(&self) -> &[T] {
> > +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> > +        // initialized elements of type `T`.
> > +        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
> > +    }
> > +}
> > +
> > +impl<T, A> DerefMut for Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    #[inline]
> > +    fn deref_mut(&mut self) -> &mut [T] {
> > +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> > +        // initialized elements of type `T`.
> > +        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
> > +    }
> > +}
> > +
> > +impl<T: Eq, A> Eq for Vec<T, A> where A: Allocator {}
> > +
> > +impl<T, I: SliceIndex<[T]>, A> Index<I> for Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    type Output = I::Output;
> > +
> > +    #[inline]
> > +    fn index(&self, index: I) -> &Self::Output {
> > +        Index::index(&**self, index)
> > +    }
> > +}
> > +
> > +impl<T, I: SliceIndex<[T]>, A> IndexMut<I> for Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    #[inline]
> > +    fn index_mut(&mut self, index: I) -> &mut Self::Output {
> > +        IndexMut::index_mut(&mut **self, index)
> > +    }
> > +}
> > +
> > +macro_rules! __impl_slice_eq {
> > +    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
> > +        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
> > +        where
> > +            T: PartialEq<U>,
> > +            $($ty: $bound)?
> > +        {
> > +            #[inline]
> > +            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
> > +        }
> > +    }
> > +}
> > +
> > +__impl_slice_eq! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> }
> > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &[U] }
> > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &mut [U] }
> > +__impl_slice_eq! { [A: Allocator] &[T], Vec<U, A> }
> > +__impl_slice_eq! { [A: Allocator] &mut [T], Vec<U, A> }
> > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, [U] }
> > +__impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
> > +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
> > +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
> > diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> > index 6bf77577eae7..bb80a43d20fb 100644
> > --- a/rust/kernel/prelude.rs
> > +++ b/rust/kernel/prelude.rs
> > @@ -14,7 +14,7 @@
> >  #[doc(no_inline)]
> >  pub use core::pin::Pin;
> >
> > -pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox};
> > +pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
> >
> >  #[doc(no_inline)]
> >  pub use alloc::vec::Vec;
> > --
> > 2.45.2
> >
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec`
  2024-08-01 15:07   ` Alice Ryhl
@ 2024-08-01 15:30     ` Danilo Krummrich
  0 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 15:30 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 05:07:48PM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > Implement `IntoIterator` for `Vec`, `Vec`'s `IntoIter` type, as well as
> > `Iterator` for `IntoIter`.
> >
> > `Vec::into_iter` disassembles the `Vec` into its raw parts; additionally,
> > `IntoIter` keeps track of a separate pointer, which is incremented
> > correspondingsly as the iterator advances, while the length, or the count
> > of elements, is decremented.
> >
> > This also means that `IntoIter` takes the ownership of the backing
> > buffer and is responsible to drop the remaining elements and free the
> > backing buffer, if it's dropped.
> >
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > ---
> >  rust/kernel/alloc.rs      |   1 +
> >  rust/kernel/alloc/kvec.rs | 186 ++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 187 insertions(+)
> >
> > diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> > index bd93140f3094..f2998ad57456 100644
> > --- a/rust/kernel/alloc.rs
> > +++ b/rust/kernel/alloc.rs
> > @@ -19,6 +19,7 @@
> >  pub use self::kbox::KVBox;
> >  pub use self::kbox::VBox;
> >
> > +pub use self::kvec::IntoIter;
> >  pub use self::kvec::KVVec;
> >  pub use self::kvec::KVec;
> >  pub use self::kvec::VVec;
> > diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> > index 04cc85f7d92c..50e7705e5686 100644
> > --- a/rust/kernel/alloc/kvec.rs
> > +++ b/rust/kernel/alloc/kvec.rs
> > @@ -12,6 +12,8 @@
> >      ops::DerefMut,
> >      ops::Index,
> >      ops::IndexMut,
> > +    ptr,
> > +    ptr::NonNull,
> >      slice,
> >      slice::SliceIndex,
> >  };
> > @@ -581,3 +583,187 @@ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
> >  __impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
> >  __impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
> >  __impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
> > +
> > +impl<'a, T, A> IntoIterator for &'a Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    type Item = &'a T;
> > +    type IntoIter = slice::Iter<'a, T>;
> > +
> > +    fn into_iter(self) -> Self::IntoIter {
> > +        self.iter()
> > +    }
> > +}
> > +
> > +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    type Item = &'a mut T;
> > +    type IntoIter = slice::IterMut<'a, T>;
> > +
> > +    fn into_iter(self) -> Self::IntoIter {
> > +        self.iter_mut()
> > +    }
> > +}
> > +
> > +/// An iterator that moves out of a vector.
> > +///
> > +/// This `struct` is created by the `into_iter` method on [`Vec`] (provided by the [`IntoIterator`]
> > +/// trait).
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// let v = kernel::kvec![0, 1, 2]?;
> > +/// let iter = v.into_iter();
> > +///
> > +/// # Ok::<(), Error>(())
> > +/// ```
> > +pub struct IntoIter<T, A: Allocator> {
> > +    ptr: *mut T,
> > +    buf: NonNull<T>,
> > +    len: usize,
> > +    cap: usize,
> > +    _p: PhantomData<A>,
> > +}
> > +
> > +impl<T, A> IntoIter<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    fn as_raw_mut_slice(&mut self) -> *mut [T] {
> > +        ptr::slice_from_raw_parts_mut(self.ptr, self.len)
> > +    }
> > +}
> > +
> > +impl<T, A> Iterator for IntoIter<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    type Item = T;
> > +
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let v = kernel::kvec![1, 2, 3]?;
> > +    /// let mut it = v.into_iter();
> > +    ///
> > +    /// assert_eq!(it.next(), Some(1));
> > +    /// assert_eq!(it.next(), Some(2));
> > +    /// assert_eq!(it.next(), Some(3));
> > +    /// assert_eq!(it.next(), None);
> > +    ///
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    fn next(&mut self) -> Option<T> {
> > +        if self.len == 0 {
> > +            return None;
> > +        }
> > +
> > +        let ptr = self.ptr;
> > +        if !Vec::<T, A>::is_zst() {
> > +            // SAFETY: We can't overflow; `end` is guaranteed to mark the end of the buffer.
> > +            unsafe { self.ptr = self.ptr.add(1) };
> > +        } else {
> > +            // For ZST `ptr` has to stay where it is to remain aligned, so we just reduce `self.len`
> > +            // by 1.
> > +        }
> > +        self.len -= 1;
> > +
> > +        // SAFETY: `ptr` is guaranteed to point at a valid element within the buffer.
> > +        Some(unsafe { ptr.read() })
> > +    }
> > +
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let v: KVec<u32> = kernel::kvec![1, 2, 3]?;
> > +    /// let mut iter = v.into_iter();
> > +    /// let size = iter.size_hint().0;
> > +    ///
> > +    /// iter.next();
> > +    /// assert_eq!(iter.size_hint().0, size - 1);
> > +    ///
> > +    /// iter.next();
> > +    /// assert_eq!(iter.size_hint().0, size - 2);
> > +    ///
> > +    /// iter.next();
> > +    /// assert_eq!(iter.size_hint().0, size - 3);
> > +    ///
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    fn size_hint(&self) -> (usize, Option<usize>) {
> > +        (self.len, Some(self.len))
> > +    }
> > +}
> > +
> > +impl<T, A> Drop for IntoIter<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    fn drop(&mut self) {
> > +        // SAFETY: Drop the remaining vector's elements in place, before we free the backing
> > +        // memory.
> > +        unsafe { ptr::drop_in_place(self.as_raw_mut_slice()) };
> > +
> > +        // If `cap == 0` we never allocated any memory in the first place.
> > +        if self.cap != 0 {
> > +            // SAFETY: `self.buf` was previously allocated with `A`.
> > +            unsafe { A::free(self.buf.cast()) };
> > +        }
> 
> Is this ok for ZST?

Yes, for ZST `self.cap` is always zero.

> 
> > +    }
> > +}
> > +
> > +impl<T, A> IntoIterator for Vec<T, A>
> > +where
> > +    A: Allocator,
> > +{
> > +    type Item = T;
> > +    type IntoIter = IntoIter<T, A>;
> > +
> > +    /// Creates a consuming iterator, that is, one that moves each value out of
> > +    /// the vector (from start to end). The vector cannot be used after calling
> > +    /// this.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// let v = kernel::kvec![1, 2]?;
> > +    /// let mut v_iter = v.into_iter();
> > +    ///
> > +    /// let first_element: Option<u32> = v_iter.next();
> > +    ///
> > +    /// assert_eq!(first_element, Some(1));
> > +    /// assert_eq!(v_iter.next(), Some(2));
> > +    /// assert_eq!(v_iter.next(), None);
> > +    ///
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    ///
> > +    /// ```
> > +    /// let v = kernel::kvec![];
> > +    /// let mut v_iter = v.into_iter();
> > +    ///
> > +    /// let first_element: Option<u32> = v_iter.next();
> > +    ///
> > +    /// assert_eq!(first_element, None);
> > +    ///
> > +    /// # Ok::<(), Error>(())
> > +    /// ```
> > +    #[inline]
> > +    fn into_iter(self) -> Self::IntoIter {
> > +        let (ptr, len, cap) = self.into_raw_parts();
> > +
> > +        IntoIter {
> > +            ptr,
> > +            // SAFETY: `ptr` is either a dangling pointer or a pointer to a valid memory
> > +            // allocation, allocated with `A`.
> > +            buf: unsafe { NonNull::new_unchecked(ptr) },
> > +            len,
> > +            cap,
> > +            _p: PhantomData::<A>,
> > +        }
> > +    }
> > +}
> > --
> > 2.45.2
> >
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type
  2024-08-01 15:27     ` Danilo Krummrich
@ 2024-08-01 15:31       ` Alice Ryhl
  2024-08-01 15:46         ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-01 15:31 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 5:28 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu, Aug 01, 2024 at 05:05:41PM +0200, Alice Ryhl wrote:
> > On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > >
> > > `Vec` provides a contiguous growable array type (such as `Vec`) with
> > > contents allocated with the kernel's allocators (e.g. `Kmalloc`,
> > > `Vmalloc` or `KVmalloc`).
> > >
> > > In contrast to Rust's `Vec` type, the kernel `Vec` type considers the
> > > kernel's GFP flags for all appropriate functions, always reports
> > > allocation failures through `Result<_, AllocError>` and remains
> > > independent from unstable features.
> > >
> > > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > > ---
> > >  rust/kernel/alloc.rs      |   6 +
> > >  rust/kernel/alloc/kbox.rs |  16 +-
> > >  rust/kernel/alloc/kvec.rs | 583 ++++++++++++++++++++++++++++++++++++++
> > >  rust/kernel/prelude.rs    |   2 +-
> > >  4 files changed, 605 insertions(+), 2 deletions(-)
> > >  create mode 100644 rust/kernel/alloc/kvec.rs
> > >
> > > diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> > > index 4bddd023aa7f..bd93140f3094 100644
> > > --- a/rust/kernel/alloc.rs
> > > +++ b/rust/kernel/alloc.rs
> > > @@ -5,6 +5,7 @@
> > >  #[cfg(not(any(test, testlib)))]
> > >  pub mod allocator;
> > >  pub mod kbox;
> > > +pub mod kvec;
> > >  pub mod vec_ext;
> > >
> > >  #[cfg(any(test, testlib))]
> > > @@ -18,6 +19,11 @@
> > >  pub use self::kbox::KVBox;
> > >  pub use self::kbox::VBox;
> > >
> > > +pub use self::kvec::KVVec;
> > > +pub use self::kvec::KVec;
> > > +pub use self::kvec::VVec;
> > > +pub use self::kvec::Vec;
> > > +
> > >  /// Indicates an allocation error.
> > >  #[derive(Copy, Clone, PartialEq, Eq, Debug)]
> > >  pub struct AllocError;
> > > diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
> > > index 7074f00e07bc..39feaed4a8f8 100644
> > > --- a/rust/kernel/alloc/kbox.rs
> > > +++ b/rust/kernel/alloc/kbox.rs
> > > @@ -2,7 +2,7 @@
> > >
> > >  //! Implementation of [`Box`].
> > >
> > > -use super::{AllocError, Allocator, Flags};
> > > +use super::{AllocError, Allocator, Flags, Vec};
> > >  use core::fmt;
> > >  use core::marker::PhantomData;
> > >  use core::mem::ManuallyDrop;
> > > @@ -169,6 +169,20 @@ pub fn into_pin(b: Self) -> Pin<Self>
> > >      }
> > >  }
> > >
> > > +impl<T, A, const N: usize> Box<[T; N], A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    /// Convert a `Box<[T], A>` to a `Vec<T, A>`.
> > > +    pub fn into_vec(b: Self) -> Vec<T, A> {
> >
> > This doc-comment seems wrong. [T] and [T; N] are not the same thing.
>
> Indeed, gonna fix.
>
> >
> > > +        let len = b.len();
> > > +        unsafe {
> > > +            let ptr = Self::into_raw(b);
> > > +            Vec::from_raw_parts(ptr as _, len, len)
> > > +        }
> > > +    }
> > > +}
> > > +
> > >  impl<T, A> Box<MaybeUninit<T>, A>
> > >  where
> > >      A: Allocator,
> > > diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> > > new file mode 100644
> > > index 000000000000..04cc85f7d92c
> > > --- /dev/null
> > > +++ b/rust/kernel/alloc/kvec.rs
> > > @@ -0,0 +1,583 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +
> > > +//! Implementation of [`Vec`].
> > > +
> > > +use super::{AllocError, Allocator, Flags};
> > > +use crate::types::Unique;
> > > +use core::{
> > > +    fmt,
> > > +    marker::PhantomData,
> > > +    mem::{ManuallyDrop, MaybeUninit},
> > > +    ops::Deref,
> > > +    ops::DerefMut,
> > > +    ops::Index,
> > > +    ops::IndexMut,
> > > +    slice,
> > > +    slice::SliceIndex,
> > > +};
> > > +
> > > +/// Create a [`Vec`] containing the arguments.
> > > +///
> > > +/// # Examples
> > > +///
> > > +/// ```
> > > +/// let mut v = kernel::kvec![];
> > > +/// v.push(1, GFP_KERNEL)?;
> > > +/// assert_eq!(v, [1]);
> > > +///
> > > +/// let mut v = kernel::kvec![1; 3]?;
> > > +/// v.push(4, GFP_KERNEL)?;
> > > +/// assert_eq!(v, [1, 1, 1, 4]);
> > > +///
> > > +/// let mut v = kernel::kvec![1, 2, 3]?;
> > > +/// v.push(4, GFP_KERNEL)?;
> > > +/// assert_eq!(v, [1, 2, 3, 4]);
> > > +///
> > > +/// # Ok::<(), Error>(())
> > > +/// ```
> > > +#[macro_export]
> > > +macro_rules! kvec {
> > > +    () => (
> > > +        {
> > > +            $crate::alloc::KVec::new()
> > > +        }
> > > +    );
> > > +    ($elem:expr; $n:expr) => (
> > > +        {
> > > +            $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL)
> > > +        }
> > > +    );
> > > +    ($($x:expr),+ $(,)?) => (
> > > +        {
> > > +            match $crate::alloc::KBox::new([$($x),+], GFP_KERNEL) {
> > > +                Ok(b) => Ok($crate::alloc::KBox::into_vec(b)),
> > > +                Err(e) => Err(e),
> > > +            }
> > > +        }
> > > +    );
> > > +}
> > > +
> > > +/// The kernel's [`Vec`] type.
> > > +///
> > > +/// A contiguous growable array type with contents allocated with the kernel's allocators (e.g.
> > > +/// `Kmalloc`, `Vmalloc` or `KVmalloc`, written `Vec<T, A>`.
> >
> > A closing bracket is missing in this sentence.
>
> Gonna fix.
>
> >
> > > +/// For non-zero-sized values, a [`Vec`] will use the given allocator `A` for its allocation. For
> > > +/// the most common allocators the type aliases `KVec`, `VVec` and `KVVec` exist.
> > > +///
> > > +/// For zero-sized types the [`Vec`]'s pointer must be `dangling_mut::<T>`; no memory is allocated.
> > > +///
> > > +/// Generally, [`Vec`] consists of a pointer that represents the vector's backing buffer, the
> > > +/// capacity of the vector (the number of elements that currently fit into the vector), it's length
> > > +/// (the number of elements that are currently stored in the vector) and the `Allocator` used to
> > > +/// allocate (and free) the backing buffer.
> > > +///
> > > +/// A [`Vec`] can be deconstructed into and (re-)constructed from it's previously named raw parts
> > > +/// and manually modified.
> > > +///
> > > +/// [`Vec`]'s backing buffer gets, if required, automatically increased (re-allocated) when elements
> > > +/// are added to the vector.
> > > +///
> > > +/// # Invariants
> > > +///
> > > +/// The [`Vec`] backing buffer's pointer always properly aligned and either points to memory
> > > +/// allocated with `A` or, for zero-sized types, is a dangling pointer.
> > > +///
> > > +/// The length of the vector always represents the exact number of elements stored in the vector.
> > > +///
> > > +/// The capacity of the vector always represents the absolute number of elements that can be stored
> > > +/// within the vector without re-allocation. However, it is legal for the backing buffer to be
> > > +/// larger than `size_of<T>` times the capacity.
> > > +///
> > > +/// The `Allocator` of the vector is the exact allocator the backing buffer was allocated with (and
> > > +/// must be freed with).
> > > +pub struct Vec<T, A: Allocator> {
> > > +    ptr: Unique<T>,
> > > +    /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
> > > +    ///
> > > +    /// # Safety
> > > +    ///
> > > +    /// `cap` must be in the `0..=isize::MAX` range.
> > > +    cap: usize,
> >
> > This section header should say Invariants, not Safety.
>
> Agreed.
>
> >
> > > +    len: usize,
> > > +    _p: PhantomData<A>,
> > > +}
> > > +
> > > +/// Type alias for `Vec` with a `Kmalloc` allocator.
> > > +///
> > > +/// # Examples
> > > +///
> > > +/// ```
> > > +/// let mut v = KVec::new();
> > > +/// v.push(1, GFP_KERNEL)?;
> > > +/// assert_eq!(&v, &[1]);
> > > +///
> > > +/// # Ok::<(), Error>(())
> > > +/// ```
> > > +pub type KVec<T> = Vec<T, super::allocator::Kmalloc>;
> > > +
> > > +/// Type alias for `Vec` with a `Vmalloc` allocator.
> > > +///
> > > +/// # Examples
> > > +///
> > > +/// ```
> > > +/// let mut v = VVec::new();
> > > +/// v.push(1, GFP_KERNEL)?;
> > > +/// assert_eq!(&v, &[1]);
> > > +///
> > > +/// # Ok::<(), Error>(())
> > > +/// ```
> > > +pub type VVec<T> = Vec<T, super::allocator::Vmalloc>;
> > > +
> > > +/// Type alias for `Vec` with a `KVmalloc` allocator.
> > > +///
> > > +/// # Examples
> > > +///
> > > +/// ```
> > > +/// let mut v = KVVec::new();
> > > +/// v.push(1, GFP_KERNEL)?;
> > > +/// assert_eq!(&v, &[1]);
> > > +///
> > > +/// # Ok::<(), Error>(())
> > > +/// ```
> > > +pub type KVVec<T> = Vec<T, super::allocator::KVmalloc>;
> > > +
> > > +impl<T, A> Vec<T, A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    #[inline]
> > > +    fn is_zst() -> bool {
> > > +        core::mem::size_of::<T>() == 0
> > > +    }
> > > +
> > > +    /// Returns the total number of elements the vector can hold without
> > > +    /// reallocating.
> > > +    pub fn capacity(&self) -> usize {
> > > +        if Self::is_zst() {
> > > +            usize::MAX
> > > +        } else {
> > > +            self.cap
> > > +        }
> > > +    }
> >
> > I would consider always storing usize::MAX in the capacity field for zst types?
>
> This wouldn't work. `self.cap` is supposed to represent the actual capacity of
> the vector, which for ZSTs is zero.

Storing usize::MAX values of a zero-sized type takes up zero bytes,
and your vector has space for zero bytes. Seems sensible to me to use
usize::MAX.

Anyway, it's up to you. I'm ok either way.

> > > +
> > > +    /// Returns the number of elements in the vector, also referred to
> > > +    /// as its 'length'.
> > > +    #[inline]
> > > +    pub fn len(&self) -> usize {
> > > +        self.len
> > > +    }
> > > +
> > > +    /// Forces the length of the vector to new_len.
> > > +    ///
> > > +    /// # Safety
> > > +    ///
> > > +    /// - `new_len` must be less than or equal to [`Self::capacity()`].
> > > +    /// - The elements at `old_len..new_len` must be initialized.
> > > +    #[inline]
> > > +    pub unsafe fn set_len(&mut self, new_len: usize) {
> > > +        self.len = new_len;
> > > +    }
> > > +
> > > +    /// Extracts a slice containing the entire vector.
> > > +    ///
> > > +    /// Equivalent to `&s[..]`.
> > > +    #[inline]
> > > +    pub fn as_slice(&self) -> &[T] {
> > > +        self
> > > +    }
> > > +
> > > +    /// Extracts a mutable slice of the entire vector.
> > > +    ///
> > > +    /// Equivalent to `&mut s[..]`.
> > > +    #[inline]
> > > +    pub fn as_mut_slice(&mut self) -> &mut [T] {
> > > +        self
> > > +    }
> > > +
> > > +    /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
> > > +    /// raw pointer valid for zero sized reads if the vector didn't allocate.
> > > +    #[inline]
> > > +    pub fn as_mut_ptr(&self) -> *mut T {
> > > +        self.ptr.as_ptr()
> > > +    }
> > > +
> > > +    /// Returns a raw pointer to the slice's buffer.
> > > +    #[inline]
> > > +    pub fn as_ptr(&self) -> *const T {
> > > +        self.as_mut_ptr()
> > > +    }
> > > +
> > > +    /// Returns `true` if the vector contains no elements.
> > > +    ///
> > > +    /// # Examples
> > > +    ///
> > > +    /// ```
> > > +    /// let mut v = KVec::new();
> > > +    /// assert!(v.is_empty());
> > > +    ///
> > > +    /// v.push(1, GFP_KERNEL);
> > > +    /// assert!(!v.is_empty());
> > > +    /// ```
> > > +    #[inline]
> > > +    pub fn is_empty(&self) -> bool {
> > > +        self.len() == 0
> > > +    }
> > > +
> > > +    /// Constructs a new, empty Vec<T, A>.
> > > +    ///
> > > +    /// This method does not allocate by itself.
> > > +    #[inline]
> > > +    pub const fn new() -> Self {
> > > +        Self {
> > > +            ptr: Unique::dangling(),
> > > +            cap: 0,
> > > +            len: 0,
> > > +            _p: PhantomData::<A>,
> > > +        }
> > > +    }
> > > +
> > > +    /// Returns the remaining spare capacity of the vector as a slice of `MaybeUninit<T>`.
> > > +    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
> > > +        // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated
> > > +        // and valid, but uninitialized.
> > > +        unsafe {
> > > +            slice::from_raw_parts_mut(
> > > +                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
> > > +                self.capacity() - self.len,
> > > +            )
> > > +        }
> >
> > Is this correct for ZSTs?
>
> Yes, it gives us a slice of ZSTs with the maximum possible length usize::MAX.
>
> >
> > > +    }
> > > +
> > > +    /// Appends an element to the back of the [`Vec`] instance.
> > > +    ///
> > > +    /// # Examples
> > > +    ///
> > > +    /// ```
> > > +    /// let mut v = KVec::new();
> > > +    /// v.push(1, GFP_KERNEL)?;
> > > +    /// assert_eq!(&v, &[1]);
> > > +    ///
> > > +    /// v.push(2, GFP_KERNEL)?;
> > > +    /// assert_eq!(&v, &[1, 2]);
> > > +    /// # Ok::<(), Error>(())
> > > +    /// ```
> > > +    pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> {
> > > +        Vec::reserve(self, 1, flags)?;
> > > +        let s = self.spare_capacity_mut();
> > > +        s[0].write(v);
> > > +
> > > +        // SAFETY: We just initialised the first spare entry, so it is safe to increase the length
> > > +        // by 1. We also know that the new length is <= capacity because of the previous call to
> > > +        // `reserve` above.
> > > +        unsafe { self.set_len(self.len() + 1) };
> > > +        Ok(())
> > > +    }
> > > +
> > > +    /// Creates a new [`Vec`] instance with at least the given capacity.
> > > +    ///
> > > +    /// # Examples
> > > +    ///
> > > +    /// ```
> > > +    /// let v = KVec::<u32>::with_capacity(20, GFP_KERNEL)?;
> > > +    ///
> > > +    /// assert!(v.capacity() >= 20);
> > > +    /// # Ok::<(), Error>(())
> > > +    /// ```
> > > +    pub fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> {
> > > +        let mut v = Vec::new();
> > > +
> > > +        Self::reserve(&mut v, capacity, flags)?;
> > > +
> > > +        Ok(v)
> > > +    }
> > > +
> > > +    /// Pushes clones of the elements of slice into the [`Vec`] instance.
> > > +    ///
> > > +    /// # Examples
> > > +    ///
> > > +    /// ```
> > > +    /// let mut v = KVec::new();
> > > +    /// v.push(1, GFP_KERNEL)?;
> > > +    ///
> > > +    /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?;
> > > +    /// assert_eq!(&v, &[1, 20, 30, 40]);
> > > +    ///
> > > +    /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?;
> > > +    /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]);
> > > +    /// # Ok::<(), Error>(())
> > > +    /// ```
> > > +    pub fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
> > > +    where
> > > +        T: Clone,
> > > +    {
> > > +        self.reserve(other.len(), flags)?;
> > > +        for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) {
> > > +            slot.write(item.clone());
> > > +        }
> > > +
> > > +        // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase
> > > +        // the length by the same amount. We also know that the new length is <= capacity because
> > > +        // of the previous call to `reserve` above.
> > > +        unsafe { self.set_len(self.len() + other.len()) };
> > > +        Ok(())
> > > +    }
> > > +
> > > +    /// Creates a Vec<T, A> directly from a pointer, a length, a capacity, and an allocator.
> > > +    ///
> > > +    /// # Safety
> > > +    ///
> > > +    /// This is highly unsafe, due to the number of invariants that aren’t checked:
> > > +    ///
> > > +    /// - `ptr` must be currently allocated via the given allocator `A`.
> > > +    /// - `T` needs to have the same alignment as what `ptr` was allocated with. (`T` having a less
> > > +    ///   strict alignment is not sufficient, the alignment really needs to be equal to satisfy the
> > > +    ///   `dealloc` requirement that memory must be allocated and deallocated with the same layout.)
> > > +    /// - The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs to be
> > > +    ///   smaller or equal the size the pointer was allocated with.
> > > +    /// - `length` needs to be less than or equal to `capacity`.
> > > +    /// - The first `length` values must be properly initialized values of type `T`.
> > > +    /// - The allocated size in bytes must be no larger than `isize::MAX`. See the safety
> > > +    ///   documentation of `pointer::offset`.
> > > +    ///
> > > +    /// It is also valid to create an empty `Vec` passing a dangling pointer for `ptr` and zero for
> > > +    /// `cap` and `len`.
> > > +    ///
> > > +    /// # Examples
> > > +    ///
> > > +    /// ```
> > > +    /// let mut v = kernel::kvec![1, 2, 3]?;
> > > +    /// v.reserve(1, GFP_KERNEL)?;
> > > +    ///
> > > +    /// let (mut ptr, mut len, cap) = v.into_raw_parts();
> > > +    ///
> > > +    /// // SAFETY: We've just reserved memory for another element.
> > > +    /// unsafe { ptr.add(len).write(4) };
> > > +    /// len += 1;
> > > +    ///
> > > +    /// // SAFETY: We only wrote an additional element at the end of the `KVec`'s buffer and
> > > +    /// // correspondingly increased the length of the `KVec` by one. Otherwise, we construct it
> > > +    /// // from the exact same raw parts.
> > > +    /// let v = unsafe { KVec::from_raw_parts(ptr, len, cap) };
> > > +    ///
> > > +    /// assert_eq!(v, [1, 2, 3, 4]);
> > > +    ///
> > > +    /// # Ok::<(), Error>(())
> > > +    /// ```
> > > +    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
> > > +        let cap = if Self::is_zst() { 0 } else { capacity };
> > > +
> > > +        Self {
> > > +            // SAFETY: By the safety requirements, `ptr` is either dangling or pointing to a valid
> > > +            // memory allocation, allocated with `A`.
> > > +            ptr: unsafe { Unique::new_unchecked(ptr) },
> > > +            cap,
> > > +            len: length,
> > > +            _p: PhantomData::<A>,
> > > +        }
> > > +    }
> > > +
> > > +    /// Decomposes a `Vec<T, A>` into its raw components: (`pointer`, `length`, `capacity`).
> > > +    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
> > > +        let me = ManuallyDrop::new(self);
> > > +        let len = me.len();
> > > +        let capacity = me.capacity();
> > > +        let ptr = me.as_mut_ptr();
> > > +        (ptr, len, capacity)
> > > +    }
> > > +
> > > +    /// Ensures that the capacity exceeds the length by at least `additional` elements.
> > > +    ///
> > > +    /// # Examples
> > > +    ///
> > > +    /// ```
> > > +    /// let mut v = KVec::new();
> > > +    /// v.push(1, GFP_KERNEL)?;
> > > +    ///
> > > +    /// v.reserve(10, GFP_KERNEL)?;
> > > +    /// let cap = v.capacity();
> > > +    /// assert!(cap >= 10);
> > > +    ///
> > > +    /// v.reserve(10, GFP_KERNEL)?;
> > > +    /// let new_cap = v.capacity();
> > > +    /// assert_eq!(new_cap, cap);
> > > +    ///
> > > +    /// # Ok::<(), Error>(())
> > > +    /// ```
> > > +    pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> {
> > > +        let len = self.len();
> > > +        let cap = self.capacity();
> > > +
> > > +        if cap - len >= additional {
> > > +            return Ok(());
> > > +        }
> > > +
> > > +        if Self::is_zst() {
> > > +            // The capacity is already `usize::MAX` for SZTs, we can't go higher.
> > > +            return Err(AllocError);
> > > +        }
> > > +
> > > +        // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size
> > > +        // is greater than `isize::MAX`. So the multiplication by two won't overflow.
> >
> > You know it won't overflow because of the type invariants. The thing
> > about Layout::array should instead be used to argue why setting
> > self.cap below does not break the invariants.
>
> Good point, I will reword it.
>
> >
> > > +        let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
> > > +        let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
> > > +
> > > +        // We need to make sure that `ptr` is either NULL or comes from a previous call to
> > > +        // `realloc_flags`. A `Vec<T, A>`'s `ptr` value is not guaranteed to be NULL and might be
> > > +        // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T, A>`'s
> > > +        // capacity to be zero if no memory has been allocated yet.
> > > +        let ptr = if cap == 0 {
> > > +            None
> > > +        } else {
> > > +            Some(self.ptr.as_non_null().cast())
> > > +        };
> > > +
> > > +        // SAFETY: `ptr` is valid because it's either `None` or comes from a previous call to
> > > +        // `A::realloc`. We also verified that the type is not a ZST.
> > > +        let ptr = unsafe { A::realloc(ptr, layout, flags)? };
> > > +
> > > +        self.ptr = ptr.cast().into();
> > > +        self.cap = new_cap;
> > > +
> > > +        Ok(())
> > > +    }
> > > +}
> > > +
> > > +impl<T: Clone, A: Allocator> Vec<T, A> {
> > > +    /// Extend the vector by `n` clones of value.
> > > +    pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> {
> > > +        self.reserve(n, flags)?;
> > > +
> > > +        let spare = self.spare_capacity_mut();
> > > +
> > > +        for i in 0..spare.len() - 1 {
> > > +            spare[i].write(value.clone());
> > > +        }
> >
> > Minus one? Shouldn't this instead loop for `0..n`?
>
> We can indeed just use `n` instead of `slice::len` here.

But `spare.len()` could be longer than `n`?

>
> Minus one, because we create clones for the first n - 1 elements and for the
> last one we just use the value itself.
>
> >
> > > +
> > > +        // We can write the last element directly without cloning needlessly
> > > +        spare[spare.len() - 1].write(value);
> >
> > spare[n-1].write(value);
>
> Yep, works too.
>
> >
> > > +
> > > +        // SAFETY: `self.reserve` not bailing out with an error guarantees that we're not
> > > +        // exceeding the capacity of this `Vec`.
> > > +        unsafe { self.set_len(self.len() + n) };
> > > +
> > > +        Ok(())
> > > +    }
> > > +
> > > +    /// Create a new `Vec<T, A> and extend it by `n` clones of `value`.
> > > +    pub fn from_elem(value: T, n: usize, flags: Flags) -> Result<Self, AllocError> {
> > > +        let mut v = Self::with_capacity(n, flags)?;
> > > +
> > > +        v.extend_with(n, value, flags)?;
> > > +
> > > +        Ok(v)
> > > +    }
> > > +}
> > > +
> > > +impl<T, A> Drop for Vec<T, A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    fn drop(&mut self) {
> > > +        // SAFETY: We need to drop the vector's elements in place, before we free the backing
> > > +        // memory.
> > > +        unsafe {
> > > +            core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
> > > +                self.as_mut_ptr(),
> > > +                self.len,
> > > +            ))
> > > +        };
> > > +
> > > +        // If `cap == 0` we never allocated any memory in the first place.
> > > +        if self.cap != 0 {
> > > +            // SAFETY: `self.ptr` was previously allocated with `A`.
> > > +            unsafe { A::free(self.ptr.as_non_null().cast()) };
> >
> > Do you need a ZST check here?
>
> No, for ZST `self.cap` is always zero.
>
> >
> > > +        }
> > > +    }
> > > +}
> > > +
> > > +impl<T> Default for KVec<T> {
> > > +    #[inline]
> > > +    fn default() -> Self {
> > > +        Self::new()
> > > +    }
> > > +}
> > > +
> > > +impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
> > > +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> > > +        fmt::Debug::fmt(&**self, f)
> > > +    }
> > > +}
> > > +
> > > +impl<T, A> Deref for Vec<T, A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    type Target = [T];
> > > +
> > > +    #[inline]
> > > +    fn deref(&self) -> &[T] {
> > > +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> > > +        // initialized elements of type `T`.
> > > +        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
> > > +    }
> > > +}
> > > +
> > > +impl<T, A> DerefMut for Vec<T, A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    #[inline]
> > > +    fn deref_mut(&mut self) -> &mut [T] {
> > > +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> > > +        // initialized elements of type `T`.
> > > +        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
> > > +    }
> > > +}
> > > +
> > > +impl<T: Eq, A> Eq for Vec<T, A> where A: Allocator {}
> > > +
> > > +impl<T, I: SliceIndex<[T]>, A> Index<I> for Vec<T, A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    type Output = I::Output;
> > > +
> > > +    #[inline]
> > > +    fn index(&self, index: I) -> &Self::Output {
> > > +        Index::index(&**self, index)
> > > +    }
> > > +}
> > > +
> > > +impl<T, I: SliceIndex<[T]>, A> IndexMut<I> for Vec<T, A>
> > > +where
> > > +    A: Allocator,
> > > +{
> > > +    #[inline]
> > > +    fn index_mut(&mut self, index: I) -> &mut Self::Output {
> > > +        IndexMut::index_mut(&mut **self, index)
> > > +    }
> > > +}
> > > +
> > > +macro_rules! __impl_slice_eq {
> > > +    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
> > > +        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
> > > +        where
> > > +            T: PartialEq<U>,
> > > +            $($ty: $bound)?
> > > +        {
> > > +            #[inline]
> > > +            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
> > > +        }
> > > +    }
> > > +}
> > > +
> > > +__impl_slice_eq! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> }
> > > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &[U] }
> > > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &mut [U] }
> > > +__impl_slice_eq! { [A: Allocator] &[T], Vec<U, A> }
> > > +__impl_slice_eq! { [A: Allocator] &mut [T], Vec<U, A> }
> > > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, [U] }
> > > +__impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
> > > +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
> > > +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
> > > diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> > > index 6bf77577eae7..bb80a43d20fb 100644
> > > --- a/rust/kernel/prelude.rs
> > > +++ b/rust/kernel/prelude.rs
> > > @@ -14,7 +14,7 @@
> > >  #[doc(no_inline)]
> > >  pub use core::pin::Pin;
> > >
> > > -pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox};
> > > +pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
> > >
> > >  #[doc(no_inline)]
> > >  pub use alloc::vec::Vec;
> > > --
> > > 2.45.2
> > >
> >


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter`
  2024-08-01 15:10   ` Alice Ryhl
@ 2024-08-01 15:37     ` Danilo Krummrich
  2024-08-02  7:08       ` Alice Ryhl
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 15:37 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 05:10:22PM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > Currently, we can't implement `FromIterator`. There are a couple of
> > issues with this trait in the kernel, namely:
> >
> >   - Rust's specialization feature is unstable. This prevents us to
> >     optimze for the special case where `I::IntoIter` equals `Vec`'s
> >     `IntoIter` type.
> >   - We also can't use `I::IntoIter`'s type ID either to work around this,
> >     since `FromIterator` doesn't require this type to be `'static`.
> >   - `FromIterator::from_iter` does return `Self` instead of
> >     `Result<Self, AllocError>`, hence we can't properly handle allocation
> >     failures.
> >   - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle
> >     additional allocation flags.
> >
> > Instead, provide `IntoIter::collect`, such that we can at least convert
> > `IntoIter` into a `Vec` again.
> >
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> 
> I'm not convinced a collect implementation specific to IntoIter is necessary?

For the reasons above, we can't implement `FromIterator`. At some point we may
want to implement our own kernel `FromIterator` trait, but that's out of scope
for this series.

For now, I just want to provide a way to get a `Vec` from `IntoIter` again,
which without `Vec::collect` would be impossible.

> 
> > +
> > +        // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be
> > +        // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves
> > +        // it as it is.
> > +        ptr = match unsafe { A::realloc(Some(buf.cast()), layout, flags) } {
> 
> Why would you shrink it? You can just keep the capacity.

What if the vector was pretty huge and meanwhile as advanced by a lot? I think
we don't want to waste those resources.

Ideally the corresponding `Allocator` implements a proper heuristic for when to
actually shrink. For instance, krealloc() never shrinks, and it's probably not
worth it. For vrealloc() though we clearly want to shrink properly (i.e. unmap
and free spare pages) at some point.

> 
> Alice
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type
  2024-08-01 15:31       ` Alice Ryhl
@ 2024-08-01 15:46         ` Danilo Krummrich
  0 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-01 15:46 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 05:31:48PM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 5:28 PM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > On Thu, Aug 01, 2024 at 05:05:41PM +0200, Alice Ryhl wrote:
> > > On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > >
> > > > `Vec` provides a contiguous growable array type (such as `Vec`) with
> > > > contents allocated with the kernel's allocators (e.g. `Kmalloc`,
> > > > `Vmalloc` or `KVmalloc`).
> > > >
> > > > In contrast to Rust's `Vec` type, the kernel `Vec` type considers the
> > > > kernel's GFP flags for all appropriate functions, always reports
> > > > allocation failures through `Result<_, AllocError>` and remains
> > > > independent from unstable features.
> > > >
> > > > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > > > ---
> > > >  rust/kernel/alloc.rs      |   6 +
> > > >  rust/kernel/alloc/kbox.rs |  16 +-
> > > >  rust/kernel/alloc/kvec.rs | 583 ++++++++++++++++++++++++++++++++++++++
> > > >  rust/kernel/prelude.rs    |   2 +-
> > > >  4 files changed, 605 insertions(+), 2 deletions(-)
> > > >  create mode 100644 rust/kernel/alloc/kvec.rs
> > > >
> > > > diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> > > > index 4bddd023aa7f..bd93140f3094 100644
> > > > --- a/rust/kernel/alloc.rs
> > > > +++ b/rust/kernel/alloc.rs
> > > > @@ -5,6 +5,7 @@
> > > >  #[cfg(not(any(test, testlib)))]
> > > >  pub mod allocator;
> > > >  pub mod kbox;
> > > > +pub mod kvec;
> > > >  pub mod vec_ext;
> > > >
> > > >  #[cfg(any(test, testlib))]
> > > > @@ -18,6 +19,11 @@
> > > >  pub use self::kbox::KVBox;
> > > >  pub use self::kbox::VBox;
> > > >
> > > > +pub use self::kvec::KVVec;
> > > > +pub use self::kvec::KVec;
> > > > +pub use self::kvec::VVec;
> > > > +pub use self::kvec::Vec;
> > > > +
> > > >  /// Indicates an allocation error.
> > > >  #[derive(Copy, Clone, PartialEq, Eq, Debug)]
> > > >  pub struct AllocError;
> > > > diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
> > > > index 7074f00e07bc..39feaed4a8f8 100644
> > > > --- a/rust/kernel/alloc/kbox.rs
> > > > +++ b/rust/kernel/alloc/kbox.rs
> > > > @@ -2,7 +2,7 @@
> > > >
> > > >  //! Implementation of [`Box`].
> > > >
> > > > -use super::{AllocError, Allocator, Flags};
> > > > +use super::{AllocError, Allocator, Flags, Vec};
> > > >  use core::fmt;
> > > >  use core::marker::PhantomData;
> > > >  use core::mem::ManuallyDrop;
> > > > @@ -169,6 +169,20 @@ pub fn into_pin(b: Self) -> Pin<Self>
> > > >      }
> > > >  }
> > > >
> > > > +impl<T, A, const N: usize> Box<[T; N], A>
> > > > +where
> > > > +    A: Allocator,
> > > > +{
> > > > +    /// Convert a `Box<[T], A>` to a `Vec<T, A>`.
> > > > +    pub fn into_vec(b: Self) -> Vec<T, A> {
> > >
> > > This doc-comment seems wrong. [T] and [T; N] are not the same thing.
> >
> > Indeed, gonna fix.
> >
> > >
> > > > +        let len = b.len();
> > > > +        unsafe {
> > > > +            let ptr = Self::into_raw(b);
> > > > +            Vec::from_raw_parts(ptr as _, len, len)
> > > > +        }
> > > > +    }
> > > > +}
> > > > +
> > > >  impl<T, A> Box<MaybeUninit<T>, A>
> > > >  where
> > > >      A: Allocator,
> > > > diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> > > > new file mode 100644
> > > > index 000000000000..04cc85f7d92c
> > > > --- /dev/null
> > > > +++ b/rust/kernel/alloc/kvec.rs
> > > > @@ -0,0 +1,583 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +
> > > > +//! Implementation of [`Vec`].
> > > > +
> > > > +use super::{AllocError, Allocator, Flags};
> > > > +use crate::types::Unique;
> > > > +use core::{
> > > > +    fmt,
> > > > +    marker::PhantomData,
> > > > +    mem::{ManuallyDrop, MaybeUninit},
> > > > +    ops::Deref,
> > > > +    ops::DerefMut,
> > > > +    ops::Index,
> > > > +    ops::IndexMut,
> > > > +    slice,
> > > > +    slice::SliceIndex,
> > > > +};
> > > > +
> > > > +/// Create a [`Vec`] containing the arguments.
> > > > +///
> > > > +/// # Examples
> > > > +///
> > > > +/// ```
> > > > +/// let mut v = kernel::kvec![];
> > > > +/// v.push(1, GFP_KERNEL)?;
> > > > +/// assert_eq!(v, [1]);
> > > > +///
> > > > +/// let mut v = kernel::kvec![1; 3]?;
> > > > +/// v.push(4, GFP_KERNEL)?;
> > > > +/// assert_eq!(v, [1, 1, 1, 4]);
> > > > +///
> > > > +/// let mut v = kernel::kvec![1, 2, 3]?;
> > > > +/// v.push(4, GFP_KERNEL)?;
> > > > +/// assert_eq!(v, [1, 2, 3, 4]);
> > > > +///
> > > > +/// # Ok::<(), Error>(())
> > > > +/// ```
> > > > +#[macro_export]
> > > > +macro_rules! kvec {
> > > > +    () => (
> > > > +        {
> > > > +            $crate::alloc::KVec::new()
> > > > +        }
> > > > +    );
> > > > +    ($elem:expr; $n:expr) => (
> > > > +        {
> > > > +            $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL)
> > > > +        }
> > > > +    );
> > > > +    ($($x:expr),+ $(,)?) => (
> > > > +        {
> > > > +            match $crate::alloc::KBox::new([$($x),+], GFP_KERNEL) {
> > > > +                Ok(b) => Ok($crate::alloc::KBox::into_vec(b)),
> > > > +                Err(e) => Err(e),
> > > > +            }
> > > > +        }
> > > > +    );
> > > > +}
> > > > +
> > > > +/// The kernel's [`Vec`] type.
> > > > +///
> > > > +/// A contiguous growable array type with contents allocated with the kernel's allocators (e.g.
> > > > +/// `Kmalloc`, `Vmalloc` or `KVmalloc`, written `Vec<T, A>`.
> > >
> > > A closing bracket is missing in this sentence.
> >
> > Gonna fix.
> >
> > >
> > > > +/// For non-zero-sized values, a [`Vec`] will use the given allocator `A` for its allocation. For
> > > > +/// the most common allocators the type aliases `KVec`, `VVec` and `KVVec` exist.
> > > > +///
> > > > +/// For zero-sized types the [`Vec`]'s pointer must be `dangling_mut::<T>`; no memory is allocated.
> > > > +///
> > > > +/// Generally, [`Vec`] consists of a pointer that represents the vector's backing buffer, the
> > > > +/// capacity of the vector (the number of elements that currently fit into the vector), it's length
> > > > +/// (the number of elements that are currently stored in the vector) and the `Allocator` used to
> > > > +/// allocate (and free) the backing buffer.
> > > > +///
> > > > +/// A [`Vec`] can be deconstructed into and (re-)constructed from it's previously named raw parts
> > > > +/// and manually modified.
> > > > +///
> > > > +/// [`Vec`]'s backing buffer gets, if required, automatically increased (re-allocated) when elements
> > > > +/// are added to the vector.
> > > > +///
> > > > +/// # Invariants
> > > > +///
> > > > +/// The [`Vec`] backing buffer's pointer always properly aligned and either points to memory
> > > > +/// allocated with `A` or, for zero-sized types, is a dangling pointer.
> > > > +///
> > > > +/// The length of the vector always represents the exact number of elements stored in the vector.
> > > > +///
> > > > +/// The capacity of the vector always represents the absolute number of elements that can be stored
> > > > +/// within the vector without re-allocation. However, it is legal for the backing buffer to be
> > > > +/// larger than `size_of<T>` times the capacity.
> > > > +///
> > > > +/// The `Allocator` of the vector is the exact allocator the backing buffer was allocated with (and
> > > > +/// must be freed with).
> > > > +pub struct Vec<T, A: Allocator> {
> > > > +    ptr: Unique<T>,
> > > > +    /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
> > > > +    ///
> > > > +    /// # Safety
> > > > +    ///
> > > > +    /// `cap` must be in the `0..=isize::MAX` range.
> > > > +    cap: usize,
> > >
> > > This section header should say Invariants, not Safety.
> >
> > Agreed.
> >
> > >
> > > > +    len: usize,
> > > > +    _p: PhantomData<A>,
> > > > +}
> > > > +
> > > > +/// Type alias for `Vec` with a `Kmalloc` allocator.
> > > > +///
> > > > +/// # Examples
> > > > +///
> > > > +/// ```
> > > > +/// let mut v = KVec::new();
> > > > +/// v.push(1, GFP_KERNEL)?;
> > > > +/// assert_eq!(&v, &[1]);
> > > > +///
> > > > +/// # Ok::<(), Error>(())
> > > > +/// ```
> > > > +pub type KVec<T> = Vec<T, super::allocator::Kmalloc>;
> > > > +
> > > > +/// Type alias for `Vec` with a `Vmalloc` allocator.
> > > > +///
> > > > +/// # Examples
> > > > +///
> > > > +/// ```
> > > > +/// let mut v = VVec::new();
> > > > +/// v.push(1, GFP_KERNEL)?;
> > > > +/// assert_eq!(&v, &[1]);
> > > > +///
> > > > +/// # Ok::<(), Error>(())
> > > > +/// ```
> > > > +pub type VVec<T> = Vec<T, super::allocator::Vmalloc>;
> > > > +
> > > > +/// Type alias for `Vec` with a `KVmalloc` allocator.
> > > > +///
> > > > +/// # Examples
> > > > +///
> > > > +/// ```
> > > > +/// let mut v = KVVec::new();
> > > > +/// v.push(1, GFP_KERNEL)?;
> > > > +/// assert_eq!(&v, &[1]);
> > > > +///
> > > > +/// # Ok::<(), Error>(())
> > > > +/// ```
> > > > +pub type KVVec<T> = Vec<T, super::allocator::KVmalloc>;
> > > > +
> > > > +impl<T, A> Vec<T, A>
> > > > +where
> > > > +    A: Allocator,
> > > > +{
> > > > +    #[inline]
> > > > +    fn is_zst() -> bool {
> > > > +        core::mem::size_of::<T>() == 0
> > > > +    }
> > > > +
> > > > +    /// Returns the total number of elements the vector can hold without
> > > > +    /// reallocating.
> > > > +    pub fn capacity(&self) -> usize {
> > > > +        if Self::is_zst() {
> > > > +            usize::MAX
> > > > +        } else {
> > > > +            self.cap
> > > > +        }
> > > > +    }
> > >
> > > I would consider always storing usize::MAX in the capacity field for zst types?
> >
> > This wouldn't work. `self.cap` is supposed to represent the actual capacity of
> > the vector, which for ZSTs is zero.
> 
> Storing usize::MAX values of a zero-sized type takes up zero bytes,
> and your vector has space for zero bytes. Seems sensible to me to use
> usize::MAX.

The logic here really is that `self.cap` represents the actual buffer size,
whereas `Self::capacity` represents the number of elements we can still store
without reallocating. Depending on the case we need to know one or the other.

I can add a comment to make this more clear if you prefer.

> 
> Anyway, it's up to you. I'm ok either way.
> 
> > > > +
> > > > +    /// Returns the number of elements in the vector, also referred to
> > > > +    /// as its 'length'.
> > > > +    #[inline]
> > > > +    pub fn len(&self) -> usize {
> > > > +        self.len
> > > > +    }
> > > > +
> > > > +    /// Forces the length of the vector to new_len.
> > > > +    ///
> > > > +    /// # Safety
> > > > +    ///
> > > > +    /// - `new_len` must be less than or equal to [`Self::capacity()`].
> > > > +    /// - The elements at `old_len..new_len` must be initialized.
> > > > +    #[inline]
> > > > +    pub unsafe fn set_len(&mut self, new_len: usize) {
> > > > +        self.len = new_len;
> > > > +    }
> > > > +
> > > > +    /// Extracts a slice containing the entire vector.
> > > > +    ///
> > > > +    /// Equivalent to `&s[..]`.
> > > > +    #[inline]
> > > > +    pub fn as_slice(&self) -> &[T] {
> > > > +        self
> > > > +    }
> > > > +
> > > > +    /// Extracts a mutable slice of the entire vector.
> > > > +    ///
> > > > +    /// Equivalent to `&mut s[..]`.
> > > > +    #[inline]
> > > > +    pub fn as_mut_slice(&mut self) -> &mut [T] {
> > > > +        self
> > > > +    }
> > > > +
> > > > +    /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
> > > > +    /// raw pointer valid for zero sized reads if the vector didn't allocate.
> > > > +    #[inline]
> > > > +    pub fn as_mut_ptr(&self) -> *mut T {
> > > > +        self.ptr.as_ptr()
> > > > +    }
> > > > +
> > > > +    /// Returns a raw pointer to the slice's buffer.
> > > > +    #[inline]
> > > > +    pub fn as_ptr(&self) -> *const T {
> > > > +        self.as_mut_ptr()
> > > > +    }
> > > > +
> > > > +    /// Returns `true` if the vector contains no elements.
> > > > +    ///
> > > > +    /// # Examples
> > > > +    ///
> > > > +    /// ```
> > > > +    /// let mut v = KVec::new();
> > > > +    /// assert!(v.is_empty());
> > > > +    ///
> > > > +    /// v.push(1, GFP_KERNEL);
> > > > +    /// assert!(!v.is_empty());
> > > > +    /// ```
> > > > +    #[inline]
> > > > +    pub fn is_empty(&self) -> bool {
> > > > +        self.len() == 0
> > > > +    }
> > > > +
> > > > +    /// Constructs a new, empty Vec<T, A>.
> > > > +    ///
> > > > +    /// This method does not allocate by itself.
> > > > +    #[inline]
> > > > +    pub const fn new() -> Self {
> > > > +        Self {
> > > > +            ptr: Unique::dangling(),
> > > > +            cap: 0,
> > > > +            len: 0,
> > > > +            _p: PhantomData::<A>,
> > > > +        }
> > > > +    }
> > > > +
> > > > +    /// Returns the remaining spare capacity of the vector as a slice of `MaybeUninit<T>`.
> > > > +    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
> > > > +        // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated
> > > > +        // and valid, but uninitialized.
> > > > +        unsafe {
> > > > +            slice::from_raw_parts_mut(
> > > > +                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
> > > > +                self.capacity() - self.len,
> > > > +            )
> > > > +        }
> > >
> > > Is this correct for ZSTs?
> >
> > Yes, it gives us a slice of ZSTs with the maximum possible length usize::MAX.
> >
> > >
> > > > +    }
> > > > +
> > > > +    /// Appends an element to the back of the [`Vec`] instance.
> > > > +    ///
> > > > +    /// # Examples
> > > > +    ///
> > > > +    /// ```
> > > > +    /// let mut v = KVec::new();
> > > > +    /// v.push(1, GFP_KERNEL)?;
> > > > +    /// assert_eq!(&v, &[1]);
> > > > +    ///
> > > > +    /// v.push(2, GFP_KERNEL)?;
> > > > +    /// assert_eq!(&v, &[1, 2]);
> > > > +    /// # Ok::<(), Error>(())
> > > > +    /// ```
> > > > +    pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> {
> > > > +        Vec::reserve(self, 1, flags)?;
> > > > +        let s = self.spare_capacity_mut();
> > > > +        s[0].write(v);
> > > > +
> > > > +        // SAFETY: We just initialised the first spare entry, so it is safe to increase the length
> > > > +        // by 1. We also know that the new length is <= capacity because of the previous call to
> > > > +        // `reserve` above.
> > > > +        unsafe { self.set_len(self.len() + 1) };
> > > > +        Ok(())
> > > > +    }
> > > > +
> > > > +    /// Creates a new [`Vec`] instance with at least the given capacity.
> > > > +    ///
> > > > +    /// # Examples
> > > > +    ///
> > > > +    /// ```
> > > > +    /// let v = KVec::<u32>::with_capacity(20, GFP_KERNEL)?;
> > > > +    ///
> > > > +    /// assert!(v.capacity() >= 20);
> > > > +    /// # Ok::<(), Error>(())
> > > > +    /// ```
> > > > +    pub fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> {
> > > > +        let mut v = Vec::new();
> > > > +
> > > > +        Self::reserve(&mut v, capacity, flags)?;
> > > > +
> > > > +        Ok(v)
> > > > +    }
> > > > +
> > > > +    /// Pushes clones of the elements of slice into the [`Vec`] instance.
> > > > +    ///
> > > > +    /// # Examples
> > > > +    ///
> > > > +    /// ```
> > > > +    /// let mut v = KVec::new();
> > > > +    /// v.push(1, GFP_KERNEL)?;
> > > > +    ///
> > > > +    /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?;
> > > > +    /// assert_eq!(&v, &[1, 20, 30, 40]);
> > > > +    ///
> > > > +    /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?;
> > > > +    /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]);
> > > > +    /// # Ok::<(), Error>(())
> > > > +    /// ```
> > > > +    pub fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
> > > > +    where
> > > > +        T: Clone,
> > > > +    {
> > > > +        self.reserve(other.len(), flags)?;
> > > > +        for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) {
> > > > +            slot.write(item.clone());
> > > > +        }
> > > > +
> > > > +        // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase
> > > > +        // the length by the same amount. We also know that the new length is <= capacity because
> > > > +        // of the previous call to `reserve` above.
> > > > +        unsafe { self.set_len(self.len() + other.len()) };
> > > > +        Ok(())
> > > > +    }
> > > > +
> > > > +    /// Creates a Vec<T, A> directly from a pointer, a length, a capacity, and an allocator.
> > > > +    ///
> > > > +    /// # Safety
> > > > +    ///
> > > > +    /// This is highly unsafe, due to the number of invariants that aren’t checked:
> > > > +    ///
> > > > +    /// - `ptr` must be currently allocated via the given allocator `A`.
> > > > +    /// - `T` needs to have the same alignment as what `ptr` was allocated with. (`T` having a less
> > > > +    ///   strict alignment is not sufficient, the alignment really needs to be equal to satisfy the
> > > > +    ///   `dealloc` requirement that memory must be allocated and deallocated with the same layout.)
> > > > +    /// - The size of `T` times the `capacity` (i.e. the allocated size in bytes) needs to be
> > > > +    ///   smaller or equal the size the pointer was allocated with.
> > > > +    /// - `length` needs to be less than or equal to `capacity`.
> > > > +    /// - The first `length` values must be properly initialized values of type `T`.
> > > > +    /// - The allocated size in bytes must be no larger than `isize::MAX`. See the safety
> > > > +    ///   documentation of `pointer::offset`.
> > > > +    ///
> > > > +    /// It is also valid to create an empty `Vec` passing a dangling pointer for `ptr` and zero for
> > > > +    /// `cap` and `len`.
> > > > +    ///
> > > > +    /// # Examples
> > > > +    ///
> > > > +    /// ```
> > > > +    /// let mut v = kernel::kvec![1, 2, 3]?;
> > > > +    /// v.reserve(1, GFP_KERNEL)?;
> > > > +    ///
> > > > +    /// let (mut ptr, mut len, cap) = v.into_raw_parts();
> > > > +    ///
> > > > +    /// // SAFETY: We've just reserved memory for another element.
> > > > +    /// unsafe { ptr.add(len).write(4) };
> > > > +    /// len += 1;
> > > > +    ///
> > > > +    /// // SAFETY: We only wrote an additional element at the end of the `KVec`'s buffer and
> > > > +    /// // correspondingly increased the length of the `KVec` by one. Otherwise, we construct it
> > > > +    /// // from the exact same raw parts.
> > > > +    /// let v = unsafe { KVec::from_raw_parts(ptr, len, cap) };
> > > > +    ///
> > > > +    /// assert_eq!(v, [1, 2, 3, 4]);
> > > > +    ///
> > > > +    /// # Ok::<(), Error>(())
> > > > +    /// ```
> > > > +    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
> > > > +        let cap = if Self::is_zst() { 0 } else { capacity };
> > > > +
> > > > +        Self {
> > > > +            // SAFETY: By the safety requirements, `ptr` is either dangling or pointing to a valid
> > > > +            // memory allocation, allocated with `A`.
> > > > +            ptr: unsafe { Unique::new_unchecked(ptr) },
> > > > +            cap,
> > > > +            len: length,
> > > > +            _p: PhantomData::<A>,
> > > > +        }
> > > > +    }
> > > > +
> > > > +    /// Decomposes a `Vec<T, A>` into its raw components: (`pointer`, `length`, `capacity`).
> > > > +    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
> > > > +        let me = ManuallyDrop::new(self);
> > > > +        let len = me.len();
> > > > +        let capacity = me.capacity();
> > > > +        let ptr = me.as_mut_ptr();
> > > > +        (ptr, len, capacity)
> > > > +    }
> > > > +
> > > > +    /// Ensures that the capacity exceeds the length by at least `additional` elements.
> > > > +    ///
> > > > +    /// # Examples
> > > > +    ///
> > > > +    /// ```
> > > > +    /// let mut v = KVec::new();
> > > > +    /// v.push(1, GFP_KERNEL)?;
> > > > +    ///
> > > > +    /// v.reserve(10, GFP_KERNEL)?;
> > > > +    /// let cap = v.capacity();
> > > > +    /// assert!(cap >= 10);
> > > > +    ///
> > > > +    /// v.reserve(10, GFP_KERNEL)?;
> > > > +    /// let new_cap = v.capacity();
> > > > +    /// assert_eq!(new_cap, cap);
> > > > +    ///
> > > > +    /// # Ok::<(), Error>(())
> > > > +    /// ```
> > > > +    pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> {
> > > > +        let len = self.len();
> > > > +        let cap = self.capacity();
> > > > +
> > > > +        if cap - len >= additional {
> > > > +            return Ok(());
> > > > +        }
> > > > +
> > > > +        if Self::is_zst() {
> > > > +            // The capacity is already `usize::MAX` for SZTs, we can't go higher.
> > > > +            return Err(AllocError);
> > > > +        }
> > > > +
> > > > +        // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size
> > > > +        // is greater than `isize::MAX`. So the multiplication by two won't overflow.
> > >
> > > You know it won't overflow because of the type invariants. The thing
> > > about Layout::array should instead be used to argue why setting
> > > self.cap below does not break the invariants.
> >
> > Good point, I will reword it.
> >
> > >
> > > > +        let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
> > > > +        let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
> > > > +
> > > > +        // We need to make sure that `ptr` is either NULL or comes from a previous call to
> > > > +        // `realloc_flags`. A `Vec<T, A>`'s `ptr` value is not guaranteed to be NULL and might be
> > > > +        // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T, A>`'s
> > > > +        // capacity to be zero if no memory has been allocated yet.
> > > > +        let ptr = if cap == 0 {
> > > > +            None
> > > > +        } else {
> > > > +            Some(self.ptr.as_non_null().cast())
> > > > +        };
> > > > +
> > > > +        // SAFETY: `ptr` is valid because it's either `None` or comes from a previous call to
> > > > +        // `A::realloc`. We also verified that the type is not a ZST.
> > > > +        let ptr = unsafe { A::realloc(ptr, layout, flags)? };
> > > > +
> > > > +        self.ptr = ptr.cast().into();
> > > > +        self.cap = new_cap;
> > > > +
> > > > +        Ok(())
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T: Clone, A: Allocator> Vec<T, A> {
> > > > +    /// Extend the vector by `n` clones of value.
> > > > +    pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> {
> > > > +        self.reserve(n, flags)?;
> > > > +
> > > > +        let spare = self.spare_capacity_mut();
> > > > +
> > > > +        for i in 0..spare.len() - 1 {
> > > > +            spare[i].write(value.clone());
> > > > +        }
> > >
> > > Minus one? Shouldn't this instead loop for `0..n`?
> >
> > We can indeed just use `n` instead of `slice::len` here.
> 
> But `spare.len()` could be longer than `n`?

You're right, we *have to* use `n`. Gonna fix that.

> 
> >
> > Minus one, because we create clones for the first n - 1 elements and for the
> > last one we just use the value itself.
> >
> > >
> > > > +
> > > > +        // We can write the last element directly without cloning needlessly
> > > > +        spare[spare.len() - 1].write(value);
> > >
> > > spare[n-1].write(value);
> >
> > Yep, works too.
> >
> > >
> > > > +
> > > > +        // SAFETY: `self.reserve` not bailing out with an error guarantees that we're not
> > > > +        // exceeding the capacity of this `Vec`.
> > > > +        unsafe { self.set_len(self.len() + n) };
> > > > +
> > > > +        Ok(())
> > > > +    }
> > > > +
> > > > +    /// Create a new `Vec<T, A> and extend it by `n` clones of `value`.
> > > > +    pub fn from_elem(value: T, n: usize, flags: Flags) -> Result<Self, AllocError> {
> > > > +        let mut v = Self::with_capacity(n, flags)?;
> > > > +
> > > > +        v.extend_with(n, value, flags)?;
> > > > +
> > > > +        Ok(v)
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T, A> Drop for Vec<T, A>
> > > > +where
> > > > +    A: Allocator,
> > > > +{
> > > > +    fn drop(&mut self) {
> > > > +        // SAFETY: We need to drop the vector's elements in place, before we free the backing
> > > > +        // memory.
> > > > +        unsafe {
> > > > +            core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
> > > > +                self.as_mut_ptr(),
> > > > +                self.len,
> > > > +            ))
> > > > +        };
> > > > +
> > > > +        // If `cap == 0` we never allocated any memory in the first place.
> > > > +        if self.cap != 0 {
> > > > +            // SAFETY: `self.ptr` was previously allocated with `A`.
> > > > +            unsafe { A::free(self.ptr.as_non_null().cast()) };
> > >
> > > Do you need a ZST check here?
> >
> > No, for ZST `self.cap` is always zero.
> >
> > >
> > > > +        }
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T> Default for KVec<T> {
> > > > +    #[inline]
> > > > +    fn default() -> Self {
> > > > +        Self::new()
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> {
> > > > +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> > > > +        fmt::Debug::fmt(&**self, f)
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T, A> Deref for Vec<T, A>
> > > > +where
> > > > +    A: Allocator,
> > > > +{
> > > > +    type Target = [T];
> > > > +
> > > > +    #[inline]
> > > > +    fn deref(&self) -> &[T] {
> > > > +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> > > > +        // initialized elements of type `T`.
> > > > +        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T, A> DerefMut for Vec<T, A>
> > > > +where
> > > > +    A: Allocator,
> > > > +{
> > > > +    #[inline]
> > > > +    fn deref_mut(&mut self) -> &mut [T] {
> > > > +        // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len`
> > > > +        // initialized elements of type `T`.
> > > > +        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T: Eq, A> Eq for Vec<T, A> where A: Allocator {}
> > > > +
> > > > +impl<T, I: SliceIndex<[T]>, A> Index<I> for Vec<T, A>
> > > > +where
> > > > +    A: Allocator,
> > > > +{
> > > > +    type Output = I::Output;
> > > > +
> > > > +    #[inline]
> > > > +    fn index(&self, index: I) -> &Self::Output {
> > > > +        Index::index(&**self, index)
> > > > +    }
> > > > +}
> > > > +
> > > > +impl<T, I: SliceIndex<[T]>, A> IndexMut<I> for Vec<T, A>
> > > > +where
> > > > +    A: Allocator,
> > > > +{
> > > > +    #[inline]
> > > > +    fn index_mut(&mut self, index: I) -> &mut Self::Output {
> > > > +        IndexMut::index_mut(&mut **self, index)
> > > > +    }
> > > > +}
> > > > +
> > > > +macro_rules! __impl_slice_eq {
> > > > +    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
> > > > +        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
> > > > +        where
> > > > +            T: PartialEq<U>,
> > > > +            $($ty: $bound)?
> > > > +        {
> > > > +            #[inline]
> > > > +            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
> > > > +        }
> > > > +    }
> > > > +}
> > > > +
> > > > +__impl_slice_eq! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> }
> > > > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &[U] }
> > > > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, &mut [U] }
> > > > +__impl_slice_eq! { [A: Allocator] &[T], Vec<U, A> }
> > > > +__impl_slice_eq! { [A: Allocator] &mut [T], Vec<U, A> }
> > > > +__impl_slice_eq! { [A: Allocator] Vec<T, A>, [U] }
> > > > +__impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
> > > > +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
> > > > +__impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
> > > > diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> > > > index 6bf77577eae7..bb80a43d20fb 100644
> > > > --- a/rust/kernel/prelude.rs
> > > > +++ b/rust/kernel/prelude.rs
> > > > @@ -14,7 +14,7 @@
> > > >  #[doc(no_inline)]
> > > >  pub use core::pin::Pin;
> > > >
> > > > -pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox};
> > > > +pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
> > > >
> > > >  #[doc(no_inline)]
> > > >  pub use alloc::vec::Vec;
> > > > --
> > > > 2.45.2
> > > >
> > >
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter`
  2024-08-01 15:37     ` Danilo Krummrich
@ 2024-08-02  7:08       ` Alice Ryhl
  2024-08-02 12:02         ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Alice Ryhl @ 2024-08-02  7:08 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 1, 2024 at 5:37 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu, Aug 01, 2024 at 05:10:22PM +0200, Alice Ryhl wrote:
> > On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > >
> > > Currently, we can't implement `FromIterator`. There are a couple of
> > > issues with this trait in the kernel, namely:
> > >
> > >   - Rust's specialization feature is unstable. This prevents us to
> > >     optimze for the special case where `I::IntoIter` equals `Vec`'s
> > >     `IntoIter` type.
> > >   - We also can't use `I::IntoIter`'s type ID either to work around this,
> > >     since `FromIterator` doesn't require this type to be `'static`.
> > >   - `FromIterator::from_iter` does return `Self` instead of
> > >     `Result<Self, AllocError>`, hence we can't properly handle allocation
> > >     failures.
> > >   - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle
> > >     additional allocation flags.
> > >
> > > Instead, provide `IntoIter::collect`, such that we can at least convert
> > > `IntoIter` into a `Vec` again.
> > >
> > > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> >
> > I'm not convinced a collect implementation specific to IntoIter is necessary?
>
> For the reasons above, we can't implement `FromIterator`. At some point we may
> want to implement our own kernel `FromIterator` trait, but that's out of scope
> for this series.
>
> For now, I just want to provide a way to get a `Vec` from `IntoIter` again,
> which without `Vec::collect` would be impossible.

If you have a need for a collect on this particular kind of iterator, then okay.

> > > +
> > > +        // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be
> > > +        // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves
> > > +        // it as it is.
> > > +        ptr = match unsafe { A::realloc(Some(buf.cast()), layout, flags) } {
> >
> > Why would you shrink it? You can just keep the capacity.
>
> What if the vector was pretty huge and meanwhile as advanced by a lot? I think
> we don't want to waste those resources.
>
> Ideally the corresponding `Allocator` implements a proper heuristic for when to
> actually shrink. For instance, krealloc() never shrinks, and it's probably not
> worth it. For vrealloc() though we clearly want to shrink properly (i.e. unmap
> and free spare pages) at some point.

The Rust Vec never shrinks unless explicitly requested. But I guess
it's okay either way.

Alice


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter`
  2024-08-02  7:08       ` Alice Ryhl
@ 2024-08-02 12:02         ` Danilo Krummrich
  2024-08-02 12:08           ` Alice Ryhl
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-02 12:02 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Fri, Aug 02, 2024 at 09:08:48AM +0200, Alice Ryhl wrote:
> On Thu, Aug 1, 2024 at 5:37 PM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > On Thu, Aug 01, 2024 at 05:10:22PM +0200, Alice Ryhl wrote:
> > > On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > >
> > > > Currently, we can't implement `FromIterator`. There are a couple of
> > > > issues with this trait in the kernel, namely:
> > > >
> > > >   - Rust's specialization feature is unstable. This prevents us to
> > > >     optimze for the special case where `I::IntoIter` equals `Vec`'s
> > > >     `IntoIter` type.
> > > >   - We also can't use `I::IntoIter`'s type ID either to work around this,
> > > >     since `FromIterator` doesn't require this type to be `'static`.
> > > >   - `FromIterator::from_iter` does return `Self` instead of
> > > >     `Result<Self, AllocError>`, hence we can't properly handle allocation
> > > >     failures.
> > > >   - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle
> > > >     additional allocation flags.
> > > >
> > > > Instead, provide `IntoIter::collect`, such that we can at least convert
> > > > `IntoIter` into a `Vec` again.
> > > >
> > > > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > >
> > > I'm not convinced a collect implementation specific to IntoIter is necessary?
> >
> > For the reasons above, we can't implement `FromIterator`. At some point we may
> > want to implement our own kernel `FromIterator` trait, but that's out of scope
> > for this series.
> >
> > For now, I just want to provide a way to get a `Vec` from `IntoIter` again,
> > which without `Vec::collect` would be impossible.
> 
> If you have a need for a collect on this particular kind of iterator, then okay.

Even once we have our own `FromIterator` trait, we probably want to keep this
specific one besides the generic `collect` for optimization. With the generic
one we'd otherwise copy into a new `Vec`.

> 
> > > > +
> > > > +        // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be
> > > > +        // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves
> > > > +        // it as it is.
> > > > +        ptr = match unsafe { A::realloc(Some(buf.cast()), layout, flags) } {
> > >
> > > Why would you shrink it? You can just keep the capacity.
> >
> > What if the vector was pretty huge and meanwhile as advanced by a lot? I think
> > we don't want to waste those resources.
> >
> > Ideally the corresponding `Allocator` implements a proper heuristic for when to
> > actually shrink. For instance, krealloc() never shrinks, and it's probably not
> > worth it. For vrealloc() though we clearly want to shrink properly (i.e. unmap
> > and free spare pages) at some point.
> 
> The Rust Vec never shrinks unless explicitly requested. But I guess
> it's okay either way.

It actually does, see [1]. But Rust's `Vec` does it less efficiently. It either
keeps the `Vec` as it is, or creates a whole new one.

[1] https://github.com/rust-lang/rust/blob/master/library/alloc/src/vec/spec_from_iter.rs#L39

> 
> Alice
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter`
  2024-08-02 12:02         ` Danilo Krummrich
@ 2024-08-02 12:08           ` Alice Ryhl
  0 siblings, 0 replies; 63+ messages in thread
From: Alice Ryhl @ 2024-08-02 12:08 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, boqun.feng, gary, bjorn3_gh,
	benno.lossin, a.hindborg, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Fri, Aug 2, 2024 at 2:02 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Fri, Aug 02, 2024 at 09:08:48AM +0200, Alice Ryhl wrote:
> > On Thu, Aug 1, 2024 at 5:37 PM Danilo Krummrich <dakr@kernel.org> wrote:
> > >
> > > On Thu, Aug 01, 2024 at 05:10:22PM +0200, Alice Ryhl wrote:
> > > > On Thu, Aug 1, 2024 at 2:08 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > > >
> > > > > Currently, we can't implement `FromIterator`. There are a couple of
> > > > > issues with this trait in the kernel, namely:
> > > > >
> > > > >   - Rust's specialization feature is unstable. This prevents us to
> > > > >     optimze for the special case where `I::IntoIter` equals `Vec`'s
> > > > >     `IntoIter` type.
> > > > >   - We also can't use `I::IntoIter`'s type ID either to work around this,
> > > > >     since `FromIterator` doesn't require this type to be `'static`.
> > > > >   - `FromIterator::from_iter` does return `Self` instead of
> > > > >     `Result<Self, AllocError>`, hence we can't properly handle allocation
> > > > >     failures.
> > > > >   - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle
> > > > >     additional allocation flags.
> > > > >
> > > > > Instead, provide `IntoIter::collect`, such that we can at least convert
> > > > > `IntoIter` into a `Vec` again.
> > > > >
> > > > > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > > >
> > > > I'm not convinced a collect implementation specific to IntoIter is necessary?
> > >
> > > For the reasons above, we can't implement `FromIterator`. At some point we may
> > > want to implement our own kernel `FromIterator` trait, but that's out of scope
> > > for this series.
> > >
> > > For now, I just want to provide a way to get a `Vec` from `IntoIter` again,
> > > which without `Vec::collect` would be impossible.
> >
> > If you have a need for a collect on this particular kind of iterator, then okay.
>
> Even once we have our own `FromIterator` trait, we probably want to keep this
> specific one besides the generic `collect` for optimization. With the generic
> one we'd otherwise copy into a new `Vec`.
>
> >
> > > > > +
> > > > > +        // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be
> > > > > +        // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves
> > > > > +        // it as it is.
> > > > > +        ptr = match unsafe { A::realloc(Some(buf.cast()), layout, flags) } {
> > > >
> > > > Why would you shrink it? You can just keep the capacity.
> > >
> > > What if the vector was pretty huge and meanwhile as advanced by a lot? I think
> > > we don't want to waste those resources.
> > >
> > > Ideally the corresponding `Allocator` implements a proper heuristic for when to
> > > actually shrink. For instance, krealloc() never shrinks, and it's probably not
> > > worth it. For vrealloc() though we clearly want to shrink properly (i.e. unmap
> > > and free spare pages) at some point.
> >
> > The Rust Vec never shrinks unless explicitly requested. But I guess
> > it's okay either way.
>
> It actually does, see [1]. But Rust's `Vec` does it less efficiently. It either
> keeps the `Vec` as it is, or creates a whole new one.
>
> [1] https://github.com/rust-lang/rust/blob/master/library/alloc/src/vec/spec_from_iter.rs#L39

Huh, surprising.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>

Alice


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 01/25] rust: alloc: add `Allocator` trait
  2024-08-01  0:02 ` [PATCH v3 01/25] rust: alloc: add `Allocator` trait Danilo Krummrich
  2024-08-01  8:19   ` Alice Ryhl
@ 2024-08-04  6:21   ` Boqun Feng
  2024-08-04 12:29     ` Danilo Krummrich
  1 sibling, 1 reply; 63+ messages in thread
From: Boqun Feng @ 2024-08-04  6:21 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 02:02:00AM +0200, Danilo Krummrich wrote:
[...]
> +/// The kernel's [`Allocator`] trait.
> +///
> +/// An implementation of [`Allocator`] can allocate, re-allocate and free memory buffer described
> +/// via [`Layout`].
> +///
> +/// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
> +/// an object instance.
> +///
> +/// # Safety
> +///
> +/// Memory returned from an allocator must point to a valid memory buffer and remain valid until
> +/// it is explicitly freed.
> +///
> +/// Any pointer to a memory buffer which is currently allocated must be valid to be passed to any
> +/// other [`Allocator`] function. The same applies for a NULL pointer.
> +///

Are you saying you could kmalloc() a memory buffer and pass it to a
vfree()? Or am I missing something here?

Regards,
Boqun

> +/// If `realloc` is called with:
> +///   - a size of zero, the given memory allocation, if any, must be freed
> +///   - a NULL pointer, a new memory allocation must be created
> +pub unsafe trait Allocator {
> +    /// Allocate memory based on `layout` and `flags`.
> +    ///
> +    /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
> +    /// constraints (i.e. minimum size and alignment as specified by `layout`).
> +    ///
> +    /// This function is equivalent to `realloc` when called with a NULL pointer.
> +    fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
> +        // SAFETY: Passing a NULL pointer to `realloc` is valid by it's safety requirements and asks
> +        // for a new memory allocation.
> +        unsafe { Self::realloc(None, layout, flags) }
> +    }
> +
> +    /// Re-allocate an existing memory allocation to satisfy the requested `layout`. If the
> +    /// requested size is zero, `realloc` behaves equivalent to `free`.
> +    ///
> +    /// If the requested size is larger than the size of the existing allocation, a successful call
> +    /// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
> +    /// may also be larger.
> +    ///
> +    /// If the requested size is smaller than the size of the existing allocation, `realloc` may or
> +    /// may not shrink the buffer; this is implementation specific to the allocator.
> +    ///
> +    /// On allocation failure, the existing buffer, if any, remains valid.
> +    ///
> +    /// The buffer is represented as `NonNull<[u8]>`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must point to an existing and valid memory allocation created by this allocator
> +    /// instance.
> +    ///
> +    /// Additionally, `ptr` is allowed to be a NULL pointer; in this case a new memory allocation is
> +    /// created.
> +    unsafe fn realloc(
> +        ptr: Option<NonNull<u8>>,
> +        layout: Layout,
> +        flags: Flags,
> +    ) -> Result<NonNull<[u8]>, AllocError>;
> +
> +    /// Free an existing memory allocation.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must point to an existing and valid memory allocation created by this `Allocator`
> +    /// instance.
> +    unsafe fn free(ptr: NonNull<u8>) {
> +        // SAFETY: `ptr` is guaranteed to be previously allocated with this `Allocator` or NULL.
> +        // Calling `realloc` with a buffer size of zero, frees the buffer `ptr` points to.
> +        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
> +    }
> +}
> -- 
> 2.45.2
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-01  0:02 ` [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
  2024-08-01  8:43   ` Alice Ryhl
@ 2024-08-04  6:44   ` Boqun Feng
  2024-08-04 12:41     ` Danilo Krummrich
  1 sibling, 1 reply; 63+ messages in thread
From: Boqun Feng @ 2024-08-04  6:44 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm,
	Vlastimil Babka

On Thu, Aug 01, 2024 at 02:02:05AM +0200, Danilo Krummrich wrote:
> Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous
> allocator, typically used for larger objects, (much) larger than page
> size.
> 
> All memory allocations made with `Vmalloc` end up in `vrealloc()`.
> 
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/helpers.c                      |  8 ++++++++
>  rust/kernel/alloc/allocator.rs      | 24 ++++++++++++++++++++++++
>  rust/kernel/alloc/allocator_test.rs |  1 +
>  3 files changed, 33 insertions(+)
> 
> diff --git a/rust/helpers.c b/rust/helpers.c
> index 92d3c03ae1bd..4c628986f0c9 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -33,6 +33,7 @@
>  #include <linux/sched/signal.h>
>  #include <linux/slab.h>
>  #include <linux/spinlock.h>
> +#include <linux/vmalloc.h>
>  #include <linux/wait.h>
>  #include <linux/workqueue.h>
>  
> @@ -200,6 +201,13 @@ rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags)
>  }
>  EXPORT_SYMBOL_GPL(rust_helper_krealloc);
>  
> +void * __must_check __realloc_size(2)
> +rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
> +{
> +	return vrealloc(p, size, flags);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
> +
>  /*
>   * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
>   * use it in contexts where Rust expects a `usize` like slice (array) indices.
> diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
> index 397ae5bcc043..e9a3d0694f41 100644
> --- a/rust/kernel/alloc/allocator.rs
> +++ b/rust/kernel/alloc/allocator.rs
> @@ -16,6 +16,12 @@
>  /// `bindings::krealloc`.
>  pub struct Kmalloc;
>  
> +/// The virtually contiguous kernel allocator.
> +///
> +/// The vmalloc allocator allocates pages from the page level allocator and maps them into the
> +/// contiguous kernel virtual space.
> +pub struct Vmalloc;
> +
>  /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
>  fn aligned_size(new_layout: Layout) -> usize {
>      // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
> @@ -58,6 +64,10 @@ fn krealloc() -> Self {
>          Self(bindings::krealloc)
>      }
>  
> +    fn vrealloc() -> Self {
> +        Self(bindings::vrealloc)
> +    }
> +
>      // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
>      unsafe fn call(
>          &self,
> @@ -136,6 +146,20 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
>      }
>  }
>  
> +unsafe impl Allocator for Vmalloc {
> +    unsafe fn realloc(
> +        ptr: Option<NonNull<u8>>,
> +        layout: Layout,
> +        flags: Flags,
> +    ) -> Result<NonNull<[u8]>, AllocError> {
> +        let realloc = ReallocFunc::vrealloc();
> +

IIUC, vrealloc() calls __vmalloc_noprof() in allocation case, that is
calling __vmalloc_node_noprof() with align=1. In such a case, how would
vmalloc() guarantee the allocated memory is aligned to layout.align()?

[Cc Vlastimil]

Regards,
Boqun

> +        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
> +        // allocated with this `Allocator`.
> +        unsafe { realloc.call(ptr, layout, flags) }
> +    }
> +}
> +
>  #[global_allocator]
>  static ALLOCATOR: Kmalloc = Kmalloc;
>  
> diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
> index 4785efc474a7..e7bf2982f68f 100644
> --- a/rust/kernel/alloc/allocator_test.rs
> +++ b/rust/kernel/alloc/allocator_test.rs
> @@ -7,6 +7,7 @@
>  use core::ptr::NonNull;
>  
>  pub struct Kmalloc;
> +pub type Vmalloc = Kmalloc;
>  
>  unsafe impl Allocator for Kmalloc {
>      unsafe fn realloc(
> -- 
> 2.45.2
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 08/25] rust: types: implement `Unique<T>`
  2024-08-01  0:02 ` [PATCH v3 08/25] rust: types: implement `Unique<T>` Danilo Krummrich
@ 2024-08-04  6:54   ` Boqun Feng
  0 siblings, 0 replies; 63+ messages in thread
From: Boqun Feng @ 2024-08-04  6:54 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Thu, Aug 01, 2024 at 02:02:07AM +0200, Danilo Krummrich wrote:
> Implement the `Unique` type as a prerequisite for `Box` and `Vec`
> introduced in subsequent patches.
> 
> `Unique` serves as wrapper around a `NonNull`, but indicates that the
> possessor of this wrapper owns the referent.
> 
> This type already exists in Rust's core library, but, unfortunately, is
> exposed as unstable API and hence shouldn't be used in the kernel.
> 
> This implementation of `Unique` is almost identical, but mostly stripped
> down to the functionality we need for `Box` and `Vec`. Additionally, all
> unstable features are removed and / or replaced by stable ones.
> 
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>

If I understand correctly, `Unique` does nothing unless the compiler
supports putting noalias at the corresponding IRs. If so, should this
depend on whether Rust compiler supports using `Unique` outside std
libraries?

Regards,
Boqun

> ---
>  rust/kernel/types.rs | 183 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 183 insertions(+)
> 
> diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
> index bd189d646adb..7cf89067b5fc 100644
> --- a/rust/kernel/types.rs
> +++ b/rust/kernel/types.rs
> @@ -473,3 +473,186 @@ unsafe impl AsBytes for str {}
>  // does not have any uninitialized portions either.
>  unsafe impl<T: AsBytes> AsBytes for [T] {}
>  unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
> +
> +/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
> +/// of this wrapper owns the referent. Useful for building abstractions like
> +/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
> +///
> +/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
> +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
> +/// the kind of strong aliasing guarantees an instance of `T` can expect:
> +/// the referent of the pointer should not be modified without a unique path to
> +/// its owning Unique.
> +///
> +/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
> +/// consider using `NonNull`, which has weaker semantics.
> +///
> +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
> +/// is never dereferenced. This is so that enums may use this forbidden value
> +/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
> +/// However the pointer may still dangle if it isn't dereferenced.
> +///
> +/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
> +/// for any type which upholds Unique's aliasing requirements.
> +#[repr(transparent)]
> +pub struct Unique<T: ?Sized> {
> +    pointer: NonNull<T>,
> +    // NOTE: this marker has no consequences for variance, but is necessary
> +    // for dropck to understand that we logically own a `T`.
> +    //
> +    // For details, see:
> +    // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
> +    _marker: PhantomData<T>,
> +}
> +
> +/// `Unique` pointers are `Send` if `T` is `Send` because the data they
> +/// reference is unaliased. Note that this aliasing invariant is
> +/// unenforced by the type system; the abstraction using the
> +/// `Unique` must enforce it.
> +unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
> +
> +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
> +/// reference is unaliased. Note that this aliasing invariant is
> +/// unenforced by the type system; the abstraction using the
> +/// `Unique` must enforce it.
> +unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
> +
> +impl<T: Sized> Unique<T> {
> +    /// Creates a new `Unique` that is dangling, but well-aligned.
> +    ///
> +    /// This is useful for initializing types which lazily allocate, like
> +    /// `Vec::new` does.
> +    ///
> +    /// Note that the pointer value may potentially represent a valid pointer to
> +    /// a `T`, which means this must not be used as a "not yet initialized"
> +    /// sentinel value. Types that lazily allocate must track initialization by
> +    /// some other means.
> +    #[must_use]
> +    #[inline]
> +    pub const fn dangling() -> Self {
> +        Unique {
> +            pointer: NonNull::dangling(),
> +            _marker: PhantomData,
> +        }
> +    }
> +}
> +
> +impl<T: ?Sized> Unique<T> {
> +    /// Creates a new `Unique`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must be non-null.
> +    #[inline]
> +    pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
> +        // SAFETY: the caller must guarantee that `ptr` is non-null.
> +        unsafe {
> +            Unique {
> +                pointer: NonNull::new_unchecked(ptr),
> +                _marker: PhantomData,
> +            }
> +        }
> +    }
> +
> +    /// Creates a new `Unique` if `ptr` is non-null.
> +    #[allow(clippy::manual_map)]
> +    #[inline]
> +    pub fn new(ptr: *mut T) -> Option<Self> {
> +        if let Some(pointer) = NonNull::new(ptr) {
> +            Some(Unique {
> +                pointer,
> +                _marker: PhantomData,
> +            })
> +        } else {
> +            None
> +        }
> +    }
> +
> +    /// Acquires the underlying `*mut` pointer.
> +    #[must_use = "`self` will be dropped if the result is not used"]
> +    #[inline]
> +    pub const fn as_ptr(self) -> *mut T {
> +        self.pointer.as_ptr()
> +    }
> +
> +    /// Dereferences the content.
> +    ///
> +    /// The resulting lifetime is bound to self so this behaves "as if"
> +    /// it were actually an instance of T that is getting borrowed. If a longer
> +    /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// Safety requirements for this function are inherited from [NonNull::as_ref].
> +    ///
> +    #[must_use]
> +    #[inline]
> +    pub const unsafe fn as_ref(&self) -> &T {
> +        // SAFETY: the caller must guarantee that `self` meets all the
> +        // requirements for a reference.
> +        unsafe { self.pointer.as_ref() }
> +    }
> +
> +    /// Mutably dereferences the content.
> +    ///
> +    /// The resulting lifetime is bound to self so this behaves "as if"
> +    /// it were actually an instance of T that is getting borrowed. If a longer
> +    /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// Safety requirements for this function are inherited from [NonNull::as_mut].
> +    #[must_use]
> +    #[inline]
> +    pub unsafe fn as_mut(&mut self) -> &mut T {
> +        // SAFETY: the caller must guarantee that `self` meets all the
> +        // requirements for a mutable reference.
> +        unsafe { self.pointer.as_mut() }
> +    }
> +
> +    /// Casts to a pointer of another type.
> +    #[must_use = "`self` will be dropped if the result is not used"]
> +    #[inline]
> +    pub fn cast<U>(self) -> Unique<U> {
> +        Unique::from(self.pointer.cast())
> +    }
> +
> +    /// Acquires the underlying `*mut` pointer.
> +    #[must_use = "`self` will be dropped if the result is not used"]
> +    #[inline]
> +    pub const fn as_non_null(self) -> NonNull<T> {
> +        self.pointer
> +    }
> +}
> +
> +impl<T: ?Sized> Clone for Unique<T> {
> +    #[inline]
> +    fn clone(&self) -> Self {
> +        *self
> +    }
> +}
> +
> +impl<T: ?Sized> Copy for Unique<T> {}
> +
> +impl<T: ?Sized> From<&mut T> for Unique<T> {
> +    /// Converts a `&mut T` to a `Unique<T>`.
> +    ///
> +    /// This conversion is infallible since references cannot be null.
> +    #[inline]
> +    fn from(reference: &mut T) -> Self {
> +        Self::from(NonNull::from(reference))
> +    }
> +}
> +
> +impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
> +    /// Converts a `NonNull<T>` to a `Unique<T>`.
> +    ///
> +    /// This conversion is infallible since `NonNull` cannot be null.
> +    #[inline]
> +    fn from(pointer: NonNull<T>) -> Self {
> +        Unique {
> +            pointer,
> +            _marker: PhantomData,
> +        }
> +    }
> +}
> -- 
> 2.45.2
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 01/25] rust: alloc: add `Allocator` trait
  2024-08-04  6:21   ` Boqun Feng
@ 2024-08-04 12:29     ` Danilo Krummrich
  0 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-04 12:29 UTC (permalink / raw)
  To: Boqun Feng
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm

On Sat, Aug 03, 2024 at 11:21:21PM -0700, Boqun Feng wrote:
> On Thu, Aug 01, 2024 at 02:02:00AM +0200, Danilo Krummrich wrote:
> [...]
> > +/// The kernel's [`Allocator`] trait.
> > +///
> > +/// An implementation of [`Allocator`] can allocate, re-allocate and free memory buffer described
> > +/// via [`Layout`].
> > +///
> > +/// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
> > +/// an object instance.
> > +///
> > +/// # Safety
> > +///
> > +/// Memory returned from an allocator must point to a valid memory buffer and remain valid until
> > +/// it is explicitly freed.
> > +///
> > +/// Any pointer to a memory buffer which is currently allocated must be valid to be passed to any
> > +/// other [`Allocator`] function. The same applies for a NULL pointer.
> > +///
> 
> Are you saying you could kmalloc() a memory buffer and pass it to a
> vfree()? Or am I missing something here?

I will extend it to:

"valid to be passed to any other [`Allocator`] function" of the same type.

> 
> Regards,
> Boqun
> 
> > +/// If `realloc` is called with:
> > +///   - a size of zero, the given memory allocation, if any, must be freed
> > +///   - a NULL pointer, a new memory allocation must be created
> > +pub unsafe trait Allocator {
> > +    /// Allocate memory based on `layout` and `flags`.
> > +    ///
> > +    /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
> > +    /// constraints (i.e. minimum size and alignment as specified by `layout`).
> > +    ///
> > +    /// This function is equivalent to `realloc` when called with a NULL pointer.
> > +    fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
> > +        // SAFETY: Passing a NULL pointer to `realloc` is valid by it's safety requirements and asks
> > +        // for a new memory allocation.
> > +        unsafe { Self::realloc(None, layout, flags) }
> > +    }
> > +
> > +    /// Re-allocate an existing memory allocation to satisfy the requested `layout`. If the
> > +    /// requested size is zero, `realloc` behaves equivalent to `free`.
> > +    ///
> > +    /// If the requested size is larger than the size of the existing allocation, a successful call
> > +    /// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
> > +    /// may also be larger.
> > +    ///
> > +    /// If the requested size is smaller than the size of the existing allocation, `realloc` may or
> > +    /// may not shrink the buffer; this is implementation specific to the allocator.
> > +    ///
> > +    /// On allocation failure, the existing buffer, if any, remains valid.
> > +    ///
> > +    /// The buffer is represented as `NonNull<[u8]>`.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// `ptr` must point to an existing and valid memory allocation created by this allocator
> > +    /// instance.
> > +    ///
> > +    /// Additionally, `ptr` is allowed to be a NULL pointer; in this case a new memory allocation is
> > +    /// created.
> > +    unsafe fn realloc(
> > +        ptr: Option<NonNull<u8>>,
> > +        layout: Layout,
> > +        flags: Flags,
> > +    ) -> Result<NonNull<[u8]>, AllocError>;
> > +
> > +    /// Free an existing memory allocation.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// `ptr` must point to an existing and valid memory allocation created by this `Allocator`
> > +    /// instance.
> > +    unsafe fn free(ptr: NonNull<u8>) {
> > +        // SAFETY: `ptr` is guaranteed to be previously allocated with this `Allocator` or NULL.
> > +        // Calling `realloc` with a buffer size of zero, frees the buffer `ptr` points to.
> > +        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
> > +    }
> > +}
> > -- 
> > 2.45.2
> > 
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-04  6:44   ` Boqun Feng
@ 2024-08-04 12:41     ` Danilo Krummrich
  2024-08-04 15:16       ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-04 12:41 UTC (permalink / raw)
  To: Boqun Feng
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm,
	Vlastimil Babka

On Sat, Aug 03, 2024 at 11:44:58PM -0700, Boqun Feng wrote:
> On Thu, Aug 01, 2024 at 02:02:05AM +0200, Danilo Krummrich wrote:
> > Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous
> > allocator, typically used for larger objects, (much) larger than page
> > size.
> > 
> > All memory allocations made with `Vmalloc` end up in `vrealloc()`.
> > 
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > ---
> >  rust/helpers.c                      |  8 ++++++++
> >  rust/kernel/alloc/allocator.rs      | 24 ++++++++++++++++++++++++
> >  rust/kernel/alloc/allocator_test.rs |  1 +
> >  3 files changed, 33 insertions(+)
> > 
> > diff --git a/rust/helpers.c b/rust/helpers.c
> > index 92d3c03ae1bd..4c628986f0c9 100644
> > --- a/rust/helpers.c
> > +++ b/rust/helpers.c
> > @@ -33,6 +33,7 @@
> >  #include <linux/sched/signal.h>
> >  #include <linux/slab.h>
> >  #include <linux/spinlock.h>
> > +#include <linux/vmalloc.h>
> >  #include <linux/wait.h>
> >  #include <linux/workqueue.h>
> >  
> > @@ -200,6 +201,13 @@ rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags)
> >  }
> >  EXPORT_SYMBOL_GPL(rust_helper_krealloc);
> >  
> > +void * __must_check __realloc_size(2)
> > +rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
> > +{
> > +	return vrealloc(p, size, flags);
> > +}
> > +EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
> > +
> >  /*
> >   * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
> >   * use it in contexts where Rust expects a `usize` like slice (array) indices.
> > diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
> > index 397ae5bcc043..e9a3d0694f41 100644
> > --- a/rust/kernel/alloc/allocator.rs
> > +++ b/rust/kernel/alloc/allocator.rs
> > @@ -16,6 +16,12 @@
> >  /// `bindings::krealloc`.
> >  pub struct Kmalloc;
> >  
> > +/// The virtually contiguous kernel allocator.
> > +///
> > +/// The vmalloc allocator allocates pages from the page level allocator and maps them into the
> > +/// contiguous kernel virtual space.
> > +pub struct Vmalloc;
> > +
> >  /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
> >  fn aligned_size(new_layout: Layout) -> usize {
> >      // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
> > @@ -58,6 +64,10 @@ fn krealloc() -> Self {
> >          Self(bindings::krealloc)
> >      }
> >  
> > +    fn vrealloc() -> Self {
> > +        Self(bindings::vrealloc)
> > +    }
> > +
> >      // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
> >      unsafe fn call(
> >          &self,
> > @@ -136,6 +146,20 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
> >      }
> >  }
> >  
> > +unsafe impl Allocator for Vmalloc {
> > +    unsafe fn realloc(
> > +        ptr: Option<NonNull<u8>>,
> > +        layout: Layout,
> > +        flags: Flags,
> > +    ) -> Result<NonNull<[u8]>, AllocError> {
> > +        let realloc = ReallocFunc::vrealloc();
> > +
> 
> IIUC, vrealloc() calls __vmalloc_noprof() in allocation case, that is
> calling __vmalloc_node_noprof() with align=1. In such a case, how would
> vmalloc() guarantee the allocated memory is aligned to layout.align()?

True, good catch. I thought of this a while ago and then forgot to fix it.

> 
> [Cc Vlastimil]
> 
> Regards,
> Boqun
> 
> > +        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
> > +        // allocated with this `Allocator`.
> > +        unsafe { realloc.call(ptr, layout, flags) }
> > +    }
> > +}
> > +
> >  #[global_allocator]
> >  static ALLOCATOR: Kmalloc = Kmalloc;
> >  
> > diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
> > index 4785efc474a7..e7bf2982f68f 100644
> > --- a/rust/kernel/alloc/allocator_test.rs
> > +++ b/rust/kernel/alloc/allocator_test.rs
> > @@ -7,6 +7,7 @@
> >  use core::ptr::NonNull;
> >  
> >  pub struct Kmalloc;
> > +pub type Vmalloc = Kmalloc;
> >  
> >  unsafe impl Allocator for Kmalloc {
> >      unsafe fn realloc(
> > -- 
> > 2.45.2
> > 
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-04 12:41     ` Danilo Krummrich
@ 2024-08-04 15:16       ` Danilo Krummrich
  2024-08-04 17:39         ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-04 15:16 UTC (permalink / raw)
  To: Boqun Feng
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm,
	Vlastimil Babka

On Sun, Aug 04, 2024 at 02:41:26PM +0200, Danilo Krummrich wrote:
> On Sat, Aug 03, 2024 at 11:44:58PM -0700, Boqun Feng wrote:
> > On Thu, Aug 01, 2024 at 02:02:05AM +0200, Danilo Krummrich wrote:
> > > Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous
> > > allocator, typically used for larger objects, (much) larger than page
> > > size.
> > > 
> > > All memory allocations made with `Vmalloc` end up in `vrealloc()`.
> > > 
> > > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > > ---
> > >  rust/helpers.c                      |  8 ++++++++
> > >  rust/kernel/alloc/allocator.rs      | 24 ++++++++++++++++++++++++
> > >  rust/kernel/alloc/allocator_test.rs |  1 +
> > >  3 files changed, 33 insertions(+)
> > > 
> > > diff --git a/rust/helpers.c b/rust/helpers.c
> > > index 92d3c03ae1bd..4c628986f0c9 100644
> > > --- a/rust/helpers.c
> > > +++ b/rust/helpers.c
> > > @@ -33,6 +33,7 @@
> > >  #include <linux/sched/signal.h>
> > >  #include <linux/slab.h>
> > >  #include <linux/spinlock.h>
> > > +#include <linux/vmalloc.h>
> > >  #include <linux/wait.h>
> > >  #include <linux/workqueue.h>
> > >  
> > > @@ -200,6 +201,13 @@ rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags)
> > >  }
> > >  EXPORT_SYMBOL_GPL(rust_helper_krealloc);
> > >  
> > > +void * __must_check __realloc_size(2)
> > > +rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
> > > +{
> > > +	return vrealloc(p, size, flags);
> > > +}
> > > +EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
> > > +
> > >  /*
> > >   * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
> > >   * use it in contexts where Rust expects a `usize` like slice (array) indices.
> > > diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
> > > index 397ae5bcc043..e9a3d0694f41 100644
> > > --- a/rust/kernel/alloc/allocator.rs
> > > +++ b/rust/kernel/alloc/allocator.rs
> > > @@ -16,6 +16,12 @@
> > >  /// `bindings::krealloc`.
> > >  pub struct Kmalloc;
> > >  
> > > +/// The virtually contiguous kernel allocator.
> > > +///
> > > +/// The vmalloc allocator allocates pages from the page level allocator and maps them into the
> > > +/// contiguous kernel virtual space.
> > > +pub struct Vmalloc;
> > > +
> > >  /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
> > >  fn aligned_size(new_layout: Layout) -> usize {
> > >      // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
> > > @@ -58,6 +64,10 @@ fn krealloc() -> Self {
> > >          Self(bindings::krealloc)
> > >      }
> > >  
> > > +    fn vrealloc() -> Self {
> > > +        Self(bindings::vrealloc)
> > > +    }
> > > +
> > >      // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
> > >      unsafe fn call(
> > >          &self,
> > > @@ -136,6 +146,20 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
> > >      }
> > >  }
> > >  
> > > +unsafe impl Allocator for Vmalloc {
> > > +    unsafe fn realloc(
> > > +        ptr: Option<NonNull<u8>>,
> > > +        layout: Layout,
> > > +        flags: Flags,
> > > +    ) -> Result<NonNull<[u8]>, AllocError> {
> > > +        let realloc = ReallocFunc::vrealloc();
> > > +
> > 
> > IIUC, vrealloc() calls __vmalloc_noprof() in allocation case, that is
> > calling __vmalloc_node_noprof() with align=1. In such a case, how would
> > vmalloc() guarantee the allocated memory is aligned to layout.align()?
> 
> True, good catch. I thought of this a while ago and then forgot to fix it.

Just for clarification, we're always PAGE_SIZE aligned (guaranteed by
__alloc_vmap_area()), which probably would always be sufficient. That's why I
didn't gave it too much attention in the first place and then forgot about it.

However, we indeed do not honor layout.align() if it's larger than PAGE_SIZE.

> 
> > 
> > [Cc Vlastimil]
> > 
> > Regards,
> > Boqun
> > 
> > > +        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
> > > +        // allocated with this `Allocator`.
> > > +        unsafe { realloc.call(ptr, layout, flags) }
> > > +    }
> > > +}
> > > +
> > >  #[global_allocator]
> > >  static ALLOCATOR: Kmalloc = Kmalloc;
> > >  
> > > diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
> > > index 4785efc474a7..e7bf2982f68f 100644
> > > --- a/rust/kernel/alloc/allocator_test.rs
> > > +++ b/rust/kernel/alloc/allocator_test.rs
> > > @@ -7,6 +7,7 @@
> > >  use core::ptr::NonNull;
> > >  
> > >  pub struct Kmalloc;
> > > +pub type Vmalloc = Kmalloc;
> > >  
> > >  unsafe impl Allocator for Kmalloc {
> > >      unsafe fn realloc(
> > > -- 
> > > 2.45.2
> > > 
> > 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-04 15:16       ` Danilo Krummrich
@ 2024-08-04 17:39         ` Danilo Krummrich
  2024-08-04 23:57           ` Boqun Feng
  0 siblings, 1 reply; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-04 17:39 UTC (permalink / raw)
  To: Boqun Feng
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm,
	Vlastimil Babka

On Sun, Aug 04, 2024 at 05:16:49PM +0200, Danilo Krummrich wrote:
> On Sun, Aug 04, 2024 at 02:41:26PM +0200, Danilo Krummrich wrote:
> > On Sat, Aug 03, 2024 at 11:44:58PM -0700, Boqun Feng wrote:
> > > On Thu, Aug 01, 2024 at 02:02:05AM +0200, Danilo Krummrich wrote:
> > > > Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous
> > > > allocator, typically used for larger objects, (much) larger than page
> > > > size.
> > > > 
> > > > All memory allocations made with `Vmalloc` end up in `vrealloc()`.
> > > > 
> > > > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > > > ---
> > > >  rust/helpers.c                      |  8 ++++++++
> > > >  rust/kernel/alloc/allocator.rs      | 24 ++++++++++++++++++++++++
> > > >  rust/kernel/alloc/allocator_test.rs |  1 +
> > > >  3 files changed, 33 insertions(+)
> > > > 
> > > > diff --git a/rust/helpers.c b/rust/helpers.c
> > > > index 92d3c03ae1bd..4c628986f0c9 100644
> > > > --- a/rust/helpers.c
> > > > +++ b/rust/helpers.c
> > > > @@ -33,6 +33,7 @@
> > > >  #include <linux/sched/signal.h>
> > > >  #include <linux/slab.h>
> > > >  #include <linux/spinlock.h>
> > > > +#include <linux/vmalloc.h>
> > > >  #include <linux/wait.h>
> > > >  #include <linux/workqueue.h>
> > > >  
> > > > @@ -200,6 +201,13 @@ rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags)
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(rust_helper_krealloc);
> > > >  
> > > > +void * __must_check __realloc_size(2)
> > > > +rust_helper_vrealloc(const void *p, size_t size, gfp_t flags)
> > > > +{
> > > > +	return vrealloc(p, size, flags);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(rust_helper_vrealloc);
> > > > +
> > > >  /*
> > > >   * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
> > > >   * use it in contexts where Rust expects a `usize` like slice (array) indices.
> > > > diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
> > > > index 397ae5bcc043..e9a3d0694f41 100644
> > > > --- a/rust/kernel/alloc/allocator.rs
> > > > +++ b/rust/kernel/alloc/allocator.rs
> > > > @@ -16,6 +16,12 @@
> > > >  /// `bindings::krealloc`.
> > > >  pub struct Kmalloc;
> > > >  
> > > > +/// The virtually contiguous kernel allocator.
> > > > +///
> > > > +/// The vmalloc allocator allocates pages from the page level allocator and maps them into the
> > > > +/// contiguous kernel virtual space.
> > > > +pub struct Vmalloc;
> > > > +
> > > >  /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
> > > >  fn aligned_size(new_layout: Layout) -> usize {
> > > >      // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
> > > > @@ -58,6 +64,10 @@ fn krealloc() -> Self {
> > > >          Self(bindings::krealloc)
> > > >      }
> > > >  
> > > > +    fn vrealloc() -> Self {
> > > > +        Self(bindings::vrealloc)
> > > > +    }
> > > > +
> > > >      // SAFETY: `call` has the exact same safety requirements as `Allocator::realloc`.
> > > >      unsafe fn call(
> > > >          &self,
> > > > @@ -136,6 +146,20 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
> > > >      }
> > > >  }
> > > >  
> > > > +unsafe impl Allocator for Vmalloc {
> > > > +    unsafe fn realloc(
> > > > +        ptr: Option<NonNull<u8>>,
> > > > +        layout: Layout,
> > > > +        flags: Flags,
> > > > +    ) -> Result<NonNull<[u8]>, AllocError> {
> > > > +        let realloc = ReallocFunc::vrealloc();
> > > > +
> > > 
> > > IIUC, vrealloc() calls __vmalloc_noprof() in allocation case, that is
> > > calling __vmalloc_node_noprof() with align=1. In such a case, how would
> > > vmalloc() guarantee the allocated memory is aligned to layout.align()?
> > 
> > True, good catch. I thought of this a while ago and then forgot to fix it.
> 
> Just for clarification, we're always PAGE_SIZE aligned (guaranteed by
> __alloc_vmap_area()), which probably would always be sufficient. That's why I
> didn't gave it too much attention in the first place and then forgot about it.
> 
> However, we indeed do not honor layout.align() if it's larger than PAGE_SIZE.

Another note on that:

My plan for this series was to just fail allocation for alignment requests
larger than PAGE_SIZE. And, if required, address larger alignments in a later
series, since this one is probably big enough already.

However, for `Vmalloc` we could support it right away, since it's trivial. For
`KVmalloc` though it requires a bit more effort.

For consistancy it would probably be better to support alignments larger than
PAGE_SIZE either for `Vmalloc` and `KVmalloc` or neither of those though.

My personal tendency goes a bit more into the direction of picking consistancy.

Any other opinions?

> 
> > 
> > > 
> > > [Cc Vlastimil]
> > > 
> > > Regards,
> > > Boqun
> > > 
> > > > +        // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
> > > > +        // allocated with this `Allocator`.
> > > > +        unsafe { realloc.call(ptr, layout, flags) }
> > > > +    }
> > > > +}
> > > > +
> > > >  #[global_allocator]
> > > >  static ALLOCATOR: Kmalloc = Kmalloc;
> > > >  
> > > > diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
> > > > index 4785efc474a7..e7bf2982f68f 100644
> > > > --- a/rust/kernel/alloc/allocator_test.rs
> > > > +++ b/rust/kernel/alloc/allocator_test.rs
> > > > @@ -7,6 +7,7 @@
> > > >  use core::ptr::NonNull;
> > > >  
> > > >  pub struct Kmalloc;
> > > > +pub type Vmalloc = Kmalloc;
> > > >  
> > > >  unsafe impl Allocator for Kmalloc {
> > > >      unsafe fn realloc(
> > > > -- 
> > > > 2.45.2
> > > > 
> > > 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-04 17:39         ` Danilo Krummrich
@ 2024-08-04 23:57           ` Boqun Feng
  2024-08-05  0:54             ` Danilo Krummrich
  0 siblings, 1 reply; 63+ messages in thread
From: Boqun Feng @ 2024-08-04 23:57 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm,
	Vlastimil Babka

On Sun, Aug 04, 2024 at 07:39:52PM +0200, Danilo Krummrich wrote:
[...]
> > > > > +unsafe impl Allocator for Vmalloc {
> > > > > +    unsafe fn realloc(
> > > > > +        ptr: Option<NonNull<u8>>,
> > > > > +        layout: Layout,
> > > > > +        flags: Flags,
> > > > > +    ) -> Result<NonNull<[u8]>, AllocError> {
> > > > > +        let realloc = ReallocFunc::vrealloc();
> > > > > +
> > > > 
> > > > IIUC, vrealloc() calls __vmalloc_noprof() in allocation case, that is
> > > > calling __vmalloc_node_noprof() with align=1. In such a case, how would
> > > > vmalloc() guarantee the allocated memory is aligned to layout.align()?
> > > 
> > > True, good catch. I thought of this a while ago and then forgot to fix it.
> > 
> > Just for clarification, we're always PAGE_SIZE aligned (guaranteed by
> > __alloc_vmap_area()), which probably would always be sufficient. That's why I
> > didn't gave it too much attention in the first place and then forgot about it.
> > 
> > However, we indeed do not honor layout.align() if it's larger than PAGE_SIZE.
> 
> Another note on that:
> 
> My plan for this series was to just fail allocation for alignment requests
> larger than PAGE_SIZE. And, if required, address larger alignments in a later

Yeah, this sounds reasonable.

> series, since this one is probably big enough already.
> 
> However, for `Vmalloc` we could support it right away, since it's trivial. For
> `KVmalloc` though it requires a bit more effort.
> 

Could you elaborate why it requires a bit more effort? Because
kvrealloc() and kvmalloc() in C don't have a way to specify alignment
requirement? If so, I think a solution to that would be just providing
the K-or-V switch in Rust code, i.e. just `Vmalloc` and `Kmalloc` to
implement `KVmalloc`, which I don't think is a bad idea.

Regards,
Boqun

> For consistancy it would probably be better to support alignments larger than
> PAGE_SIZE either for `Vmalloc` and `KVmalloc` or neither of those though.
> 
> My personal tendency goes a bit more into the direction of picking consistancy.
> 
> Any other opinions?
> 
[...]


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator
  2024-08-04 23:57           ` Boqun Feng
@ 2024-08-05  0:54             ` Danilo Krummrich
  0 siblings, 0 replies; 63+ messages in thread
From: Danilo Krummrich @ 2024-08-05  0:54 UTC (permalink / raw)
  To: Boqun Feng
  Cc: ojeda, alex.gaynor, wedsonaf, gary, bjorn3_gh, benno.lossin,
	a.hindborg, aliceryhl, akpm, daniel.almeida, faith.ekstrand,
	boris.brezillon, lina, mcanal, zhiw, acurrid, cjia, jhubbard,
	airlied, ajanulgu, lyude, linux-kernel, rust-for-linux, linux-mm,
	Vlastimil Babka

On Sun, Aug 04, 2024 at 04:57:30PM -0700, Boqun Feng wrote:
> On Sun, Aug 04, 2024 at 07:39:52PM +0200, Danilo Krummrich wrote:
> [...]
> > > > > > +unsafe impl Allocator for Vmalloc {
> > > > > > +    unsafe fn realloc(
> > > > > > +        ptr: Option<NonNull<u8>>,
> > > > > > +        layout: Layout,
> > > > > > +        flags: Flags,
> > > > > > +    ) -> Result<NonNull<[u8]>, AllocError> {
> > > > > > +        let realloc = ReallocFunc::vrealloc();
> > > > > > +
> > > > > 
> > > > > IIUC, vrealloc() calls __vmalloc_noprof() in allocation case, that is
> > > > > calling __vmalloc_node_noprof() with align=1. In such a case, how would
> > > > > vmalloc() guarantee the allocated memory is aligned to layout.align()?
> > > > 
> > > > True, good catch. I thought of this a while ago and then forgot to fix it.
> > > 
> > > Just for clarification, we're always PAGE_SIZE aligned (guaranteed by
> > > __alloc_vmap_area()), which probably would always be sufficient. That's why I
> > > didn't gave it too much attention in the first place and then forgot about it.
> > > 
> > > However, we indeed do not honor layout.align() if it's larger than PAGE_SIZE.
> > 
> > Another note on that:
> > 
> > My plan for this series was to just fail allocation for alignment requests
> > larger than PAGE_SIZE. And, if required, address larger alignments in a later
> 
> Yeah, this sounds reasonable.
> 
> > series, since this one is probably big enough already.
> > 
> > However, for `Vmalloc` we could support it right away, since it's trivial. For
> > `KVmalloc` though it requires a bit more effort.
> > 
> 
> Could you elaborate why it requires a bit more effort? Because
> kvrealloc() and kvmalloc() in C don't have a way to specify alignment
> requirement?

Yes, exactly that.

> If so, I think a solution to that would be just providing
> the K-or-V switch in Rust code, i.e. just `Vmalloc` and `Kmalloc` to
> implement `KVmalloc`, which I don't think is a bad idea.

I really think we should do it in C. Look at all the special cases is
__kvmalloc_node_noprof(): fixup page flags, sanity check the size on kmalloc
failure, fail on certain page flags, etc.

I think we really want to keep all this logic in a single place and not
replicate it on the Rust side.

> 
> Regards,
> Boqun
> 
> > For consistancy it would probably be better to support alignments larger than
> > PAGE_SIZE either for `Vmalloc` and `KVmalloc` or neither of those though.
> > 
> > My personal tendency goes a bit more into the direction of picking consistancy.
> > 
> > Any other opinions?
> > 
> [...]
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2024-08-05  0:54 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-01  0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 01/25] rust: alloc: add `Allocator` trait Danilo Krummrich
2024-08-01  8:19   ` Alice Ryhl
2024-08-01 12:26     ` Danilo Krummrich
2024-08-01 14:25       ` Alice Ryhl
2024-08-01 15:09         ` Danilo Krummrich
2024-08-04  6:21   ` Boqun Feng
2024-08-04 12:29     ` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 02/25] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
2024-08-01  8:21   ` Alice Ryhl
2024-08-01  0:02 ` [PATCH v3 03/25] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
2024-08-01  8:21   ` Alice Ryhl
2024-08-01  0:02 ` [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
2024-08-01  8:28   ` Alice Ryhl
2024-08-01 12:30     ` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 05/25] rust: alloc: add module `allocator_test` Danilo Krummrich
2024-08-01  8:41   ` Alice Ryhl
2024-08-01  0:02 ` [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
2024-08-01  8:43   ` Alice Ryhl
2024-08-04  6:44   ` Boqun Feng
2024-08-04 12:41     ` Danilo Krummrich
2024-08-04 15:16       ` Danilo Krummrich
2024-08-04 17:39         ` Danilo Krummrich
2024-08-04 23:57           ` Boqun Feng
2024-08-05  0:54             ` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
2024-08-01  8:43   ` Alice Ryhl
2024-08-01 12:31     ` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 08/25] rust: types: implement `Unique<T>` Danilo Krummrich
2024-08-04  6:54   ` Boqun Feng
2024-08-01  0:02 ` [PATCH v3 09/25] rust: alloc: implement kernel `Box` Danilo Krummrich
2024-08-01  8:55   ` Alice Ryhl
2024-08-01 12:45     ` Danilo Krummrich
2024-08-01 12:48       ` Alice Ryhl
2024-08-01  0:02 ` [PATCH v3 10/25] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 11/25] rust: alloc: remove `BoxExt` extension Danilo Krummrich
2024-08-01 14:53   ` Alice Ryhl
2024-08-01  0:02 ` [PATCH v3 12/25] rust: alloc: add `Box` to prelude Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 13/25] rust: alloc: import kernel `Box` type in types.rs Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 14/25] rust: alloc: import kernel `Box` type in init.rs Danilo Krummrich
2024-08-01 14:55   ` Alice Ryhl
2024-08-01  0:02 ` [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type Danilo Krummrich
2024-08-01 15:05   ` Alice Ryhl
2024-08-01 15:27     ` Danilo Krummrich
2024-08-01 15:31       ` Alice Ryhl
2024-08-01 15:46         ` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
2024-08-01 15:07   ` Alice Ryhl
2024-08-01 15:30     ` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
2024-08-01 15:10   ` Alice Ryhl
2024-08-01 15:37     ` Danilo Krummrich
2024-08-02  7:08       ` Alice Ryhl
2024-08-02 12:02         ` Danilo Krummrich
2024-08-02 12:08           ` Alice Ryhl
2024-08-01  0:02 ` [PATCH v3 18/25] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 19/25] rust: alloc: remove `VecExt` extension Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 20/25] rust: alloc: add `Vec` to prelude Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 21/25] rust: alloc: remove `GlobalAlloc` and `krealloc_aligned` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 22/25] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 23/25] rust: str: test: replace `alloc::format` Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 24/25] rust: alloc: update module comment of alloc.rs Danilo Krummrich
2024-08-01  0:02 ` [PATCH v3 25/25] kbuild: rust: remove the `alloc` crate Danilo Krummrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).