All of lore.kernel.org
 help / color / mirror / Atom feed
From: Danilo Krummrich <dakr@kernel.org>
To: Benno Lossin <benno.lossin@proton.me>
Cc: ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com,
	boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com,
	a.hindborg@samsung.com, aliceryhl@google.com,
	akpm@linux-foundation.org, daniel.almeida@collabora.com,
	faith.ekstrand@collabora.com, boris.brezillon@collabora.com,
	lina@asahilina.net, mcanal@igalia.com, zhiw@nvidia.com,
	cjia@nvidia.com, jhubbard@nvidia.com, airlied@redhat.com,
	ajanulgu@redhat.com, lyude@redhat.com,
	linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	linux-mm@kvack.org
Subject: Re: [PATCH v5 01/26] rust: alloc: add `Allocator` trait
Date: Thu, 15 Aug 2024 02:16:14 +0200	[thread overview]
Message-ID: <Zr1Izo9Qp8mYkbpr@cassiopeiae> (raw)
In-Reply-To: <cfcdaa42-6a62-4a17-a8dc-2382e88774dc@proton.me>

On Wed, Aug 14, 2024 at 04:13:06PM +0000, Benno Lossin wrote:
> On 12.08.24 20:22, Danilo Krummrich 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`.
> > 
> > Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > ---
> >  rust/kernel/alloc.rs | 81 ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 81 insertions(+)
> > 
> > diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> > index 1966bd407017..194745498a75 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,83 @@ 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.
> > +///
> > +/// In order to be able to support `#[derive(SmartPointer)]` later on, we need to avoid a design
> > +/// that requires an `Allocator` to be instantiated, hence its functions must not contain any kind
> > +/// of `self` parameter.
> > +///
> > +/// # Safety
> > +///
> > +/// Memory returned from an allocator must point to a valid memory buffer and remain valid until
> > +/// it is explicitly freed.
> 
> I wouldn't say that an allocator "returns memory", and in general I
> don't think the structure of the safety comment here is nice, how about
> the following: we put "Implementers must ensure that all trait functions
> abide by the guarantees documented in the `# Guarantees` sections."...

Sounds reasonable to me. Additionally, I'd still keep the part below, that says
that any pointer to a memory allocation must bbe valid to be passed to any other [`Allocator`]
function of the same type.

> 
> > +///
> > +/// Any pointer to a memory buffer which is currently allocated must be valid to be passed to any
> > +/// other [`Allocator`] function of the same type.
> > +///
> > +/// If `realloc` is called with:
> > +///   - a size of zero, the given memory allocation, if any, must be freed
> > +///   - `None`, 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 `None`.
> 
> ... Then we can add this here:
> 
>     /// # Guarantees
>     ///
>     /// When the return value is `Ok(ptr)`, then `ptr` is
>     /// - valid for writes (and reads after the memory has been initialized) for `layout.size()` bytes,
>     ///   until it is passed to [`Allocator::free`] or [`Allocator::realloc`],
>     /// - aligned to `layout.align()`,
>     /// - is valid for reads, if `flags.contains(flags::__GFP_ZERO)`,
> 
> Do we need to handle other flags?

The whole flags thing is a bit difficult to represent here properly.

Theoretically, we'd need to add that it guarantees that the memory is zeroed for
__GFP_ZERO, non-blocking for GFP_NOWAIT, etc. But, I think we shouldn't
re-iterate all different behavior for the different flags.

Another inconvenience is that not all page flags are honored or make sense for
all allocators. This is especially inconvenient for `KVmalloc` where we can't
even say if we end up in vrealloc() or krealloc(). kvmalloc() even contains a
couple of flag fixups for this reason [2].

I think we should just point to [1], which should document everything already.

[1] https://elixir.bootlin.com/linux/v6.10.4/source/include/linux/gfp_types.h
[2] https://elixir.bootlin.com/linux/v6.10.4/source/mm/util.c#L612

> Also IIRC the memory given to us by C is considered initialized by Rust
> (though it has a non-deterministic value), so we might have an
> unconditional "valid for reads". Am I correct?

Yes, but as you say, unless allocated with __GFP_ZERO, it contains non-deterministic data. It may
even contain old data from previous allocations.

