diff options
author | Filipe Xavier <felipe_life@live.com> | 2024-09-26 17:50:37 -0300 |
---|---|---|
committer | Miguel Ojeda <ojeda@kernel.org> | 2024-10-07 21:39:58 +0200 |
commit | 6f566513982f6cf9a883ff2a839ed86034bef334 (patch) | |
tree | 583c3b26de69dff33a346b3764cbb76ef7a4364b | |
parent | fae45259cd55143d41a763cacf3c353d9d410b60 (diff) |
rust: lock: add trylock method support for lock backend
Add a non-blocking trylock method to lock backend interface, mutex and
spinlock implementations. It includes a C helper for spin_trylock.
Rust Binder will use this method together with the new shrinker
abstractions to avoid deadlocks in the memory shrinker.
Link: https://lore.kernel.org/all/20240912-shrinker-v1-1-18b7f1253553@google.com
Signed-off-by: Filipe Xavier <felipe_life@live.com>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Link: https://lore.kernel.org/r/BL0PR02MB4914579914884B5D7473B3D6E96A2@BL0PR02MB4914.namprd02.prod.outlook.com
[ Slightly reworded. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
-rw-r--r-- | rust/helpers/spinlock.c | 5 | ||||
-rw-r--r-- | rust/kernel/sync/lock.rs | 16 | ||||
-rw-r--r-- | rust/kernel/sync/lock/mutex.rs | 11 | ||||
-rw-r--r-- | rust/kernel/sync/lock/spinlock.rs | 11 |
4 files changed, 43 insertions, 0 deletions
diff --git a/rust/helpers/spinlock.c b/rust/helpers/spinlock.c index acc1376b833c..775ed4d549ae 100644 --- a/rust/helpers/spinlock.c +++ b/rust/helpers/spinlock.c @@ -22,3 +22,8 @@ void rust_helper_spin_unlock(spinlock_t *lock) { spin_unlock(lock); } + +int rust_helper_spin_trylock(spinlock_t *lock) +{ + return spin_trylock(lock); +} diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 07fcf2d8efc6..90cc5416529b 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -58,6 +58,13 @@ pub unsafe trait Backend { #[must_use] unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState; + /// Tries to acquire the lock. + /// + /// # Safety + /// + /// Callers must ensure that [`Backend::init`] has been previously called. + unsafe fn try_lock(ptr: *mut Self::State) -> Option<Self::GuardState>; + /// Releases the lock, giving up its ownership. /// /// # Safety @@ -128,6 +135,15 @@ impl<T: ?Sized, B: Backend> Lock<T, B> { // SAFETY: The lock was just acquired. unsafe { Guard::new(self, state) } } + + /// Tries to acquire the lock. + /// + /// Returns a guard that can be used to access the data protected by the lock if successful. + pub fn try_lock(&self) -> Option<Guard<'_, T, B>> { + // SAFETY: The constructor of the type calls `init`, so the existence of the object proves + // that `init` was called. + unsafe { B::try_lock(self.state.get()).map(|state| Guard::new(self, state)) } + } } /// A lock guard. diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 30632070ee67..c4f3b6cbfe48 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -115,4 +115,15 @@ unsafe impl super::Backend for MutexBackend { // caller is the owner of the mutex. unsafe { bindings::mutex_unlock(ptr) }; } + + unsafe fn try_lock(ptr: *mut Self::State) -> Option<Self::GuardState> { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + let result = unsafe { bindings::mutex_trylock(ptr) }; + + if result != 0 { + Some(()) + } else { + None + } + } } diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index ea5c5bc1ce12..c900ae23db76 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -114,4 +114,15 @@ unsafe impl super::Backend for SpinLockBackend { // caller is the owner of the spinlock. unsafe { bindings::spin_unlock(ptr) } } + + unsafe fn try_lock(ptr: *mut Self::State) -> Option<Self::GuardState> { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + let result = unsafe { bindings::spin_trylock(ptr) }; + + if result != 0 { + Some(()) + } else { + None + } + } } |