* [PATCH] rust: lock: Export Guard::do_unlocked()
@ 2025-07-24 17:25 Lyude Paul
2025-07-24 17:54 ` Boqun Feng
0 siblings, 1 reply; 2+ messages in thread
From: Lyude Paul @ 2025-07-24 17:25 UTC (permalink / raw)
To: rust-for-linux, Thomas Gleixner, Boqun Feng, linux-kernel
Cc: Peter Zijlstra, Ingo Molnar, Will Deacon, Waiman Long,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich
In RVKMS, I discovered a silly issue where as a result of our HrTimer for
vblank emulation and our vblank enable/disable callbacks sharing a
spinlock, it was possible to deadlock while trying to disable the vblank
timer.
The solution for this ended up being simple: keep track of when the HrTimer
could potentially acquire the shared spinlock, and simply drop the spinlock
temporarily from our vblank enable/disable callbacks when stopping the
timer. And do_unlocked() ended up being perfect for this.
Since this seems like it's useful, let's export this for use by the rest of
the world and write short documentation for it.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
You can find an example usage of this here:
https://gitlab.freedesktop.org/lyudess/linux/-/blob/rvkms-slim/drivers/gpu/drm/rvkms/crtc.rs
rust/kernel/sync/lock.rs | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs
index e82fa5be289c1..60eb98805a489 100644
--- a/rust/kernel/sync/lock.rs
+++ b/rust/kernel/sync/lock.rs
@@ -228,7 +228,13 @@ pub fn lock_ref(&self) -> &'a Lock<T, B> {
self.lock
}
- pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
+ /// Unlock this [`Guard`]'s lock temporarily, execute `cb`, and then re-lock it.
+ ///
+ /// This can be useful for situations where you may need to do a temporary unlock dance to avoid
+ /// issues like circular locking dependencies.
+ ///
+ /// If the closure returns a value, it will be returned by this function.
+ pub fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
// SAFETY: The caller owns the lock, so it is safe to unlock it.
unsafe { B::unlock(self.lock.state.get(), &self.state) };
base-commit: dff64b072708ffef23c117fa1ee1ea59eb417807
--
2.50.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] rust: lock: Export Guard::do_unlocked()
2025-07-24 17:25 [PATCH] rust: lock: Export Guard::do_unlocked() Lyude Paul
@ 2025-07-24 17:54 ` Boqun Feng
0 siblings, 0 replies; 2+ messages in thread
From: Boqun Feng @ 2025-07-24 17:54 UTC (permalink / raw)
To: Lyude Paul
Cc: rust-for-linux, Thomas Gleixner, linux-kernel, Peter Zijlstra,
Ingo Molnar, Will Deacon, Waiman Long, Miguel Ojeda, Alex Gaynor,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich
On Thu, Jul 24, 2025 at 01:25:00PM -0400, Lyude Paul wrote:
> In RVKMS, I discovered a silly issue where as a result of our HrTimer for
> vblank emulation and our vblank enable/disable callbacks sharing a
> spinlock, it was possible to deadlock while trying to disable the vblank
> timer.
>
> The solution for this ended up being simple: keep track of when the HrTimer
> could potentially acquire the shared spinlock, and simply drop the spinlock
> temporarily from our vblank enable/disable callbacks when stopping the
> timer. And do_unlocked() ended up being perfect for this.
>
> Since this seems like it's useful, let's export this for use by the rest of
> the world and write short documentation for it.
>
> Signed-off-by: Lyude Paul <lyude@redhat.com>
Seems reasonable.
> ---
> You can find an example usage of this here:
>
> https://gitlab.freedesktop.org/lyudess/linux/-/blob/rvkms-slim/drivers/gpu/drm/rvkms/crtc.rs
>
> rust/kernel/sync/lock.rs | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs
> index e82fa5be289c1..60eb98805a489 100644
> --- a/rust/kernel/sync/lock.rs
> +++ b/rust/kernel/sync/lock.rs
> @@ -228,7 +228,13 @@ pub fn lock_ref(&self) -> &'a Lock<T, B> {
> self.lock
> }
>
> - pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
> + /// Unlock this [`Guard`]'s lock temporarily, execute `cb`, and then re-lock it.
I would like to change this line as the following to be consistent with
other comments in the file.
/// Releases this [`Guard`]'s lock temporary, executes `cb` and then re-acquires it.
> + ///
> + /// This can be useful for situations where you may need to do a temporary unlock dance to avoid
> + /// issues like circular locking dependencies.
> + ///
Could you add an "# Examples" section here with a simple example?
Thanks!
Otherwise it looks good to me, thanks!
Regards
Boqun
> + /// If the closure returns a value, it will be returned by this function.
> + pub fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
> // SAFETY: The caller owns the lock, so it is safe to unlock it.
> unsafe { B::unlock(self.lock.state.get(), &self.state) };
>
>
> base-commit: dff64b072708ffef23c117fa1ee1ea59eb417807
> --
> 2.50.0
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-07-24 17:54 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-24 17:25 [PATCH] rust: lock: Export Guard::do_unlocked() Lyude Paul
2025-07-24 17:54 ` 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).