When converting a Box<T> into a void pointer, the allocator might
guarantee a higher alignment than the type itself does, and in that case
it is guaranteed that the void pointer has that higher alignment.
This is quite useful when combined with the XArray, which you can only
create using a ForeignOwnable whose FOREIGN_ALIGN is at least 4. This
means that you can now always use a Box<T> with the XArray no matter the
alignment of T.
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
rust/kernel/alloc/kbox.rs | 15 +++++++++++----
rust/kernel/sync/arc.rs | 6 +++---
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index bffe72f44cb33a265018e67d92d9f0abe82f8e22..fd3f1e0b9c3b3437fb50d8f1b28c92bc7cefd565 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -400,12 +400,19 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
}
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
-// pointer to `T`.
+// pointer to `T` allocated by `A`.
unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
where
A: Allocator,
{
- const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
+ const FOREIGN_ALIGN: usize = {
+ let mut align = core::mem::align_of::<T>();
+ if align < A::MIN_ALIGN {
+ align = A::MIN_ALIGN;
+ }
+ align
+ };
+
type Borrowed<'a> = &'a T;
type BorrowedMut<'a> = &'a mut T;
@@ -434,12 +441,12 @@ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a mut T {
}
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
-// pointer to `T`.
+// pointer to `T` allocated by `A`.
unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
where
A: Allocator,
{
- const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
+ const FOREIGN_ALIGN: usize = <Box<T, A> as ForeignOwnable>::FOREIGN_ALIGN;
type Borrowed<'a> = Pin<&'a T>;
type BorrowedMut<'a> = Pin<&'a mut T>;
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index 63a66761d0c7d752e09ce7372bc230661b2f7c6d..74121cf935f364c16799b5c31cc88714dfd6b702 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -373,10 +373,10 @@ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
}
}
-// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
-// pointer to `ArcInner<T>`.
+// SAFETY: The pointer returned by `into_foreign` was originally allocated as an
+// `KBox<ArcInner<T>>`, so that type is what determines the alignment.
unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
- const FOREIGN_ALIGN: usize = core::mem::align_of::<ArcInner<T>>();
+ const FOREIGN_ALIGN: usize = <KBox<ArcInner<T>> as ForeignOwnable>::FOREIGN_ALIGN;
type Borrowed<'a> = ArcBorrow<'a, T>;
type BorrowedMut<'a> = Self::Borrowed<'a>;
--
2.50.0.727.gbf7dc18ff4-goog
On Tue Jul 15, 2025 at 3:46 PM CEST, Alice Ryhl wrote: > When converting a Box<T> into a void pointer, the allocator might > guarantee a higher alignment than the type itself does, and in that case > it is guaranteed that the void pointer has that higher alignment. > > This is quite useful when combined with the XArray, which you can only > create using a ForeignOwnable whose FOREIGN_ALIGN is at least 4. This > means that you can now always use a Box<T> with the XArray no matter the > alignment of T. > > Signed-off-by: Alice Ryhl <aliceryhl@google.com> Hey this is cool! Reviewed-by: Benno Lossin <lossin@kernel.org> One question below. > --- > rust/kernel/alloc/kbox.rs | 15 +++++++++++---- > rust/kernel/sync/arc.rs | 6 +++--- > 2 files changed, 14 insertions(+), 7 deletions(-) > diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs > index 63a66761d0c7d752e09ce7372bc230661b2f7c6d..74121cf935f364c16799b5c31cc88714dfd6b702 100644 > --- a/rust/kernel/sync/arc.rs > +++ b/rust/kernel/sync/arc.rs > @@ -373,10 +373,10 @@ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> { > } > } > > -// SAFETY: The pointer returned by `into_foreign` comes from a well aligned > -// pointer to `ArcInner<T>`. > +// SAFETY: The pointer returned by `into_foreign` was originally allocated as an > +// `KBox<ArcInner<T>>`, so that type is what determines the alignment. > unsafe impl<T: 'static> ForeignOwnable for Arc<T> { > - const FOREIGN_ALIGN: usize = core::mem::align_of::<ArcInner<T>>(); > + const FOREIGN_ALIGN: usize = <KBox<ArcInner<T>> as ForeignOwnable>::FOREIGN_ALIGN; Do we at some point also want to give people the option to use vmalloc for `Arc`? --- Cheers, Benno > > type Borrowed<'a> = ArcBorrow<'a, T>; > type BorrowedMut<'a> = Self::Borrowed<'a>;
On Tue Jul 15, 2025 at 6:00 PM CEST, Benno Lossin wrote: > Do we at some point also want to give people the option to use vmalloc > for `Arc`? I'm not sure how useful that is. Typically, larger allocations (e.g. buffers) are members of smaller reference counted objects that manage their lifetime, etc.
On Tue Jul 15, 2025 at 3:46 PM CEST, Alice Ryhl wrote: > diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs > index bffe72f44cb33a265018e67d92d9f0abe82f8e22..fd3f1e0b9c3b3437fb50d8f1b28c92bc7cefd565 100644 > --- a/rust/kernel/alloc/kbox.rs > +++ b/rust/kernel/alloc/kbox.rs > @@ -400,12 +400,19 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> > } > > // SAFETY: The pointer returned by `into_foreign` comes from a well aligned > -// pointer to `T`. > +// pointer to `T` allocated by `A`. > unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A> > where > A: Allocator, > { > - const FOREIGN_ALIGN: usize = core::mem::align_of::<T>(); > + const FOREIGN_ALIGN: usize = { > + let mut align = core::mem::align_of::<T>(); > + if align < A::MIN_ALIGN { > + align = A::MIN_ALIGN; > + } > + align > + }; Pretty unfortunate that core::cmp::max() can't be used from const context. :( What do you think about const FOREIGN_ALIGN: usize = if core::mem::align_of::<T>() < A::MIN_ALIGN { A::MIN_ALIGN } else { core::mem::align_of::<T>() }; instead? I think that reads a bit better.
On Tue, Jul 15, 2025 at 4:19 PM Danilo Krummrich <dakr@kernel.org> wrote: > > On Tue Jul 15, 2025 at 3:46 PM CEST, Alice Ryhl wrote: > > diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs > > index bffe72f44cb33a265018e67d92d9f0abe82f8e22..fd3f1e0b9c3b3437fb50d8f1b28c92bc7cefd565 100644 > > --- a/rust/kernel/alloc/kbox.rs > > +++ b/rust/kernel/alloc/kbox.rs > > @@ -400,12 +400,19 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> > > } > > > > // SAFETY: The pointer returned by `into_foreign` comes from a well aligned > > -// pointer to `T`. > > +// pointer to `T` allocated by `A`. > > unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A> > > where > > A: Allocator, > > { > > - const FOREIGN_ALIGN: usize = core::mem::align_of::<T>(); > > + const FOREIGN_ALIGN: usize = { > > + let mut align = core::mem::align_of::<T>(); > > + if align < A::MIN_ALIGN { > > + align = A::MIN_ALIGN; > > + } > > + align > > + }; > > Pretty unfortunate that core::cmp::max() can't be used from const context. :( > > What do you think about > > const FOREIGN_ALIGN: usize = > if core::mem::align_of::<T>() < A::MIN_ALIGN { > A::MIN_ALIGN > } else { > core::mem::align_of::<T>() > }; > > instead? I think that reads a bit better. I don't mind doing that instead. Alice
© 2016 - 2025 Red Hat, Inc.