[PATCH] rust: sync: Accept errors for Lock payload data

Philipp Stanner posted 1 patch 2 hours ago
rust/kernel/sync/lock.rs          | 21 ++++++++++++++-------
rust/kernel/sync/lock/mutex.rs    |  7 ++++---
rust/kernel/sync/lock/spinlock.rs | 20 ++++++++++----------
3 files changed, 28 insertions(+), 20 deletions(-)
[PATCH] rust: sync: Accept errors for Lock payload data
Posted by Philipp Stanner 2 hours ago
The `Lock` baseclass currently does not allow for fallible user-data.
This can cause conflicts when used with other primitives, for example
when a lock shall be pin-initialized with payload data that is fallible.

Add support for the lock base class so that it works with
try_pin_init!(). Adjust spinlock and mutex accordingly.

Signed-off-by: Philipp Stanner <phasta@kernel.org>
---
Regarding removal of the CStrExt, I got "unused import" errors because
of it. Don't fully understand why?

P.
---
 rust/kernel/sync/lock.rs          | 21 ++++++++++++++-------
 rust/kernel/sync/lock/mutex.rs    |  7 ++++---
 rust/kernel/sync/lock/spinlock.rs | 20 ++++++++++----------
 3 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs
index 10b6b5e9b024..1b2df5d0dcf9 100644
--- a/rust/kernel/sync/lock.rs
+++ b/rust/kernel/sync/lock.rs
@@ -7,11 +7,13 @@
 
 use super::LockClassKey;
 use crate::{
-    str::{CStr, CStrExt as _},
+    str::CStr,
     types::{NotThreadSafe, Opaque, ScopeGuard},
 };
 use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
-use pin_init::{pin_data, pin_init, PinInit, Wrapper};
+use pin_init::{pin_data, PinInit, Wrapper};
+
+use kernel::prelude::*;
 
 pub mod mutex;
 pub mod spinlock;
@@ -126,14 +128,19 @@ unsafe impl<T: ?Sized + Send, B: Backend> Send for Lock<T, B> {}
 // data it protects is `Send`.
 unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
 