> 
> 
> > +    fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
> > +        // SAFETY: Passing `None` 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`.
> 
> I don't think we want to include the second sentence in the short
> description of this function, please add an empty line in between.
> 
> > +    ///
> > +    /// 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
> > +    ///
> > +    /// If `ptr = Some(p)`, then `p` must point to an existing and valid memory allocation created
> 
> I don't like the single `=` (I might have written it in haste myself),
> how about `==` or we use if-let syntax?
> 
> > +    /// by this allocator. The alignment encoded in `layout` must be smaller than or equal to the
> > +    /// alignment requested in the previous `alloc` or `realloc` call of the same allocation.
> > +    ///
> > +    /// Additionally, `ptr` is allowed to be `None`; in this case a new memory allocation is
> > +    /// created.
> 
> This Safety section does not talk about the case `layout.size() == 0`,
> but it should have the same requirement as `free()`.
> 
> Also add a `# Guarantees` section here:
> 
>     /// # Guarantees
>     ///
>     /// This function has the same guarantees as [`Allocator::alloc`]. When `ptr == Some(p)`, then it
>     /// additionally has the following:
>     /// - when `Ok(ret_ptr)` is the return value, then
>     ///   `ret_ptr[0..min(layout.size(), old_size)] == p[0..min(layout.size(), old_size)]`, where
>     ///   `old_size` is the size of the allocation that `p` points at.

We could also say "The contents of the memory pointed to by `p` are preserved
up to the lesser of the new and old size." But I'm fine with both.

