[PATCH] rust: alloc: allow different error types in `KBox::pin_slice`

Andreas Hindborg posted 1 patch 1 month, 2 weeks ago
rust/kernel/alloc/kbox.rs | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
[PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Andreas Hindborg 1 month, 2 weeks ago
Previously, `KBox::pin_slice` required the initializer error type to match
the return error type via `E: From<AllocError>`. This prevented using
infallible initializers like `new_mutex!` inside `pin_slice`, because
`Infallible` does not implement `From<AllocError>`.

Introduce a separate type parameter `E2` for the initializer error type and
require `AllocError: Into<E>` and `E2: Into<E>` instead. This allows the
initializer to return a different error type that can be converted into the
final error type, enabling use of infallible pin initializers in fallible
allocation contexts.

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
@Benno, I would like to add your SoB and CDB tags.
---
 rust/kernel/alloc/kbox.rs | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index 622b3529edfcb..8dbc58b988f1c 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -323,7 +323,7 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
     /// }
     ///
     /// // Allocate a boxed slice of 10 `Example`s.
-    /// let s = KBox::pin_slice(
+    /// let s = KBox::pin_slice::<_, _, Error, _>(
     ///     | _i | Example::new(),
     ///     10,
     ///     GFP_KERNEL
@@ -333,24 +333,31 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
     /// assert_eq!(s[3].d.lock().a, 20);
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn pin_slice<Func, Item, E>(
+    pub fn pin_slice<Func, Item, E, E2>(
         mut init: Func,
         len: usize,
         flags: Flags,
     ) -> Result<Pin<Box<[T], A>>, E>
     where
         Func: FnMut(usize) -> Item,
-        Item: PinInit<T, E>,
-        E: From<AllocError>,
+        Item: PinInit<T, E2>,
+        AllocError: Into<E>,
+        E2: Into<E>,
     {
-        let mut buffer = super::Vec::<T, A>::with_capacity(len, flags)?;
+        let mut buffer = match super::Vec::<T, A>::with_capacity(len, flags) {
+            Ok(buffer) => buffer,
+            Err(err) => return Err(err.into()),
+        };
         for i in 0..len {
             let ptr = buffer.spare_capacity_mut().as_mut_ptr().cast();
             // SAFETY:
             // - `ptr` is a valid pointer to uninitialized memory.
             // - `ptr` is not used if an error is returned.
             // - `ptr` won't be moved until it is dropped, i.e. it is pinned.
-            unsafe { init(i).__pinned_init(ptr)? };
+            match unsafe { init(i).__pinned_init(ptr) } {
+                Ok(()) => (),
+                Err(err) => return Err(err.into()),
+            }
 
             // SAFETY:
             // - `i + 1 <= len`, hence we don't exceed the capacity, due to the call to

---
base-commit: 05f7e89ab9731565d8a62e3b5d1ec206485eeb0b
change-id: 20260214-pin-slice-init-e8ef96fc07b9

Best regards,
-- 
Andreas Hindborg <a.hindborg@kernel.org>
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Danilo Krummrich 1 month, 2 weeks ago
On Sat Feb 14, 2026 at 2:28 PM CET, Andreas Hindborg wrote:
> Previously, `KBox::pin_slice` required the initializer error type to match
> the return error type via `E: From<AllocError>`. This prevented using
> infallible initializers like `new_mutex!` inside `pin_slice`, because
> `Infallible` does not implement `From<AllocError>`.
>
> Introduce a separate type parameter `E2` for the initializer error type and
> require `AllocError: Into<E>` and `E2: Into<E>` instead. This allows the
> initializer to return a different error type that can be converted into the
> final error type, enabling use of infallible pin initializers in fallible
> allocation contexts.
>
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>

I assume you have a user? I.e. do you need this patch in another tree?

> @@ -333,24 +333,31 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
>      /// assert_eq!(s[3].d.lock().a, 20);
>      /// # Ok::<(), Error>(())
>      /// ```
> -    pub fn pin_slice<Func, Item, E>(
> +    pub fn pin_slice<Func, Item, E, E2>(
>          mut init: Func,
>          len: usize,
>          flags: Flags,
>      ) -> Result<Pin<Box<[T], A>>, E>
>      where
>          Func: FnMut(usize) -> Item,
> -        Item: PinInit<T, E>,
> -        E: From<AllocError>,

I think we should keep this bound and just add:

	E: From<E2>,

> +        Item: PinInit<T, E2>,
> +        AllocError: Into<E>,
> +        E2: Into<E>,
>      {
> -        let mut buffer = super::Vec::<T, A>::with_capacity(len, flags)?;
> +        let mut buffer = match super::Vec::<T, A>::with_capacity(len, flags) {
> +            Ok(buffer) => buffer,
> +            Err(err) => return Err(err.into()),
> +        };

This...

>          for i in 0..len {
>              let ptr = buffer.spare_capacity_mut().as_mut_ptr().cast();
>              // SAFETY:
>              // - `ptr` is a valid pointer to uninitialized memory.
>              // - `ptr` is not used if an error is returned.
>              // - `ptr` won't be moved until it is dropped, i.e. it is pinned.
> -            unsafe { init(i).__pinned_init(ptr)? };
> +            match unsafe { init(i).__pinned_init(ptr) } {
> +                Ok(()) => (),
> +                Err(err) => return Err(err.into()),
> +            }

...and this match becomes unnecessary then.
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Benno Lossin 1 month, 2 weeks ago
On Sat Feb 14, 2026 at 3:17 PM CET, Danilo Krummrich wrote:
> On Sat Feb 14, 2026 at 2:28 PM CET, Andreas Hindborg wrote:
>> @@ -333,24 +333,31 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
>>      /// assert_eq!(s[3].d.lock().a, 20);
>>      /// # Ok::<(), Error>(())
>>      /// ```
>> -    pub fn pin_slice<Func, Item, E>(
>> +    pub fn pin_slice<Func, Item, E, E2>(
>>          mut init: Func,
>>          len: usize,
>>          flags: Flags,
>>      ) -> Result<Pin<Box<[T], A>>, E>
>>      where
>>          Func: FnMut(usize) -> Item,
>> -        Item: PinInit<T, E>,
>> -        E: From<AllocError>,
>
> I think we should keep this bound and just add:

The `Into` trait bounds are the idiomatic ones for functions consuming
things. See https://doc.rust-lang.org/std/convert/trait.Into.html:

    Prefer using Into over From when specifying trait bounds on a
    generic function to ensure that types that only implement Into can
    be used as well.

I should've said something to Andreas, since he created the commit
message (but this patch has left my L3 cache).

Cheers,
Benno

> 	E: From<E2>,
>
>> +        Item: PinInit<T, E2>,
>> +        AllocError: Into<E>,
>> +        E2: Into<E>,
>>      {
>> -        let mut buffer = super::Vec::<T, A>::with_capacity(len, flags)?;
>> +        let mut buffer = match super::Vec::<T, A>::with_capacity(len, flags) {
>> +            Ok(buffer) => buffer,
>> +            Err(err) => return Err(err.into()),
>> +        };
>
> This...
>
>>          for i in 0..len {
>>              let ptr = buffer.spare_capacity_mut().as_mut_ptr().cast();
>>              // SAFETY:
>>              // - `ptr` is a valid pointer to uninitialized memory.
>>              // - `ptr` is not used if an error is returned.
>>              // - `ptr` won't be moved until it is dropped, i.e. it is pinned.
>> -            unsafe { init(i).__pinned_init(ptr)? };
>> +            match unsafe { init(i).__pinned_init(ptr) } {
>> +                Ok(()) => (),
>> +                Err(err) => return Err(err.into()),
>> +            }
>
> ...and this match becomes unnecessary then.
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Danilo Krummrich 1 month, 2 weeks ago
On Sat Feb 14, 2026 at 3:40 PM CET, Benno Lossin wrote:
> On Sat Feb 14, 2026 at 3:17 PM CET, Danilo Krummrich wrote:
>> On Sat Feb 14, 2026 at 2:28 PM CET, Andreas Hindborg wrote:
>>> @@ -333,24 +333,31 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
>>>      /// assert_eq!(s[3].d.lock().a, 20);
>>>      /// # Ok::<(), Error>(())
>>>      /// ```
>>> -    pub fn pin_slice<Func, Item, E>(
>>> +    pub fn pin_slice<Func, Item, E, E2>(
>>>          mut init: Func,
>>>          len: usize,
>>>          flags: Flags,
>>>      ) -> Result<Pin<Box<[T], A>>, E>
>>>      where
>>>          Func: FnMut(usize) -> Item,
>>> -        Item: PinInit<T, E>,
>>> -        E: From<AllocError>,
>>
>> I think we should keep this bound and just add:
>
> The `Into` trait bounds are the idiomatic ones for functions consuming
> things. See https://doc.rust-lang.org/std/convert/trait.Into.html:
>
>     Prefer using Into over From when specifying trait bounds on a
>     generic function to ensure that types that only implement Into can
>     be used as well.

Yeah, but isn't this only because of [1], which does not apply to the kernel
because our minimum compiler version is 1.78 anyways?

I.e. are there any cases where we can't implement From in the kernel and have to
fall back to Into?

[1] https://doc.rust-lang.org/std/convert/trait.Into.html#implementing-into-for-conversions-to-external-types-in-old-versions-of-rust
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Gary Guo 1 month ago
On Sat Feb 14, 2026 at 2:56 PM GMT, Danilo Krummrich wrote:
> On Sat Feb 14, 2026 at 3:40 PM CET, Benno Lossin wrote:
>> On Sat Feb 14, 2026 at 3:17 PM CET, Danilo Krummrich wrote:
>>> On Sat Feb 14, 2026 at 2:28 PM CET, Andreas Hindborg wrote:
>>>> @@ -333,24 +333,31 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
>>>>      /// assert_eq!(s[3].d.lock().a, 20);
>>>>      /// # Ok::<(), Error>(())
>>>>      /// ```
>>>> -    pub fn pin_slice<Func, Item, E>(
>>>> +    pub fn pin_slice<Func, Item, E, E2>(
>>>>          mut init: Func,
>>>>          len: usize,
>>>>          flags: Flags,
>>>>      ) -> Result<Pin<Box<[T], A>>, E>
>>>>      where
>>>>          Func: FnMut(usize) -> Item,
>>>> -        Item: PinInit<T, E>,
>>>> -        E: From<AllocError>,
>>>
>>> I think we should keep this bound and just add:
>>
>> The `Into` trait bounds are the idiomatic ones for functions consuming
>> things. See https://doc.rust-lang.org/std/convert/trait.Into.html:
>>
>>     Prefer using Into over From when specifying trait bounds on a
>>     generic function to ensure that types that only implement Into can
>>     be used as well.
>
> Yeah, but isn't this only because of [1], which does not apply to the kernel
> because our minimum compiler version is 1.78 anyways?
>
> I.e. are there any cases where we can't implement From in the kernel and have to
> fall back to Into?
>
> [1] https://doc.rust-lang.org/std/convert/trait.Into.html#implementing-into-for-conversions-to-external-types-in-old-versions-of-rust

There's one benefit in using `From` in trait bound -- you can call both `From::from`
and `Into::into` inside the function. If you only have `Into` bound, then
`From::from` is not callable. A very minor benefit, though.

Another interesting observation is that `?` operator (i.e. impl of the unstable
`FromResidual` trait on `Result`) uses `From` instead of `Into`. I cannot find a
reason why this is done this way, though.

Best,
Gary
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Alice Ryhl 1 month, 2 weeks ago
On Sat, Feb 14, 2026 at 03:56:43PM +0100, Danilo Krummrich wrote:
> On Sat Feb 14, 2026 at 3:40 PM CET, Benno Lossin wrote:
> > On Sat Feb 14, 2026 at 3:17 PM CET, Danilo Krummrich wrote:
> >> On Sat Feb 14, 2026 at 2:28 PM CET, Andreas Hindborg wrote:
> >>> @@ -333,24 +333,31 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
> >>>      /// assert_eq!(s[3].d.lock().a, 20);
> >>>      /// # Ok::<(), Error>(())
> >>>      /// ```
> >>> -    pub fn pin_slice<Func, Item, E>(
> >>> +    pub fn pin_slice<Func, Item, E, E2>(
> >>>          mut init: Func,
> >>>          len: usize,
> >>>          flags: Flags,
> >>>      ) -> Result<Pin<Box<[T], A>>, E>
> >>>      where
> >>>          Func: FnMut(usize) -> Item,
> >>> -        Item: PinInit<T, E>,
> >>> -        E: From<AllocError>,
> >>
> >> I think we should keep this bound and just add:
> >
> > The `Into` trait bounds are the idiomatic ones for functions consuming
> > things. See https://doc.rust-lang.org/std/convert/trait.Into.html:
> >
> >     Prefer using Into over From when specifying trait bounds on a
> >     generic function to ensure that types that only implement Into can
> >     be used as well.
> 
> Yeah, but isn't this only because of [1], which does not apply to the kernel
> because our minimum compiler version is 1.78 anyways?
> 
> I.e. are there any cases where we can't implement From in the kernel and have to
> fall back to Into?

Probably not, but it's still best practice to use Into over From when
specifying trait bounds.

Alice
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Danilo Krummrich 1 month, 2 weeks ago
On Mon Feb 16, 2026 at 9:48 AM CET, Alice Ryhl wrote:
> On Sat, Feb 14, 2026 at 03:56:43PM +0100, Danilo Krummrich wrote:
>> Yeah, but isn't this only because of [1], which does not apply to the kernel
>> because our minimum compiler version is 1.78 anyways?
>> 
>> I.e. are there any cases where we can't implement From in the kernel and have to
>> fall back to Into?
>
> Probably not, but it's still best practice to use Into over From when
> specifying trait bounds.

I'm aware; my point is that I'm questioning this best practice in the context of
a modern and self-contained project like Rust in the kernel.

This patch is a very good example, as there seem to be zero downsides to a From
trait bound, while using the From trait bound allows for cleaner code.

(I.e. we get rid of the matches and can use the '?' operator instead. To be
fair, this could also be written as `.map_err(Into::into)?`, but still.)

I'd even argue that using a From trait bound here is a feature and not a
limitation. I.e. if someone would pass something that implements Into (but not
From) we'd catch it and can tell the caller to implement From instead of Into,
which is preferred and should always be possible in the kernel.
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Benno Lossin 1 month, 2 weeks ago
On Sat Feb 14, 2026 at 3:56 PM CET, Danilo Krummrich wrote:
> On Sat Feb 14, 2026 at 3:40 PM CET, Benno Lossin wrote:
>> On Sat Feb 14, 2026 at 3:17 PM CET, Danilo Krummrich wrote:
>>> On Sat Feb 14, 2026 at 2:28 PM CET, Andreas Hindborg wrote:
>>>> @@ -333,24 +333,31 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
>>>>      /// assert_eq!(s[3].d.lock().a, 20);
>>>>      /// # Ok::<(), Error>(())
>>>>      /// ```
>>>> -    pub fn pin_slice<Func, Item, E>(
>>>> +    pub fn pin_slice<Func, Item, E, E2>(
>>>>          mut init: Func,
>>>>          len: usize,
>>>>          flags: Flags,
>>>>      ) -> Result<Pin<Box<[T], A>>, E>
>>>>      where
>>>>          Func: FnMut(usize) -> Item,
>>>> -        Item: PinInit<T, E>,
>>>> -        E: From<AllocError>,
>>>
>>> I think we should keep this bound and just add:
>>
>> The `Into` trait bounds are the idiomatic ones for functions consuming
>> things. See https://doc.rust-lang.org/std/convert/trait.Into.html:
>>
>>     Prefer using Into over From when specifying trait bounds on a
>>     generic function to ensure that types that only implement Into can
>>     be used as well.
>
> Yeah, but isn't this only because of [1], which does not apply to the kernel
> because our minimum compiler version is 1.78 anyways?
>
> I.e. are there any cases where we can't implement From in the kernel and have to
> fall back to Into?

Hmm that's interesting. I'm not sure if that's the only reason. It would
be interesting to ask the Rust folks if there 1) is a different use-case
for `Into` today; and 2) if they could remove `Into`, would they? If the
answer to 2 is "yes", then we could think about doing that (or at least
document it for us).

Cheers,
Benno

>
> [1] https://doc.rust-lang.org/std/convert/trait.Into.html#implementing-into-for-conversions-to-external-types-in-old-versions-of-rust
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Benno Lossin 1 month, 2 weeks ago
On Sat Feb 14, 2026 at 2:28 PM CET, Andreas Hindborg wrote:
> Previously, `KBox::pin_slice` required the initializer error type to match
> the return error type via `E: From<AllocError>`. This prevented using
> infallible initializers like `new_mutex!` inside `pin_slice`, because
> `Infallible` does not implement `From<AllocError>`.
>
> Introduce a separate type parameter `E2` for the initializer error type and
> require `AllocError: Into<E>` and `E2: Into<E>` instead. This allows the
> initializer to return a different error type that can be converted into the
> final error type, enabling use of infallible pin initializers in fallible
> allocation contexts.
>
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
> ---
> @Benno, I would like to add your SoB and CDB tags.

Please do.

Cheers,
Benno

> ---
>  rust/kernel/alloc/kbox.rs | 19 +++++++++++++------
>  1 file changed, 13 insertions(+), 6 deletions(-)
Re: [PATCH] rust: alloc: allow different error types in `KBox::pin_slice`
Posted by Andreas Hindborg 1 month, 2 weeks ago
Andreas Hindborg <a.hindborg@kernel.org> writes:

> Previously, `KBox::pin_slice` required the initializer error type to match
> the return error type via `E: From<AllocError>`. This prevented using
> infallible initializers like `new_mutex!` inside `pin_slice`, because
> `Infallible` does not implement `From<AllocError>`.
>
> Introduce a separate type parameter `E2` for the initializer error type and
> require `AllocError: Into<E>` and `E2: Into<E>` instead. This allows the
> initializer to return a different error type that can be converted into the
> final error type, enabling use of infallible pin initializers in fallible
> allocation contexts.
>
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
> ---
> @Benno, I would like to add your SoB and CDB tags.

It just occured to me that we should probably add a zulip Link as well:

Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/.E2.9C.94.20Constructing.20Mutex.20from.20PinInit.3CT.2C.20Error.3E/with/567385936


Best regards,
Andreas Hindborg