From 8f65291dae0e75941cf76e427088e5612c4d692e Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 7 Mar 2025 15:26:57 -0800 Subject: rust: sync: Add accessor for the lock behind a given guard In order to assert a particular `Guard` is associated with a particular `Lock`, add an accessor to obtain a reference to the underlying `Lock` of a `Guard`. Binder needs this assertion to ensure unsafe list operations are done with the correct lock held. [Boqun: Capitalize the title and reword the commit log] Signed-off-by: Alice Ryhl Signed-off-by: Boqun Feng Signed-off-by: Ingo Molnar Reviewed-by: Fiona Behrens Link: https://lore.kernel.org/r/20250205-guard-get-lock-v2-1-ba32a8c1d5b7@google.com Link: https://lore.kernel.org/r/20250307232717.1759087-8-boqun.feng@gmail.com --- rust/kernel/sync/lock.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index eb80048e0110..8e7e6d5f61e4 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -199,7 +199,12 @@ pub struct Guard<'a, T: ?Sized, B: Backend> { // SAFETY: `Guard` is sync when the data protected by the lock is also sync. unsafe impl Sync for Guard<'_, T, B> {} -impl Guard<'_, T, B> { +impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { + /// Returns the lock that this guard originates from. + pub fn lock_ref(&self) -> &'a Lock { + self.lock + } + pub(crate) fn do_unlocked(&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) }; -- cgit v1.2.3 From c2849afafd08a1c3ad881129de48ebe1642f7675 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Fri, 7 Mar 2025 15:26:58 -0800 Subject: rust: sync: lock: Add an example for Guard:: Lock_ref() To provide examples on usage of `Guard::lock_ref()` along with the unit test, an "assert a lock is held by a guard" example is added. (Also apply feedback from Benno.) Signed-off-by: Boqun Feng Signed-off-by: Ingo Molnar Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250223072114.3715-1-boqun.feng@gmail.com Link: https://lore.kernel.org/r/20250307232717.1759087-9-boqun.feng@gmail.com --- rust/kernel/sync/lock.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 8e7e6d5f61e4..f53e87d04cd2 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -201,6 +201,30 @@ unsafe impl Sync for Guard<'_, T, B> {} impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { /// Returns the lock that this guard originates from. + /// + /// # Examples + /// + /// The following example shows how to use [`Guard::lock_ref()`] to assert the corresponding + /// lock is held. + /// + /// ``` + /// # use kernel::{new_spinlock, stack_pin_init, sync::lock::{Backend, Guard, Lock}}; + /// + /// fn assert_held(guard: &Guard<'_, T, B>, lock: &Lock) { + /// // Address-equal means the same lock. + /// assert!(core::ptr::eq(guard.lock_ref(), lock)); + /// } + /// + /// // Creates a new lock on the stack. + /// stack_pin_init!{ + /// let l = new_spinlock!(42) + /// } + /// + /// let g = l.lock(); + /// + /// // `g` originates from `l`. + /// assert_held(&g, &l); + /// ``` pub fn lock_ref(&self) -> &'a Lock { self.lock } -- cgit v1.2.3 From 70b9c8563c9c29102a785d4822f0d77d33fee808 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 7 Mar 2025 15:26:59 -0800 Subject: rust: sync: condvar: Add wait_interruptible_freezable() To support waiting for a `CondVar` as a freezable process, add a wait_interruptible_freezable() function. Binder needs this function in the appropriate places to freeze a process where some of its threads are blocked on the Binder driver. [ Boqun: Cleaned up the changelog and documentation. ] Signed-off-by: Alice Ryhl Signed-off-by: Boqun Feng Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20250307232717.1759087-10-boqun.feng@gmail.com --- rust/kernel/sync/condvar.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index 7df565038d7d..5c1e546a26c3 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -11,7 +11,9 @@ use crate::{ init::PinInit, pin_init, str::CStr, - task::{MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE}, + task::{ + MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE, + }, time::Jiffies, types::Opaque, }; @@ -159,6 +161,25 @@ impl CondVar { crate::current!().signal_pending() } + /// Releases the lock and waits for a notification in interruptible and freezable mode. + /// + /// The process is allowed to be frozen during this sleep. No lock should be held when calling + /// this function, and there is a lockdep assertion for this. Freezing a task that holds a lock + /// can trivially deadlock vs another task that needs that lock to complete before it too can + /// hit freezable. + #[must_use = "wait_interruptible_freezable returns if a signal is pending, so the caller must check the return value"] + pub fn wait_interruptible_freezable( + &self, + guard: &mut Guard<'_, T, B>, + ) -> bool { + self.wait_internal( + TASK_INTERRUPTIBLE | TASK_FREEZABLE, + guard, + MAX_SCHEDULE_TIMEOUT, + ); + crate::current!().signal_pending() + } + /// Releases the lock and waits for a notification in interruptible mode. /// /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the -- cgit v1.2.3 From f73ca66f0d7f4371d172d6f5b1f9a00e367ba921 Mon Sep 17 00:00:00 2001 From: Mitchell Levy Date: Fri, 7 Mar 2025 15:27:01 -0800 Subject: rust: lockdep: Use Pin for all LockClassKey usages Reintroduce dynamically-allocated LockClassKeys such that they are automatically (de)registered. Require that all usages of LockClassKeys ensure that they are Pin'd. Currently, only `'static` LockClassKeys are supported, so Pin is redundant. However, it is intended that dynamically-allocated LockClassKeys will eventually be supported, so using Pin from the outset will make that change simpler. Closes: https://github.com/Rust-for-Linux/linux/issues/1102 Suggested-by: Benno Lossin Suggested-by: Boqun Feng Signed-off-by: Mitchell Levy Signed-off-by: Boqun Feng Signed-off-by: Ingo Molnar Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250307232717.1759087-12-boqun.feng@gmail.com --- rust/kernel/sync/condvar.rs | 5 ++--- rust/kernel/sync/lock.rs | 4 ++-- rust/kernel/sync/lock/global.rs | 5 +++-- rust/kernel/sync/poll.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index 5c1e546a26c3..fbf68ada582f 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -17,8 +17,7 @@ use crate::{ time::Jiffies, types::Opaque, }; -use core::marker::PhantomPinned; -use core::ptr; +use core::{marker::PhantomPinned, pin::Pin, ptr}; use macros::pin_data; /// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class. @@ -103,7 +102,7 @@ unsafe impl Sync for CondVar {} impl CondVar { /// Constructs a new condvar initialiser. - pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit { pin_init!(Self { _pin: PhantomPinned, // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index f53e87d04cd2..360a10a9216d 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -12,7 +12,7 @@ use crate::{ str::CStr, types::{NotThreadSafe, Opaque, ScopeGuard}, }; -use core::{cell::UnsafeCell, marker::PhantomPinned}; +use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin}; use macros::pin_data; pub mod mutex; @@ -129,7 +129,7 @@ unsafe impl Sync for Lock {} impl Lock { /// Constructs a new lock initialiser. - pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + pub fn new(t: T, name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit { pin_init!(Self { data: UnsafeCell::new(t), _pin: PhantomPinned, diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global.rs index 480ee724e3cc..d65f94b5caf2 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -13,6 +13,7 @@ use crate::{ use core::{ cell::UnsafeCell, marker::{PhantomData, PhantomPinned}, + pin::Pin, }; /// Trait implemented for marker types for global locks. @@ -26,7 +27,7 @@ pub trait GlobalLockBackend { /// The backend used for this global lock. type Backend: Backend + 'static; /// The class for this global lock. - fn get_lock_class() -> &'static LockClassKey; + fn get_lock_class() -> Pin<&'static LockClassKey>; } /// Type used for global locks. @@ -270,7 +271,7 @@ macro_rules! global_lock { type Item = $valuety; type Backend = $crate::global_lock_inner!(backend $kind); - fn get_lock_class() -> &'static $crate::sync::LockClassKey { + fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> { $crate::static_lock_class!() } } diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs index d5f17153b424..c4934f82d68b 100644 --- a/rust/kernel/sync/poll.rs +++ b/rust/kernel/sync/poll.rs @@ -89,7 +89,7 @@ pub struct PollCondVar { impl PollCondVar { /// Constructs a new condvar initialiser. - pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit { pin_init!(Self { inner <- CondVar::new(name, key), }) -- cgit v1.2.3