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 v6 09/26] rust: alloc: implement kernel `Box`
Date: Tue, 10 Sep 2024 19:40:45 +0200 [thread overview]
Message-ID: <ZuCEneJeXcRo5qs8@pollux> (raw)
In-Reply-To: <0146cb78-5a35-4d6b-bc75-fed1fc0c270c@proton.me>
On Sat, Aug 31, 2024 at 05:39:07AM +0000, Benno Lossin wrote:
> On 16.08.24 02:10, Danilo Krummrich wrote:
> > diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
> > new file mode 100644
> > index 000000000000..93b1ab9de6e8
> > --- /dev/null
> > +++ b/rust/kernel/alloc/kbox.rs
> > @@ -0,0 +1,480 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +//! Implementation of [`Box`].
> > +
> > +#[allow(unused_imports)] // Used in doc comments.
> > +use super::allocator::{KVmalloc, Kmalloc, Vmalloc};
> > +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::NonNull;
> > +use core::result::Result;
> > +
> > +use crate::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
> > +use crate::types::ForeignOwnable;
> > +
> > +/// The kernel's [`Box`] type - a heap allocation for a single value of type `T`.
>
> A single `-` doesn't really render nicely in markdown, instead use a
> double or triple dash (`--` or `---`).
>
> > +///
> > +/// This is the kernel's version of the Rust stdlib's `Box`. There are several of differences,
> > +/// for example no `noalias` attribute is emitted and partially moving out of a `Box` is not
> > +/// supported. There are also several API differences, e.g. `Box` always requires an [`Allocator`]
> > +/// implementation to be passed as generic, page [`Flags`] when allocating memory and all functions
> > +/// that may allocate memory are failable.
>
> Do you mean fallible?
>
> > +///
> > +/// `Box` works with any of the kernel's allocators, e.g. [`Kmalloc`], [`Vmalloc`] or [`KVmalloc`].
> > +/// There are aliases for `Box` with these allocators ([`KBox`], [`VBox`], [`KVBox`]).
> > +///
> > +/// When dropping a [`Box`], the value is also dropped and the heap memory is automatically freed.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// let b = KBox::<u64>::new(24_u64, GFP_KERNEL)?;
> > +///
> > +/// assert_eq!(*b, 24_u64);
> > +/// # Ok::<(), Error>(())
> > +/// ```
> > +///
> > +/// ```
> > +/// # use kernel::bindings;
> > +/// const SIZE: usize = bindings::KMALLOC_MAX_SIZE as usize + 1;
> > +/// struct Huge([u8; SIZE]);
> > +///
> > +/// assert!(KBox::<Huge>::new_uninit(GFP_KERNEL | __GFP_NOWARN).is_err());
> > +/// ```
>
> It would be nice if you could add something like "KBox can't handle big
> allocations:" above this example, so that people aren't confused why
> this example expects an error.
I don't think that's needed, it's implied by
`SIZE == bindings::KMALLOC_MAX_SIZE + 1`.
Surely, we could add it nevertheless, but it's not very precise to just say "big
allocations". And I think this isn't the place for lengthy explanations of
`Kmalloc` behavior.
>
> > +///
> > +/// ```
> > +/// # use kernel::bindings;
> > +/// const SIZE: usize = bindings::KMALLOC_MAX_SIZE as usize + 1;
> > +/// struct Huge([u8; SIZE]);
> > +///
> > +/// assert!(KVBox::<Huge>::new_uninit(GFP_KERNEL).is_ok());
> > +/// ```
>
> Similarly, you could then say above this one "Instead use either `VBox`
> or `KVBox`:"
>
> > +///
> > +/// # Invariants
> > +///
> > +/// The [`Box`]' pointer is always properly aligned and either points to memory allocated with `A`
>
> Please use `self.0` instead of "[`Box`]'".
>
> > +/// or, for zero-sized types, is a dangling pointer.
>
> Probably "dangling, well aligned pointer.".
Does this add any value? For ZSTs everything is "well aligned", isn't it?
>
> > +#[repr(transparent)]
> > +pub struct Box<T: ?Sized, A: Allocator>(NonNull<T>, PhantomData<A>);
> > +
> > +/// Type alias for `Box` with a [`Kmalloc`] allocator.
>
> Can you make these `Box` references links?
>
> > +///
> > +/// # 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>;
> > +
> > +// SAFETY: `Box` is `Send` if `T` is `Send` because the `Box` owns a `T`.
> > +unsafe impl<T, A> Send for Box<T, A>
> > +where
> > + T: Send + ?Sized,
> > + A: Allocator,
> > +{
> > +}
> > +
> > +// SAFETY: `Box` is `Sync` if `T` is `Sync` because the `Box` owns a `T`.
> > +unsafe impl<T, A> Sync for Box<T, A>
> > +where
> > + T: Sync + ?Sized,
> > + A: Allocator,
> > +{
> > +}
> > +
> > +impl<T, A> Box<T, A>
> > +where
> > + T: ?Sized,
> > + A: Allocator,
> > +{
> > + /// Creates a new `Box<T, A>` from a raw pointer.
> > + ///
> > + /// # Safety
> > + ///
> > + /// For non-ZSTs, `raw` must point at an allocation allocated with `A`that is sufficiently
> > + /// aligned for and holds a valid `T`. The caller passes ownership of the allocation to the
> > + /// `Box`.
>
> You don't say what must happen for ZSTs.
Because we don't require anything for a ZST, do we?
>
> > + #[inline]
> > + pub const unsafe fn from_raw(raw: *mut T) -> Self {
> > + // INVARIANT: Validity of `raw` is guaranteed by the safety preconditions of this function.
> > + // SAFETY: By the safety preconditions of this function, `raw` is not a NULL pointer.
> > + Self(unsafe { NonNull::new_unchecked(raw) }, PhantomData::<A>)
> > + }
> > +
> > + /// Consumes the `Box<T, A>` and returns a raw pointer.
> > + ///
> > + /// This will not run the destructor of `T` and for non-ZSTs the allocation will stay alive
> > + /// indefinitely. Use [`Box::from_raw`] to recover the [`Box`], drop the value and free the
> > + /// allocation, if any.
> > + ///
> > + /// # 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 {
> > + let b = ManuallyDrop::new(b);
> > +
> > + b.0.as_ptr()
> > + }
> > +
> > + /// Consumes and leaks the `Box<T, A>` and returns a mutable reference.
> > + ///
> > + /// See [Box::into_raw] for more details.
> > + #[inline]
> > + pub fn leak<'a>(b: Self) -> &'a mut T {
> > + // 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) }
> > + }
> > +}
> > +
> > +impl<T, A> Box<MaybeUninit<T>, A>
> > +where
> > + A: Allocator,
> > +{
> > + /// Converts a `Box<MaybeUninit<T>, A>` to a `Box<T, A>`.
> > + ///
> > + /// It is undefined behavior to call this function while the value inside of `b` is not yet
> > + /// fully initialized.
> > + ///
> > + /// # Safety
> > + ///
> > + /// Callers must ensure that the value inside of `b` is in an initialized state.
> > + pub unsafe fn assume_init(b: Self) -> Box<T, A> {
> > + let raw = Self::into_raw(b);
> > +
> > + // SAFETY: `raw` comes from a previous call to `Box::into_raw`. By the safety requirements
> > + // of this function, the value inside the `Box` is in an initialized state. Hence, it is
> > + // safe to reconstruct the `Box` as `Box<T, A>`.
> > + unsafe { Box::from_raw(raw as *mut T) }
>
> You should be able to use `.cast()` instead.
>
> > + }
> > +
> > + /// 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.
>
> The variable is called `b`.
>
> > + unsafe { Self::assume_init(b) }
> > + }
> > +}
>
> [...]
>
> > +impl<T, A> Drop for Box<T, A>
> > +where
> > + T: ?Sized,
> > + A: Allocator,
> > +{
> > + fn drop(&mut self) {
> > + let size = core::mem::size_of_val::<T>(self);
> > +
> > + // SAFETY: We need to drop `self.0` in place, before we free the backing memory.
>
> This is the reason you are calling this function, not the justification
> why it is OK to do so. (the pointer is valid)
>
> > + unsafe { core::ptr::drop_in_place(self.0.as_ptr()) };
>
> Instead of using the raw pointer directly, you can also just use
> `deref_mut`.
>
> > +
> > + if size != 0 {
> > + // SAFETY: `ptr` was previously allocated with `A`.
>
> There is no variable `ptr`, this is guaranteed by the type invariant of
> `Self`.
>
> ---
> Cheers,
> Benno
>
> > + unsafe { A::free(self.0.cast()) };
> > + }
> > + }
> > +}
> > diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> > index 4571daec0961..a9210634a8c3 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};
> > --
> > 2.46.0
> >
>
next prev parent reply other threads:[~2024-09-10 17:40 UTC|newest]
Thread overview: 100+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-16 0:10 [PATCH v6 00/26] Generic `Allocator` support for Rust Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 01/26] rust: alloc: add `Allocator` trait Danilo Krummrich
2024-08-29 18:19 ` Benno Lossin
2024-08-29 21:56 ` Danilo Krummrich
2024-08-30 13:06 ` Benno Lossin
2024-09-03 11:56 ` Danilo Krummrich
2024-09-10 13:03 ` Benno Lossin
2024-09-10 13:23 ` Danilo Krummrich
2024-09-10 19:37 ` Benno Lossin
2024-08-30 13:44 ` Benno Lossin
2024-08-31 12:01 ` Gary Guo
2024-08-16 0:10 ` [PATCH v6 02/26] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
2024-08-31 12:16 ` Gary Guo
2024-08-16 0:10 ` [PATCH v6 03/26] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 04/26] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
2024-08-29 18:32 ` Benno Lossin
2024-08-29 22:04 ` Danilo Krummrich
2024-08-30 14:45 ` Benno Lossin
2024-09-03 11:48 ` Danilo Krummrich
2024-09-10 13:11 ` Benno Lossin
2024-09-10 13:37 ` Danilo Krummrich
2024-09-10 19:42 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 05/26] rust: alloc: add module `allocator_test` Danilo Krummrich
2024-08-31 12:18 ` Gary Guo
2024-08-16 0:10 ` [PATCH v6 06/26] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
2024-08-31 5:21 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 07/26] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 08/26] rust: alloc: add __GFP_NOWARN to `Flags` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 09/26] rust: alloc: implement kernel `Box` Danilo Krummrich
2024-08-20 9:47 ` Alice Ryhl
2024-08-20 15:26 ` Danilo Krummrich
2024-08-27 19:21 ` Boqun Feng
2024-08-31 5:39 ` Benno Lossin
2024-09-10 17:40 ` Danilo Krummrich [this message]
2024-09-10 19:49 ` Benno Lossin
2024-09-10 23:25 ` Danilo Krummrich
2024-09-11 8:36 ` Benno Lossin
2024-09-11 11:02 ` Danilo Krummrich
2024-09-11 13:26 ` Benno Lossin
2024-09-11 13:27 ` Alice Ryhl
2024-09-11 14:50 ` Danilo Krummrich
2024-09-12 8:03 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 10/26] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
2024-08-29 18:35 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 11/26] rust: alloc: remove `BoxExt` extension Danilo Krummrich
2024-08-29 18:38 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 12/26] rust: alloc: add `Box` to prelude Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 13/26] rust: alloc: implement kernel `Vec` type Danilo Krummrich
2024-09-03 19:08 ` Boqun Feng
2024-09-10 18:26 ` Danilo Krummrich
2024-09-10 19:33 ` Benno Lossin
2024-09-10 19:32 ` Benno Lossin
2024-09-11 0:18 ` Danilo Krummrich
2024-09-11 8:46 ` Benno Lossin
2024-09-10 20:07 ` Benno Lossin
2024-09-11 21:59 ` Danilo Krummrich
2024-09-23 9:24 ` Alice Ryhl
2024-08-16 0:10 ` [PATCH v6 14/26] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
2024-09-04 10:29 ` Alice Ryhl
2024-09-10 20:04 ` Benno Lossin
2024-09-10 23:39 ` Danilo Krummrich
2024-09-11 8:52 ` Benno Lossin
2024-09-11 11:32 ` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 15/26] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
2024-09-10 20:12 ` Benno Lossin
2024-09-11 0:22 ` Danilo Krummrich
2024-09-11 8:53 ` Benno Lossin
2024-09-11 11:33 ` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 16/26] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
2024-08-29 18:41 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 17/26] rust: alloc: remove `VecExt` extension Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 18/26] rust: alloc: add `Vec` to prelude Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 19/26] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 20/26] rust: error: check for config `test` in `Error::name` Danilo Krummrich
2024-08-29 18:41 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 21/26] rust: alloc: implement `contains` for `Flags` Danilo Krummrich
2024-08-29 18:42 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 22/26] rust: alloc: implement `Cmalloc` in module allocator_test Danilo Krummrich
2024-08-29 19:14 ` Benno Lossin
2024-08-29 22:25 ` Danilo Krummrich
2024-08-30 12:56 ` Benno Lossin
2024-09-11 12:31 ` Danilo Krummrich
2024-09-11 13:32 ` Benno Lossin
2024-09-11 14:37 ` Danilo Krummrich
2024-09-12 8:18 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 23/26] rust: str: test: replace `alloc::format` Danilo Krummrich
2024-08-29 18:43 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 24/26] rust: alloc: update module comment of alloc.rs Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 25/26] kbuild: rust: remove the `alloc` crate and `GlobalAlloc` Danilo Krummrich
2024-08-21 21:34 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 26/26] MAINTAINERS: add entry for the Rust `alloc` module Danilo Krummrich
2024-08-31 12:57 ` Gary Guo
2024-09-03 12:03 ` Danilo Krummrich
2024-09-04 10:15 ` Alice Ryhl
2024-09-04 12:51 ` Benno Lossin
2024-09-04 12:57 ` Miguel Ojeda
2024-09-10 13:26 ` Benno Lossin
2024-09-10 13:42 ` Danilo Krummrich
2024-09-10 14:27 ` Benno Lossin
2024-08-27 19:17 ` [PATCH v6 00/26] Generic `Allocator` support for Rust Boqun Feng
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=ZuCEneJeXcRo5qs8@pollux \
--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.