From f4c2c90bb7b4ae1812dbaca15d9637eecaac2c9f Mon Sep 17 00:00:00 2001 From: Filipe Xavier Date: Thu, 26 Sep 2024 17:50:37 -0300 Subject: [PATCH] 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 Reviewed-by: Fiona Behrens Reviewed-by: Alice Ryhl Reviewed-by: Boqun Feng Link: https://lore.kernel.org/r/BL0PR02MB4914579914884B5D7473B3D6E96A2@BL0PR02MB4914.namprd02.prod.outlook.com [ Slightly reworded. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/helpers/spinlock.c | 5 +++++ rust/kernel/sync/lock.rs | 16 ++++++++++++++++ rust/kernel/sync/lock/mutex.rs | 11 +++++++++++ rust/kernel/sync/lock/spinlock.rs | 11 +++++++++++ 4 files changed, 43 insertions(+) diff --git a/rust/helpers/spinlock.c b/rust/helpers/spinlock.c index acc1376b833c78..775ed4d549aefe 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 07fcf2d8efc6ce..90cc5416529bdd 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; + /// Releases the lock, giving up its ownership. /// /// # Safety @@ -128,6 +135,15 @@ impl Lock { // 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> { + // 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 30632070ee6709..c4f3b6cbfe48de 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 { + // 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 ea5c5bc1ce12ed..c900ae23db76fe 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 { + // 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 + } + } }