>     /// - when the return value is `Err(AllocError)`, then `p` is still valid.
> 
> ---
> Cheers,
> Benno
> 
> > +    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` and
> > +    /// must not be a dangling pointer.
> > +    ///
> > +    /// The memory allocation at `ptr` must never again be read from or written to.
> > +    unsafe fn free(ptr: NonNull<u8>) {
> > +        // SAFETY: The caller guarantees that `ptr` points at a valid allocation created by this
> > +        // allocator. We are passing a `Layout` with the smallest possible alignment, so it is
> > +        // smaller than or equal to the alignment previously used with this allocation.
> > +        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), Flags(0)) };
> > +    }
> > +}
> > --
> > 2.45.2
> > 
> 

  reply	other threads:[~2024-08-15  0:16 UTC|newest]

Thread overview: 95+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-12 18:22 [PATCH v5 00/26] Generic `Allocator` support for Rust Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 01/26] rust: alloc: add `Allocator` trait Danilo Krummrich
2024-08-14 16:13   ` Benno Lossin
2024-08-15  0:16     ` Danilo Krummrich [this message]
2024-08-15 13:49       ` Benno Lossin
2024-08-12 18:22 ` [PATCH v5 02/26] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 03/26] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 04/26] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
2024-08-14  7:51   ` Alice Ryhl
2024-08-14 13:36     ` Danilo Krummrich
2024-08-14 13:44       ` Alice Ryhl
2024-08-14 13:48         ` Danilo Krummrich
2024-08-14 13:50           ` Alice Ryhl
2024-08-14 14:00             ` Danilo Krummrich
2024-08-14 15:03               ` Miguel Ojeda
2024-08-14 15:19                 ` Danilo Krummrich
2024-08-14 15:28                   ` Benno Lossin
2024-08-14 16:01                     ` Danilo Krummrich
2024-08-14 16:02                   ` Miguel Ojeda
2024-08-14 16:16                     ` Miguel Ojeda
2024-08-14 16:56                       ` Danilo Krummrich
2024-08-14 16:21   ` Benno Lossin
2024-08-14 16:59     ` Danilo Krummrich
2024-08-14 17:02       ` Benno Lossin
2024-08-14 17:15         ` Danilo Krummrich
2024-08-14 21:07           ` Benno Lossin
2024-08-14 16:28   ` Benno Lossin
2024-08-14 17:13     ` Danilo Krummrich
2024-08-14 21:10       ` Benno Lossin
2024-08-12 18:22 ` [PATCH v5 05/26] rust: alloc: add module `allocator_test` Danilo Krummrich
2024-08-14 16:25   ` Benno Lossin
2024-08-12 18:22 ` [PATCH v5 06/26] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
2024-08-14 16:32   ` Benno Lossin
2024-08-14 22:12     ` Danilo Krummrich
2024-08-14 23:20       ` Danilo Krummrich
2024-08-15  6:48         ` Benno Lossin
2024-08-15 12:29           ` Danilo Krummrich
2024-08-15 13:44             ` Benno Lossin
2024-08-15 14:23               ` Danilo Krummrich
2024-08-15 19:08                 ` Benno Lossin
2024-08-12 18:22 ` [PATCH v5 07/26] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 08/26] rust: alloc: add __GFP_NOWARN to `Flags` Danilo Krummrich
2024-08-14  7:48   ` Alice Ryhl
2024-08-14 16:35   ` Benno Lossin
2024-08-12 18:22 ` [PATCH v5 09/26] rust: alloc: implement kernel `Box` Danilo Krummrich
2024-08-14  8:26   ` Alice Ryhl
2024-08-14 12:22     ` Danilo Krummrich
2024-08-14 12:29       ` Alice Ryhl
2024-08-14 17:01   ` Benno Lossin
2024-08-14 21:58     ` Danilo Krummrich
2024-08-15 12:44       ` Miguel Ojeda
2024-08-15 13:24       ` Benno Lossin
2024-08-15 14:00         ` Danilo Krummrich
2024-08-15 14:10           ` Benno Lossin
2024-08-15 14:17             ` Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 10/26] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 11/26] rust: alloc: remove `BoxExt` extension Danilo Krummrich
2024-08-14 11:55   ` Dirk Behme
2024-08-14 12:08     ` Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 12/26] rust: alloc: add `Box` to prelude Danilo Krummrich
2024-08-12 18:22 ` [PATCH v5 13/26] rust: alloc: implement kernel `Vec` type Danilo Krummrich
2024-08-14  8:42   ` Alice Ryhl
2024-08-14 12:29     ` Danilo Krummrich
2024-08-14 12:36       ` Alice Ryhl
2024-08-15 13:31         ` Benno Lossin
2024-08-14 22:46     ` Danilo Krummrich
2024-08-15  7:30       ` Alice Ryhl
2024-08-15 12:17         ` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 14/26] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 15/26] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 16/26] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 17/26] rust: alloc: remove `VecExt` extension Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 18/26] rust: alloc: add `Vec` to prelude Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 19/26] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 20/26] rust: error: check for config `test` in `Error::name` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 21/26] rust: alloc: implement `contains` for `Flags` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 22/26] rust: alloc: implement `Cmalloc` in module allocator_test Danilo Krummrich
2024-08-13  7:07   ` Heghedus Razvan
2024-08-13 12:34     ` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 23/26] rust: str: test: replace `alloc::format` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 24/26] rust: alloc: update module comment of alloc.rs Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 25/26] kbuild: rust: remove the `alloc` crate and `GlobalAlloc` Danilo Krummrich
2024-08-12 18:23 ` [PATCH v5 26/26] MAINTAINERS: add entry for the Rust `alloc` module Danilo Krummrich
2024-08-14 19:32 ` [PATCH v5 00/26] Generic `Allocator` support for Rust Boqun Feng
2024-08-14 20:53   ` Danilo Krummrich
2024-08-15  2:52   ` Danilo Krummrich
2024-08-15  9:20     ` Alice Ryhl
2024-08-15 12:33       ` Danilo Krummrich
2024-08-15 12:34         ` Alice Ryhl
2024-08-15 13:33           ` Danilo Krummrich
2024-08-15 13:39             ` Benno Lossin
2024-08-15 14:09               ` Danilo Krummrich
2024-08-15 14:19                 ` Benno Lossin
2024-08-15 17:19     ` Boqun Feng
2024-08-15 17:31       ` Danilo Krummrich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Zr1Izo9Qp8mYkbpr@cassiopeiae \
    --to=dakr@kernel.org \
    --cc=a.hindborg@samsung.com \
    --cc=airlied@redhat.com \
    --cc=ajanulgu@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=boris.brezillon@collabora.com \
    --cc=cjia@nvidia.com \
    --cc=daniel.almeida@collabora.com \
    --cc=faith.ekstrand@collabora.com \
    --cc=gary@garyguo.net \
    --cc=jhubbard@nvidia.com \
    --cc=lina@asahilina.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lyude@redhat.com \
    --cc=mcanal@igalia.com \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=wedsonaf@gmail.com \
    --cc=zhiw@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.