From 15abc88057eeec052aefde897df277eca2340ac6 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 19 Nov 2024 18:11:03 -0500 Subject: rust: sync: Add Lock::from_raw() for Lock<(), B> The KMS bindings [1] have a few bindings that require manually acquiring specific locks before calling certain functions. At the moment though, the only way of acquiring these locks in bindings is to simply call the C locking functions directly - since said locks are not initialized on the Rust side of things. However - if we add `#[repr(C)]` to `Lock<(), B>`, then given `()` is a ZST - `Lock<(), B>` becomes equivalent in data layout to its inner `B::State` type. Since locks in C don't have data explicitly associated with them anyway, we can take advantage of this to add a `Lock::from_raw()` function that can translate a raw pointer to `B::State` into its proper `Lock<(), B>` equivalent. This lets us simply acquire a reference to the lock in question and work with it like it was initialized on the Rust side of things, allowing us to use less unsafe code to implement bindings with lock requirements. [Boqun: Use "Link:" instead of a URL and format the commit log] Signed-off-by: Lyude Paul Reviewed-by: Alice Ryhl Link: https://patchwork.freedesktop.org/series/131522/ [1] Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241119231146.2298971-2-lyude@redhat.com --- rust/kernel/sync/lock.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'rust/kernel/sync/lock.rs') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 41dcddac69e2..57dc2e90e504 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -96,6 +96,7 @@ pub unsafe trait Backend { /// /// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock /// [`Backend`] specified as the generic parameter `B`. +#[repr(C)] #[pin_data] pub struct Lock { /// The kernel lock object. @@ -134,6 +135,28 @@ impl Lock { } } +impl Lock<(), B> { + /// Constructs a [`Lock`] from a raw pointer. + /// + /// This can be useful for interacting with a lock which was initialised outside of Rust. + /// + /// # Safety + /// + /// The caller promises that `ptr` points to a valid initialised instance of [`State`] during + /// the whole lifetime of `'a`. + /// + /// [`State`]: Backend::State + pub unsafe fn from_raw<'a>(ptr: *mut B::State) -> &'a Self { + // SAFETY: + // - By the safety contract `ptr` must point to a valid initialised instance of `B::State` + // - Since the lock data type is `()` which is a ZST, `state` is the only non-ZST member of + // the struct + // - Combined with `#[repr(C)]`, this guarantees `Self` has an equivalent data layout to + // `B::State`. + unsafe { &*ptr.cast() } + } +} + impl Lock { /// Acquires the lock and gives the caller access to the data protected by it. pub fn lock(&self) -> Guard<'_, T, B> { -- cgit v1.2.3 From daa03fe50ec376aeadd63a264c471c56af194e83 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 19 Nov 2024 18:11:04 -0500 Subject: rust: sync: Make Guard::new() public Since we added a `Lock::from_raw()` function previously, it makes sense to also introduce an interface for creating a `Guard` from a reference to a `Lock` for instances where we've derived the `Lock` from a raw pointer and know that the lock is already acquired, there are such usages in KMS API. [Boqun: Add backquotes to type names, reformat the commit log, reword a bit on the usage of KMS API] Signed-off-by: Lyude Paul Reviewed-by: Filipe Xavier Reviewed-by: Alice Ryhl Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241119231146.2298971-3-lyude@redhat.com --- rust/kernel/sync/lock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel/sync/lock.rs') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 57dc2e90e504..72dbf3fbb259 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -234,7 +234,7 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { /// # Safety /// /// The caller must ensure that it owns the lock. - pub(crate) unsafe fn new(lock: &'a Lock, state: B::GuardState) -> Self { + pub unsafe fn new(lock: &'a Lock, state: B::GuardState) -> Self { Self { lock, state, -- cgit v1.2.3 From fbd7a5a0359bc770e898d918d84977ea61163aad Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Mon, 25 Nov 2024 15:40:58 -0500 Subject: rust: sync: Add lock::Backend::assert_is_held() Since we've exposed Lock::from_raw() and Guard::new() publically, we want to be able to make sure that we assert that a lock is actually held when constructing a Guard for it to handle instances of unsafe Guard::new() calls outside of our lock module. Hence add a new method assert_is_held() to Backend, which uses lockdep to check whether or not a lock has been acquired. When lockdep is disabled, this has no overhead. [Boqun: Resolve the conflicts with exposing Guard::new(), reword the commit log a bit and format "unsafe { ; }" into "unsafe { }" for the consistency. ] Signed-off-by: Lyude Paul Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241125204139.656801-1-lyude@redhat.com --- rust/helpers/mutex.c | 5 +++++ rust/helpers/spinlock.c | 5 +++++ rust/kernel/sync/lock.rs | 10 ++++++++++ rust/kernel/sync/lock/mutex.rs | 5 +++++ rust/kernel/sync/lock/spinlock.rs | 5 +++++ 5 files changed, 30 insertions(+) (limited to 'rust/kernel/sync/lock.rs') diff --git a/rust/helpers/mutex.c b/rust/helpers/mutex.c index 7e00680958ef..06575553eda5 100644 --- a/rust/helpers/mutex.c +++ b/rust/helpers/mutex.c @@ -12,3 +12,8 @@ void rust_helper___mutex_init(struct mutex *mutex, const char *name, { __mutex_init(mutex, name, key); } + +void rust_helper_mutex_assert_is_held(struct mutex *mutex) +{ + lockdep_assert_held(mutex); +} diff --git a/rust/helpers/spinlock.c b/rust/helpers/spinlock.c index 5971fdf6f755..42c4bf01a23e 100644 --- a/rust/helpers/spinlock.c +++ b/rust/helpers/spinlock.c @@ -30,3 +30,8 @@ int rust_helper_spin_trylock(spinlock_t *lock) { return spin_trylock(lock); } + +void rust_helper_spin_assert_is_held(spinlock_t *lock) +{ + lockdep_assert_held(lock); +} diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 72dbf3fbb259..eb80048e0110 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -90,6 +90,13 @@ pub unsafe trait Backend { // SAFETY: The safety requirements ensure that the lock is initialised. *guard_state = unsafe { Self::lock(ptr) }; } + + /// Asserts that the lock is held using lockdep. + /// + /// # Safety + /// + /// Callers must ensure that [`Backend::init`] has been previously called. + unsafe fn assert_is_held(ptr: *mut Self::State); } /// A mutual exclusion primitive. @@ -235,6 +242,9 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { /// /// The caller must ensure that it owns the lock. pub unsafe fn new(lock: &'a Lock, state: B::GuardState) -> Self { + // SAFETY: The caller can only hold the lock if `Backend::init` has already been called. + unsafe { B::assert_is_held(lock.state.get()) }; + Self { lock, state, diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 10a70c07268d..70cadbc2e8e2 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -134,4 +134,9 @@ unsafe impl super::Backend for MutexBackend { None } } + + unsafe fn assert_is_held(ptr: *mut Self::State) { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + unsafe { bindings::mutex_assert_is_held(ptr) } + } } diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index 081c0220013b..ab2f8d075311 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -133,4 +133,9 @@ unsafe impl super::Backend for SpinLockBackend { None } } + + unsafe fn assert_is_held(ptr: *mut Self::State) { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + unsafe { bindings::spin_assert_is_held(ptr) } + } } -- cgit v1.2.3