+use core::convert::Infallible;
+
 impl<T, B: Backend> Lock<T, B> {
     /// Constructs a new lock initialiser.
-    pub fn new(
-        t: impl PinInit<T>,
+    pub fn new<E>(
+        t: impl PinInit<T, E>,
         name: &'static CStr,
         key: Pin<&'static LockClassKey>,
-    ) -> impl PinInit<Self> {
-        pin_init!(Self {
+    ) -> impl PinInit<Self, E>
+    where
+        E: From<Infallible>,
+    {
+        try_pin_init!(Self {
             data <- UnsafeCell::pin_init(t),
             _pin: PhantomPinned,
             // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
@@ -141,7 +148,7 @@ pub fn new(
             state <- Opaque::ffi_init(|slot| unsafe {
                 B::init(slot, name.as_char_ptr(), key.as_ptr())
             }),
-        })
+        }? E)
     }
 }
 
diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs
index cda0203efefb..35e6b02ff426 100644
--- a/rust/kernel/sync/lock/mutex.rs
+++ b/rust/kernel/sync/lock/mutex.rs
@@ -35,6 +35,7 @@ macro_rules! new_mutex {
 ///
 /// ```
 /// use kernel::sync::{new_mutex, Mutex};
+/// use kernel::prelude::*;
 ///
 /// struct Inner {
 ///     a: u32,
@@ -49,8 +50,8 @@ macro_rules! new_mutex {
 /// }
 ///
 /// impl Example {
-///     fn new() -> impl PinInit<Self> {
-///         pin_init!(Self {
+///     fn new() -> impl PinInit<Self, Error> {
+///         try_pin_init!(Self {
 ///             c: 10,
 ///             d <- new_mutex!(Inner { a: 20, b: 30 }),
 ///         })
@@ -58,7 +59,7 @@ macro_rules! new_mutex {
 /// }
 ///
 /// // Allocate a boxed `Example`.
-/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
+/// let e = KBox::try_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 aafc80125f59..8ea2c5b202e6 100644
--- a/rust/kernel/sync/lock/spinlock.rs
+++ b/rust/kernel/sync/lock/spinlock.rs
@@ -4,10 +4,7 @@
 //!
 //! This module allows Rust code to use the kernel's `spinlock_t`.
 use super::*;
-use crate::{
-    interrupt::LocalInterruptDisabled,
-    prelude::*, //
-};
+use crate::interrupt::LocalInterruptDisabled;
 
 /// Creates a [`SpinLock`] initialiser with the given name and a newly-created lock class.
 ///
@@ -38,6 +35,7 @@ macro_rules! new_spinlock {
 ///
 /// ```
 /// use kernel::sync::{new_spinlock, SpinLock};
+/// use kernel::prelude::*;
 ///
 /// struct Inner {
 ///     a: u32,
@@ -52,8 +50,8 @@ macro_rules! new_spinlock {
 /// }
 ///
 /// impl Example {
-///     fn new() -> impl PinInit<Self> {
-///         pin_init!(Self {
+///     fn new() -> impl PinInit<Self, Error> {
+///         try_pin_init!(Self {
 ///             c: 10,
 ///             d <- new_spinlock!(Inner { a: 20, b: 30 }),
 ///         })
@@ -184,6 +182,7 @@ macro_rules! new_spinlock_irq {
 ///
 /// ```
 /// use kernel::sync::{new_spinlock_irq, SpinLockIrq};
+/// use kernel::prelude::*;
 ///
 /// struct Inner {
 ///     a: u32,
@@ -199,8 +198,8 @@ macro_rules! new_spinlock_irq {
 /// }
 ///
 /// impl Example {
-///     fn new() -> impl PinInit<Self> {
-///         pin_init!(Self {
+///     fn new() -> impl PinInit<Self, Error> {
+///         try_pin_init!(Self {
 ///             c <- new_spinlock_irq!(Inner { a: 0, b: 10 }),
 ///             d <- new_spinlock_irq!(Inner { a: 20, b: 30 }),
 ///         })
@@ -232,6 +231,7 @@ macro_rules! new_spinlock_irq {
 /// ```
 /// use kernel::sync::{new_spinlock_irq, SpinLockIrq};
 /// use kernel::interrupt::*;
+/// use kernel::prelude::*;
 ///
 /// struct Inner {
 ///     a: u32,
@@ -244,8 +244,8 @@ macro_rules! new_spinlock_irq {
 /// }
 ///
 /// impl Example {
-///     fn new() -> impl PinInit<Self> {
-///         pin_init!(Self {
+///     fn new() -> impl PinInit<Self, Error> {
+///         try_pin_init!(Self {
 ///             inner <- new_spinlock_irq!(Inner { a: 20 }),
 ///         })
 ///     }
-- 
2.55.0
Re: [PATCH] rust: sync: Accept errors for Lock payload data
Posted by Gary Guo 34 minutes ago
On Thu Sep 24, 2026 at 9:55 AM BST, Philipp Stanner wrote:
> The `Lock` baseclass currently does not allow for fallible user-data.
> This can cause conflicts when used with other primitives, for example
> when a lock shall be pin-initialized with payload data that is fallible.
>
> Add support for the lock base class so that it works with
> try_pin_init!(). Adjust spinlock and mutex accordingly.
>
> Signed-off-by: Philipp Stanner <phasta@kernel.org>
> ---
> Regarding removal of the CStrExt, I got "unused import" errors because
> of it. Don't fully understand why?

Because it's part of the prelude.

>
> P.
> ---
>  rust/kernel/sync/lock.rs          | 21 ++++++++++++++-------
>  rust/kernel/sync/lock/mutex.rs    |  7 ++++---
>  rust/kernel/sync/lock/spinlock.rs | 20 ++++++++++----------
>  3 files changed, 28 insertions(+), 20 deletions(-)
>
> diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs
> index 10b6b5e9b024..1b2df5d0dcf9 100644
> --- a/rust/kernel/sync/lock.rs
> +++ b/rust/kernel/sync/lock.rs
> @@ -7,11 +7,13 @@
>  
>  use super::LockClassKey;
>  use crate::{
> -    str::{CStr, CStrExt as _},
> +    str::CStr,
>      types::{NotThreadSafe, Opaque, ScopeGuard},
>  };
>  use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
> -use pin_init::{pin_data, pin_init, PinInit, Wrapper};
> +use pin_init::{pin_data, PinInit, Wrapper};
> +
> +use kernel::prelude::*;
>  
>  pub mod mutex;
>  pub mod spinlock;
> @@ -126,14 +128,19 @@ unsafe impl<T: ?Sized + Send, B: Backend> Send for Lock<T, B> {}
>  // data it protects is `Send`.
>  unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
>  
> +use core::convert::Infallible;
> +
>  impl<T, B: Backend> Lock<T, B> {
>      /// Constructs a new lock initialiser.
> -    pub fn new(
> -        t: impl PinInit<T>,
> +    pub fn new<E>(
> +        t: impl PinInit<T, E>,
>          name: &'static CStr,
>          key: Pin<&'static LockClassKey>,
> -    ) -> impl PinInit<Self> {
> -        pin_init!(Self {
> +    ) -> impl PinInit<Self, E>
> +    where
> +        E: From<Infallible>,
> +    {
> +        try_pin_init!(Self {

FWIW if `? E` is specified, both `pin_init!` and `try_pin_init!` behave the
same, so there no need to change it here.

The difference between these two macros are the default error type; the former is
`Infallible` and the latter is `kernel::error::Error`.

>              data <- UnsafeCell::pin_init(t),
>              _pin: PhantomPinned,
>              // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
> @@ -141,7 +148,7 @@ pub fn new(
>              state <- Opaque::ffi_init(|slot| unsafe {
>                  B::init(slot, name.as_char_ptr(), key.as_ptr())
>              }),
> -        })
> +        }? E)
>      }
>  }
>  
> diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs
> index cda0203efefb..35e6b02ff426 100644
> --- a/rust/kernel/sync/lock/mutex.rs
> +++ b/rust/kernel/sync/lock/mutex.rs
> @@ -35,6 +35,7 @@ macro_rules! new_mutex {
>  ///
>  /// ```
>  /// use kernel::sync::{new_mutex, Mutex};
> +/// use kernel::prelude::*;
>  ///
>  /// struct Inner {
>  ///     a: u32,
> @@ -49,8 +50,8 @@ macro_rules! new_mutex {
>  /// }
>  ///
>  /// impl Example {
> -///     fn new() -> impl PinInit<Self> {
> -///         pin_init!(Self {
> +///     fn new() -> impl PinInit<Self, Error> {
> +///         try_pin_init!(Self {
>  ///             c: 10,
>  ///             d <- new_mutex!(Inner { a: 20, b: 30 }),
>  ///         })
> @@ -58,7 +59,7 @@ macro_rules! new_mutex {
>  /// }
>  ///
>  /// // Allocate a boxed `Example`.
> -/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
> +/// let e = KBox::try_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 aafc80125f59..8ea2c5b202e6 100644
> --- a/rust/kernel/sync/lock/spinlock.rs
> +++ b/rust/kernel/sync/lock/spinlock.rs
> @@ -4,10 +4,7 @@
>  //!
>  //! This module allows Rust code to use the kernel's `spinlock_t`.
>  use super::*;
> -use crate::{
> -    interrupt::LocalInterruptDisabled,
> -    prelude::*, //
> -};
> +use crate::interrupt::LocalInterruptDisabled;
>  
>  /// Creates a [`SpinLock`] initialiser with the given name and a newly-created lock class.
>  ///
> @@ -38,6 +35,7 @@ macro_rules! new_spinlock {
>  ///
>  /// ```
>  /// use kernel::sync::{new_spinlock, SpinLock};
> +/// use kernel::prelude::*;

Doctests have prelude imported by default.

Best,
Gary


>  ///
>  /// struct Inner {
>  ///     a: u32,
> @@ -52,8 +50,8 @@ macro_rules! new_spinlock {
>  /// }
>  ///
>  /// impl Example {
> -///     fn new() -> impl PinInit<Self> {
> -///         pin_init!(Self {
> +///     fn new() -> impl PinInit<Self, Error> {
> +///         try_pin_init!(Self {
>  ///             c: 10,
>  ///             d <- new_spinlock!(Inner { a: 20, b: 30 }),
>  ///         })
> @@ -184,6 +182,7 @@ macro_rules! new_spinlock_irq {
>  ///
>  /// ```
>  /// use kernel::sync::{new_spinlock_irq, SpinLockIrq};
> +/// use kernel::prelude::*;
>  ///
>  /// struct Inner {
>  ///     a: u32,
> @@ -199,8 +198,8 @@ macro_rules! new_spinlock_irq {
>  /// }
>  ///
>  /// impl Example {
> -///     fn new() -> impl PinInit<Self> {
> -///         pin_init!(Self {
> +///     fn new() -> impl PinInit<Self, Error> {
> +///         try_pin_init!(Self {
>  ///             c <- new_spinlock_irq!(Inner { a: 0, b: 10 }),
>  ///             d <- new_spinlock_irq!(Inner { a: 20, b: 30 }),
>  ///         })
> @@ -232,6 +231,7 @@ macro_rules! new_spinlock_irq {
>  /// ```
>  /// use kernel::sync::{new_spinlock_irq, SpinLockIrq};
>  /// use kernel::interrupt::*;
> +/// use kernel::prelude::*;
>  ///
>  /// struct Inner {
>  ///     a: u32,
> @@ -244,8 +244,8 @@ macro_rules! new_spinlock_irq {
>  /// }
>  ///
>  /// impl Example {
> -///     fn new() -> impl PinInit<Self> {
> -///         pin_init!(Self {
> +///     fn new() -> impl PinInit<Self, Error> {
> +///         try_pin_init!(Self {
>  ///             inner <- new_spinlock_irq!(Inner { a: 20 }),
>  ///         })
>  ///     }