From: Onur <work@onurozkan.dev>
To: Daniel Almeida <daniel.almeida@collabora.com>
Cc: rust-for-linux@vger.kernel.org, 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
Subject: Re: [PATCH v6 5/7] rust: ww_mutex: add context-free locking functions
Date: Sat, 6 Sep 2025 14:20:59 +0300 [thread overview]
Message-ID: <20250906142059.35bf5fc1@nimda.home> (raw)
In-Reply-To: <392B3416-61A7-4A41-8BDA-3A114F23D3F8@collabora.com>
On Fri, 5 Sep 2025 16:14:59 -0300
Daniel Almeida <daniel.almeida@collabora.com> wrote:
> Hi Onur
>
> > On 3 Sep 2025, at 10:13, Onur Özkan <work@onurozkan.dev> wrote:
> >
> > 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.
>
> Can you please mention how this is not exposed to the outside world?
>
> It should be obvious from its private visibility, but still.
>
I would like to keep this private and force users to go through the
public ones. This function contains the entire internal locking logic
and its signature may need to change if we update any of the internals.
Since it's private, we can safely make breaking changes without
affecting external calls.
The public functions on the other hand are much more stable (at worst,
only one or two of them might need a breaking change).
> > +#[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) };
>
> Use an intermediary variable to refer to the actual function. Then
> call this only once below the match statement.
>
> This will consolidate all the safety comments and "to_result()" calls
> into a single place, considerably reducing the clutter here.
>
Good idea!
> > +
> > + 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.
>
> “With no acquire context”.
>
> > + ///
> > + /// 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-06 11:28 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 ` [PATCH v6 5/7] rust: ww_mutex: add context-free locking functions Onur Özkan
2025-09-05 19:14 ` Daniel Almeida
2025-09-06 11:20 ` Onur [this message]
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=20250906142059.35bf5fc1@nimda.home \
--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