From: "Onur Özkan" <work@onurozkan.dev>
To: rust-for-linux@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, lossin@kernel.org,
lyude@redhat.com, ojeda@kernel.org, alex.gaynor@gmail.com,
boqun.feng@gmail.com, gary@garyguo.net, a.hindborg@kernel.org,
aliceryhl@google.com, tmgross@umich.edu, dakr@kernel.org,
peterz@infradead.org, mingo@redhat.com, will@kernel.org,
longman@redhat.com, felipe_life@live.com, daniel@sedlak.dev,
bjorn3_gh@protonmail.com, daniel.almeida@collabora.com,
"Onur Özkan" <work@onurozkan.dev>
Subject: [PATCH v6 5/7] rust: ww_mutex: add context-free locking functions
Date: Wed, 3 Sep 2025 16:13:11 +0300 [thread overview]
Message-ID: <20250903131313.4365-6-work@onurozkan.dev> (raw)
In-Reply-To: <20250903131313.4365-1-work@onurozkan.dev>
Adds new `WwMutex` functions (`lock`, `lock_interruptible`,
`lock_slow`, `lock_slow_interruptible` and `try_lock`) that
can be used without `WwAcquireCtx`. This provides simpler API
when deadlock avoidance grouping is not needed.
Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
rust/kernel/sync/lock/ww_mutex.rs | 162 ++++++++++++++++++++++--------
1 file changed, 122 insertions(+), 40 deletions(-)
diff --git a/rust/kernel/sync/lock/ww_mutex.rs b/rust/kernel/sync/lock/ww_mutex.rs
index d289718d2c98..b415d6deae9b 100644
--- a/rust/kernel/sync/lock/ww_mutex.rs
+++ b/rust/kernel/sync/lock/ww_mutex.rs
@@ -138,6 +138,75 @@ pub fn new_wound_wait(name: &'static CStr) -> impl PinInit<Self> {
}
}
+/// Locking kinds used by [`lock_common`] to unify internal FFI locking logic.
+#[derive(Copy, Clone, Debug)]
+enum LockKind {
+ /// Blocks until lock is acquired.
+ Regular,
+ /// Blocks but can be interrupted by signals.
+ Interruptible,
+ /// Used in slow path after deadlock detection.
+ Slow,
+ /// Slow path but interruptible.
+ SlowInterruptible,
+ /// Does not block, returns immediately if busy.
+ Try,
+}
+
+/// Internal helper that unifies the different locking kinds.
+fn lock_common<'a, T: ?Sized>(
+ ww_mutex: &'a WwMutex<'a, T>,
+ ctx: Option<&WwAcquireCtx<'_>>,
+ kind: LockKind,
+) -> Result<WwMutexGuard<'a, T>> {
+ let ctx_ptr = ctx.map_or(core::ptr::null_mut(), |c| c.inner.get());
+
+ match kind {
+ LockKind::Regular => {
+ // SAFETY: `WwMutex` is always pinned. If `WwAcquireCtx` is `Some`, it is pinned,
+ // if `None`, it is set to `core::ptr::null_mut()`. Both cases are safe.
+ let ret = unsafe { bindings::ww_mutex_lock(ww_mutex.mutex.get(), ctx_ptr) };
+
+ to_result(ret)?;
+ }
+ LockKind::Interruptible => {
+ // SAFETY: `WwMutex` is always pinned. If `WwAcquireCtx` is `Some`, it is pinned,
+ // if `None`, it is set to `core::ptr::null_mut()`. Both cases are safe.
+ let ret =
+ unsafe { bindings::ww_mutex_lock_interruptible(ww_mutex.mutex.get(), ctx_ptr) };
+
+ to_result(ret)?;
+ }
+ LockKind::Slow => {
+ // SAFETY: `WwMutex` is always pinned. If `WwAcquireCtx` is `Some`, it is pinned,
+ // if `None`, it is set to `core::ptr::null_mut()`. Both cases are safe.
+ unsafe { bindings::ww_mutex_lock_slow(ww_mutex.mutex.get(), ctx_ptr) };
+ }
+ LockKind::SlowInterruptible => {
+ // SAFETY: `WwMutex` is always pinned. If `WwAcquireCtx` is `Some`, it is pinned,
+ // if `None`, it is set to `core::ptr::null_mut()`. Both cases are safe.
+ let ret = unsafe {
+ bindings::ww_mutex_lock_slow_interruptible(ww_mutex.mutex.get(), ctx_ptr)
+ };
+
+ to_result(ret)?;
+ }
+ LockKind::Try => {
+ // SAFETY: `WwMutex` is always pinned. If `WwAcquireCtx` is `Some`, it is pinned,
+ // if `None`, it is set to `core::ptr::null_mut()`. Both cases are safe.
+ let ret = unsafe { bindings::ww_mutex_trylock(ww_mutex.mutex.get(), ctx_ptr) };
+
+ if ret == 0 {
+ return Err(EBUSY);
+ } else {
+ to_result(ret)?;
+ }
+ }
+ };
+
+ Ok(WwMutexGuard::new(ww_mutex))
+}
+
/// Groups multiple mutex acquisitions together for deadlock avoidance.
///
/// Must be used when acquiring multiple mutexes of the same class.
@@ -196,14 +265,9 @@ pub fn done(&self) {
unsafe { bindings::ww_acquire_done(self.inner.get()) };
}
- /// Locks the given mutex.
+ /// Locks the given mutex on this acquire context ([`WwAcquireCtx`]).
pub fn lock<'a, T>(&'a self, ww_mutex: &'a WwMutex<'a, T>) -> Result<WwMutexGuard<'a, T>> {
- // SAFETY: The mutex is pinned and valid.
- let ret = unsafe { bindings::ww_mutex_lock(ww_mutex.mutex.get(), self.inner.get()) };
-
- to_result(ret)?;
-
- Ok(WwMutexGuard::new(ww_mutex))
+ lock_common(ww_mutex, Some(self), LockKind::Regular)
}
/// Similar to `lock`, but can be interrupted by signals.
@@ -211,24 +275,14 @@ pub fn lock_interruptible<'a, T>(
&'a self,
ww_mutex: &'a WwMutex<'a, T>,
) -> Result<WwMutexGuard<'a, T>> {
- // SAFETY: The mutex is pinned and valid.
- let ret = unsafe {
- bindings::ww_mutex_lock_interruptible(ww_mutex.mutex.get(), self.inner.get())
- };
-
- to_result(ret)?;
-
- Ok(WwMutexGuard::new(ww_mutex))
+ lock_common(ww_mutex, Some(self), LockKind::Interruptible)
}
- /// Locks the given mutex using the slow path.
+ /// Locks the given mutex on this acquire context ([`WwAcquireCtx`]) using the slow path.
///
/// This function should be used when `lock` fails (typically due to a potential deadlock).
pub fn lock_slow<'a, T>(&'a self, ww_mutex: &'a WwMutex<'a, T>) -> Result<WwMutexGuard<'a, T>> {
- // SAFETY: The mutex is pinned and valid, and we're in the slow path.
- unsafe { bindings::ww_mutex_lock_slow(ww_mutex.mutex.get(), self.inner.get()) };
-
- Ok(WwMutexGuard::new(ww_mutex))
+ lock_common(ww_mutex, Some(self), LockKind::Slow)
}
/// Similar to `lock_slow`, but can be interrupted by signals.
@@ -236,30 +290,14 @@ pub fn lock_slow_interruptible<'a, T>(
&'a self,
ww_mutex: &'a WwMutex<'a, T>,
) -> Result<WwMutexGuard<'a, T>> {
- // SAFETY: The mutex is pinned and valid, and we are in the slow path.
- let ret = unsafe {
- bindings::ww_mutex_lock_slow_interruptible(ww_mutex.mutex.get(), self.inner.get())
- };
-
- to_result(ret)?;
-
- Ok(WwMutexGuard::new(ww_mutex))
+ lock_common(ww_mutex, Some(self), LockKind::SlowInterruptible)
}
- /// Tries to lock the mutex without blocking.
+ /// Tries to lock the mutex on this acquire context ([`WwAcquireCtx`]) without blocking.
///
/// Unlike `lock`, no deadlock handling is performed.
pub fn try_lock<'a, T>(&'a self, ww_mutex: &'a WwMutex<'a, T>) -> Result<WwMutexGuard<'a, T>> {
- // SAFETY: The mutex is pinned and valid.
- let ret = unsafe { bindings::ww_mutex_trylock(ww_mutex.mutex.get(), self.inner.get()) };
-
- if ret == 0 {
- return Err(EBUSY);
- } else {
- to_result(ret)?;
- }
-
- Ok(WwMutexGuard::new(ww_mutex))
+ lock_common(ww_mutex, Some(self), LockKind::Try)
}
}
@@ -355,7 +393,7 @@ pub fn new(t: T, ww_class: &'ww_class WwClass) -> impl PinInit<Self> {
}
}
-impl<T: ?Sized> WwMutex<'_, T> {
+impl<'ww_class, T: ?Sized> WwMutex<'ww_class, T> {
/// Returns a raw pointer to the inner mutex.
fn as_ptr(&self) -> *mut bindings::ww_mutex {
self.mutex.get()
@@ -370,6 +408,35 @@ fn is_locked(&self) -> bool {
// SAFETY: The mutex is pinned and valid.
unsafe { bindings::ww_mutex_is_locked(self.mutex.get()) }
}
+
+ /// Locks the given mutex without acquire context ([`WwAcquireCtx`]).
+ pub fn lock<'a>(&'a self) -> Result<WwMutexGuard<'a, T>> {
+ lock_common(self, None, LockKind::Regular)
+ }
+
+ /// Similar to `lock`, but can be interrupted by signals.
+ pub fn lock_interruptible<'a>(&'a self) -> Result<WwMutexGuard<'a, T>> {
+ lock_common(self, None, LockKind::Interruptible)
+ }
+
+ /// Locks the given mutex without acquire context ([`WwAcquireCtx`]) using the slow path.
+ ///
+ /// This function should be used when `lock` fails (typically due to a potential deadlock).
+ pub fn lock_slow<'a>(&'a self) -> Result<WwMutexGuard<'a, T>> {
+ lock_common(self, None, LockKind::Slow)
+ }
+
+ /// Similar to `lock_slow`, but can be interrupted by signals.
+ pub fn lock_slow_interruptible<'a>(&'a self) -> Result<WwMutexGuard<'a, T>> {
+ lock_common(self, None, LockKind::SlowInterruptible)
+ }
+
+ /// Tries to lock the mutex without acquire context ([`WwAcquireCtx`]) and without blocking.
+ ///
+ /// Unlike `lock`, no deadlock handling is performed.
+ pub fn try_lock<'a>(&'a self) -> Result<WwMutexGuard<'a, T>> {
+ lock_common(self, None, LockKind::Try)
+ }
}
/// A guard that provides exclusive access to the data protected
@@ -547,4 +614,19 @@ fn test_with_global_classes() -> Result {
Ok(())
}
+
+ #[test]
+ fn test_mutex_without_ctx() -> Result {
+ let mutex = Arc::pin_init(WwMutex::new(100, &TEST_WOUND_WAIT_CLASS), GFP_KERNEL)?;
+ let guard = mutex.lock()?;
+
+ assert_eq!(*guard, 100);
+ assert!(mutex.is_locked());
+
+ drop(guard);
+
+ assert!(!mutex.is_locked());
+
+ Ok(())
+ }
}
--
2.50.0
next prev parent reply other threads:[~2025-09-03 13:21 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-03 13:13 [PATCH v6 0/7] rust: add `ww_mutex` support Onur Özkan
2025-09-03 13:13 ` [PATCH v6 1/7] rust: add C wrappers for ww_mutex inline functions Onur Özkan
2025-09-03 13:46 ` Daniel Almeida
2025-09-03 13:13 ` [PATCH v6 2/7] rust: implement `WwClass` for ww_mutex support Onur Özkan
2025-09-03 16:06 ` Boqun Feng
2025-09-04 8:23 ` Onur Özkan
2025-09-03 13:13 ` [PATCH v6 3/7] rust: implement `WwMutex`, `WwAcquireCtx` and `WwMutexGuard` Onur Özkan
2025-09-05 18:49 ` Daniel Almeida
2025-09-05 19:03 ` Daniel Almeida
2025-09-06 11:38 ` Onur
2025-10-22 10:47 ` Onur Özkan
2025-09-06 11:35 ` Onur
2025-09-03 13:13 ` [PATCH v6 4/7] add KUnit coverage on Rust ww_mutex implementation Onur Özkan
2025-09-05 19:04 ` Daniel Almeida
2025-09-03 13:13 ` Onur Özkan [this message]
2025-09-05 19:14 ` [PATCH v6 5/7] rust: ww_mutex: add context-free locking functions Daniel Almeida
2025-09-06 11:20 ` Onur
2025-10-21 13:31 ` Daniel Almeida
2025-10-21 13:20 ` Onur Özkan
2025-09-03 13:13 ` [PATCH v6 6/7] rust: ww_mutex/exec: add high-level API Onur Özkan
2025-09-05 19:42 ` Daniel Almeida
2025-09-06 11:13 ` Onur
2025-09-06 15:04 ` Daniel Almeida
2025-09-07 8:20 ` Onur
2025-09-07 8:38 ` Onur
2025-10-21 19:36 ` Onur Özkan
2025-10-21 13:24 ` Onur Özkan
2025-10-21 14:04 ` Onur Özkan
2025-09-05 23:11 ` Elle Rhumsaa
2025-09-06 11:47 ` Onur Özkan
2025-09-03 13:13 ` [PATCH v6 7/7] add KUnit coverage on ww_mutex/exec implementation Onur Özkan
2025-09-05 23:12 ` Elle Rhumsaa
2025-10-16 19:47 ` [PATCH v6 0/7] rust: add `ww_mutex` support Lyude Paul
2025-10-17 5:03 ` Onur Özkan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250903131313.4365-6-work@onurozkan.dev \
--to=work@onurozkan.dev \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=daniel@sedlak.dev \
--cc=felipe_life@live.com \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=longman@redhat.com \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=mingo@redhat.com \
--cc=ojeda@kernel.org \
--cc=peterz@infradead.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®