* [PATCH v2 0/2] Clean up Rust LockClassKey
@ 2025-07-28 9:42 Alice Ryhl
2025-07-28 9:42 ` [PATCH v2 1/2] rust: sync: refactor static_lock_class!() macro Alice Ryhl
2025-07-28 9:42 ` [PATCH v2 2/2] rust: sync: clean up LockClassKey and its docs Alice Ryhl
0 siblings, 2 replies; 6+ messages in thread
From: Alice Ryhl @ 2025-07-28 9:42 UTC (permalink / raw)
To: Boqun Feng, Miguel Ojeda
Cc: Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Daniel Almeida, rust-for-linux,
linux-kernel, Alice Ryhl
This series applies the suggestion from Benno [1] and various other
improvements I found when looking over the LockClassKey implementation.
Based on rust-next.
[1]: https://lore.kernel.org/all/DBIJLR7XNI6U.21PMPODHE83DZ@kernel.org/
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Changes in v2:
- Change safety comment to require a static object. Adjust commit
message accordingly.
- Add Reviewed-by.
- Link to v1: https://lore.kernel.org/r/20250723-lock-class-key-cleanup-v1-0-85fa506b8ca4@google.com
---
Alice Ryhl (2):
rust: sync: refactor static_lock_class!() macro
rust: sync: clean up LockClassKey and its docs
rust/kernel/sync.rs | 78 +++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 58 insertions(+), 20 deletions(-)
---
base-commit: dff64b072708ffef23c117fa1ee1ea59eb417807
change-id: 20250723-lock-class-key-cleanup-a3baf53b123a
Best regards,
--
Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] rust: sync: refactor static_lock_class!() macro
2025-07-28 9:42 [PATCH v2 0/2] Clean up Rust LockClassKey Alice Ryhl
@ 2025-07-28 9:42 ` Alice Ryhl
2025-07-28 10:18 ` Benno Lossin
2025-07-28 9:42 ` [PATCH v2 2/2] rust: sync: clean up LockClassKey and its docs Alice Ryhl
1 sibling, 1 reply; 6+ messages in thread
From: Alice Ryhl @ 2025-07-28 9:42 UTC (permalink / raw)
To: Boqun Feng, Miguel Ojeda
Cc: Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Daniel Almeida, rust-for-linux,
linux-kernel, Alice Ryhl
By introducing a new_static() constructor, the macro does not need to go
through MaybeUninit::uninit().assume_init(), which is a pattern that is
best avoided when possible.
The safety comment requires not only requires that the value is leaked,
but also that it is stored in the right portion of memory. This is so
that the lockdep static_obj() check will succeed when using this
constructor. One could argue that lockdep detects this scenario, so the
safety comment isn't needed. However, it simplifies matters to require
that static_obj() will succeed and it's not a burdensome requirement on
the caller.
Suggested-by: Benno Lossin <lossin@kernel.org>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
rust/kernel/sync.rs | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index 00f9b558a3ade19e442b32b46d05885b67e1d830..2c04a3806ca885637583fde336d054426f569fe5 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -39,6 +39,21 @@ pub struct LockClassKey {
unsafe impl Sync for LockClassKey {}
impl LockClassKey {
+ /// Initializes a statically allocated lock class key.
+ ///
+ /// This is usually used indirectly through the [`static_lock_class!`] macro.
+ ///
+ /// # Safety
+ ///
+ /// * Before using the returned value, it must be pinned in a static memory location.
+ /// * The destructor must never run on the returned `LockClassKey`.
+ #[doc(hidden)]
+ pub const unsafe fn new_static() -> Self {
+ LockClassKey {
+ inner: Opaque::uninit(),
+ }
+ }
+
/// Initializes a dynamically allocated lock class key. In the common case of using a
/// statically allocated lock class key, the static_lock_class! macro should be used instead.
///
@@ -95,13 +110,11 @@ fn drop(self: Pin<&mut Self>) {
#[macro_export]
macro_rules! static_lock_class {
() => {{
- static CLASS: $crate::sync::LockClassKey =
- // Lockdep expects uninitialized memory when it's handed a statically allocated `struct
- // lock_class_key`.
- //
- // SAFETY: `LockClassKey` transparently wraps `Opaque` which permits uninitialized
- // memory.
- unsafe { ::core::mem::MaybeUninit::uninit().assume_init() };
+ // SAFETY: The returned `LockClassKey` is stored in static memory. Drop never runs on a
+ // static global.
+ static CLASS: $crate::sync::LockClassKey = unsafe {
+ $crate::sync::LockClassKey::new_static()
+ };
$crate::prelude::Pin::static_ref(&CLASS)
}};
}
--
2.50.1.470.g6ba607880d-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] rust: sync: clean up LockClassKey and its docs
2025-07-28 9:42 [PATCH v2 0/2] Clean up Rust LockClassKey Alice Ryhl
2025-07-28 9:42 ` [PATCH v2 1/2] rust: sync: refactor static_lock_class!() macro Alice Ryhl
@ 2025-07-28 9:42 ` Alice Ryhl
2025-08-12 8:05 ` Benno Lossin
1 sibling, 1 reply; 6+ messages in thread
From: Alice Ryhl @ 2025-07-28 9:42 UTC (permalink / raw)
To: Boqun Feng, Miguel Ojeda
Cc: Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Daniel Almeida, rust-for-linux,
linux-kernel, Alice Ryhl
Several aspects of the code and documentation for this type is
incomplete. Also several things are hidden from the docs. Thus, clean it
up and make it easier to read the rendered html docs.
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
rust/kernel/sync.rs | 55 ++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 40 insertions(+), 15 deletions(-)
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index 2c04a3806ca885637583fde336d054426f569fe5..66d0a3c2f92d76213bc7fdb7b86d54d4835aee79 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -26,7 +26,9 @@
pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard};
pub use locked_by::LockedBy;
-/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
+/// Represents a lockdep class.
+///
+/// Wraps the kernel's `struct lock_class_key`.
#[repr(transparent)]
#[pin_data(PinnedDrop)]
pub struct LockClassKey {
@@ -34,6 +36,10 @@ pub struct LockClassKey {
inner: Opaque<bindings::lock_class_key>,
}
+// SAFETY: Unregistering a lock class key from a different thread than where it was registered is
+// allowed.
+unsafe impl Send for LockClassKey {}
+
// SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and
// provides its own synchronization.
unsafe impl Sync for LockClassKey {}
@@ -41,29 +47,31 @@ unsafe impl Sync for LockClassKey {}
impl LockClassKey {
/// Initializes a statically allocated lock class key.
///
- /// This is usually used indirectly through the [`static_lock_class!`] macro.
+ /// This is usually used indirectly through the [`static_lock_class!`] macro. See its
+ /// documentation for more information.
///
/// # Safety
///
/// * Before using the returned value, it must be pinned in a static memory location.
/// * The destructor must never run on the returned `LockClassKey`.
- #[doc(hidden)]
pub const unsafe fn new_static() -> Self {
LockClassKey {
inner: Opaque::uninit(),
}
}
- /// Initializes a dynamically allocated lock class key. In the common case of using a
- /// statically allocated lock class key, the static_lock_class! macro should be used instead.
+ /// Initializes a dynamically allocated lock class key.
+ ///
+ /// In the common case of using a statically allocated lock class key, the
+ /// [`static_lock_class!`] macro should be used instead.
///
/// # Examples
+ ///
/// ```
- /// # use kernel::c_str;
- /// # use kernel::alloc::KBox;
- /// # use kernel::types::ForeignOwnable;
- /// # use kernel::sync::{LockClassKey, SpinLock};
- /// # use pin_init::stack_pin_init;
+ /// use kernel::c_str;
+ /// use kernel::types::ForeignOwnable;
+ /// use kernel::sync::{LockClassKey, SpinLock};
+ /// use pin_init::stack_pin_init;
///
/// let key = KBox::pin_init(LockClassKey::new_dynamic(), GFP_KERNEL)?;
/// let key_ptr = key.into_foreign();
@@ -81,7 +89,6 @@ impl LockClassKey {
/// // SAFETY: We dropped `num`, the only use of the key, so the result of the previous
/// // `borrow` has also been dropped. Thus, it's safe to use from_foreign.
/// unsafe { drop(<Pin<KBox<LockClassKey>> as ForeignOwnable>::from_foreign(key_ptr)) };
- ///
/// # Ok::<(), Error>(())
/// ```
pub fn new_dynamic() -> impl PinInit<Self> {
@@ -91,7 +98,10 @@ pub fn new_dynamic() -> impl PinInit<Self> {
})
}
- pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key {
+ /// Returns a raw pointer to the inner C struct.
+ ///
+ /// It is up to the caller to use the raw pointer correctly.
+ pub fn as_ptr(&self) -> *mut bindings::lock_class_key {
self.inner.get()
}
}
@@ -99,14 +109,28 @@ pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key {
#[pinned_drop]
impl PinnedDrop for LockClassKey {
fn drop(self: Pin<&mut Self>) {
- // SAFETY: self.as_ptr was registered with lockdep and self is pinned, so the address
- // hasn't changed. Thus, it's safe to pass to unregister.
+ // SAFETY: `self.as_ptr()` was registered with lockdep and `self` is pinned, so the address
+ // hasn't changed. Thus, it's safe to pass it to unregister.
unsafe { bindings::lockdep_unregister_key(self.as_ptr()) }
}
}
/// Defines a new static lock class and returns a pointer to it.
-#[doc(hidden)]
+///
+/// # Examples
+///
+/// ```
+/// use kernel::c_str;
+/// use kernel::sync::{static_lock_class, Arc, SpinLock};
+///
+/// fn new_locked_int() -> Result<Arc<SpinLock<u32>>> {
+/// Arc::pin_init(SpinLock::new(
+/// 42,
+/// c_str!("new_locked_int"),
+/// static_lock_class!(),
+/// ), GFP_KERNEL)
+/// }
+/// ```
#[macro_export]
macro_rules! static_lock_class {
() => {{
@@ -118,6 +142,7 @@ macro_rules! static_lock_class {
$crate::prelude::Pin::static_ref(&CLASS)
}};
}
+pub use static_lock_class;
/// Returns the given string, if one is provided, otherwise generates one based on the source code
/// location.
--
2.50.1.470.g6ba607880d-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] rust: sync: refactor static_lock_class!() macro
2025-07-28 9:42 ` [PATCH v2 1/2] rust: sync: refactor static_lock_class!() macro Alice Ryhl
@ 2025-07-28 10:18 ` Benno Lossin
0 siblings, 0 replies; 6+ messages in thread
From: Benno Lossin @ 2025-07-28 10:18 UTC (permalink / raw)
To: Alice Ryhl, Boqun Feng, Miguel Ojeda
Cc: Gary Guo, Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Daniel Almeida, rust-for-linux, linux-kernel
On Mon Jul 28, 2025 at 11:42 AM CEST, Alice Ryhl wrote:
> By introducing a new_static() constructor, the macro does not need to go
> through MaybeUninit::uninit().assume_init(), which is a pattern that is
> best avoided when possible.
>
> The safety comment requires not only requires that the value is leaked,
"requires" appears twice.
> but also that it is stored in the right portion of memory. This is so
> that the lockdep static_obj() check will succeed when using this
> constructor. One could argue that lockdep detects this scenario, so the
> safety comment isn't needed. However, it simplifies matters to require
> that static_obj() will succeed and it's not a burdensome requirement on
> the caller.
I'd argue that's implementation detail and the safety requirement of
using a lockclass key is that it either is uninit in static memory or it
was registered. (otherwise we wouldn't be "allowed" to add this as a
safety requirement)
(just adding this for info, feel free to keep the paragraph above as-is)
> Suggested-by: Benno Lossin <lossin@kernel.org>
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Benno Lossin <lossin@kernel.org>
> @@ -95,13 +110,11 @@ fn drop(self: Pin<&mut Self>) {
> #[macro_export]
> macro_rules! static_lock_class {
> () => {{
> - static CLASS: $crate::sync::LockClassKey =
> - // Lockdep expects uninitialized memory when it's handed a statically allocated `struct
> - // lock_class_key`.
> - //
> - // SAFETY: `LockClassKey` transparently wraps `Opaque` which permits uninitialized
> - // memory.
> - unsafe { ::core::mem::MaybeUninit::uninit().assume_init() };
> + // SAFETY: The returned `LockClassKey` is stored in static memory. Drop never runs on a
You're not mentioning the "pinned in a static memory location" part
(only the static memory, so missing the pinning). A read-only static
is implicitly pinned, so we should mention that.
---
Cheers,
Benno
> + // static global.
> + static CLASS: $crate::sync::LockClassKey = unsafe {
> + $crate::sync::LockClassKey::new_static()
> + };
> $crate::prelude::Pin::static_ref(&CLASS)
> }};
> }
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/2] rust: sync: clean up LockClassKey and its docs
2025-07-28 9:42 ` [PATCH v2 2/2] rust: sync: clean up LockClassKey and its docs Alice Ryhl
@ 2025-08-12 8:05 ` Benno Lossin
2025-08-12 15:46 ` Boqun Feng
0 siblings, 1 reply; 6+ messages in thread
From: Benno Lossin @ 2025-08-12 8:05 UTC (permalink / raw)
To: Alice Ryhl, Boqun Feng, Miguel Ojeda
Cc: Gary Guo, Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Daniel Almeida, rust-for-linux, linux-kernel
On Mon Jul 28, 2025 at 11:42 AM CEST, Alice Ryhl wrote:
> Several aspects of the code and documentation for this type is
> incomplete. Also several things are hidden from the docs. Thus, clean it
> up and make it easier to read the rendered html docs.
>
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Benno Lossin <lossin@kernel.org>
---
Cheers,
Benno
> ---
> rust/kernel/sync.rs | 55 ++++++++++++++++++++++++++++++++++++++---------------
> 1 file changed, 40 insertions(+), 15 deletions(-)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/2] rust: sync: clean up LockClassKey and its docs
2025-08-12 8:05 ` Benno Lossin
@ 2025-08-12 15:46 ` Boqun Feng
0 siblings, 0 replies; 6+ messages in thread
From: Boqun Feng @ 2025-08-12 15:46 UTC (permalink / raw)
To: Benno Lossin
Cc: Alice Ryhl, Miguel Ojeda, Gary Guo, Björn Roy Baron,
Andreas Hindborg, Trevor Gross, Danilo Krummrich, Daniel Almeida,
rust-for-linux, linux-kernel
On Tue, Aug 12, 2025 at 10:05:55AM +0200, Benno Lossin wrote:
> On Mon Jul 28, 2025 at 11:42 AM CEST, Alice Ryhl wrote:
> > Several aspects of the code and documentation for this type is
> > incomplete. Also several things are hidden from the docs. Thus, clean it
> > up and make it easier to read the rendered html docs.
> >
> > Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> > Signed-off-by: Alice Ryhl <aliceryhl@google.com>
>
> Reviewed-by: Benno Lossin <lossin@kernel.org>
>
Thanks! I'm going to apply your tag for v3 [1], and queue for v6.18.
[1]: https://lore.kernel.org/rust-for-linux/20250811-lock-class-key-cleanup-v3-2-b12967ee1ca2@google.com/
Regards,
Boqun
> ---
> Cheers,
> Benno
>
> > ---
> > rust/kernel/sync.rs | 55 ++++++++++++++++++++++++++++++++++++++---------------
> > 1 file changed, 40 insertions(+), 15 deletions(-)
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-08-12 15:46 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-28 9:42 [PATCH v2 0/2] Clean up Rust LockClassKey Alice Ryhl
2025-07-28 9:42 ` [PATCH v2 1/2] rust: sync: refactor static_lock_class!() macro Alice Ryhl
2025-07-28 10:18 ` Benno Lossin
2025-07-28 9:42 ` [PATCH v2 2/2] rust: sync: clean up LockClassKey and its docs Alice Ryhl
2025-08-12 8:05 ` Benno Lossin
2025-08-12 15:46 ` Boqun Feng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).