Skip to content

Commit c5488f3

Browse files
committed
rust: lock: implement IrqSaveBackend for SpinLock
This allows Rust code to use the `lock_irqsave` variant of spinlocks. Cc: Peter Zijlstra <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Will Deacon <[email protected]> Cc: Waiman Long <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent e5aa829 commit c5488f3

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

rust/helpers.c

+16
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,22 @@ void rust_helper_spin_unlock(spinlock_t *lock)
5959
}
6060
EXPORT_SYMBOL_GPL(rust_helper_spin_unlock);
6161

62+
unsigned long rust_helper_spin_lock_irqsave(spinlock_t *lock)
63+
{
64+
unsigned long flags;
65+
66+
spin_lock_irqsave(lock, flags);
67+
68+
return flags;
69+
}
70+
EXPORT_SYMBOL_GPL(rust_helper_spin_lock_irqsave);
71+
72+
void rust_helper_spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
73+
{
74+
spin_unlock_irqrestore(lock, flags);
75+
}
76+
EXPORT_SYMBOL_GPL(rust_helper_spin_unlock_irqrestore);
77+
6278
refcount_t rust_helper_REFCOUNT_INIT(int n)
6379
{
6480
return (refcount_t)REFCOUNT_INIT(n);

rust/kernel/sync/lock/spinlock.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ macro_rules! new_spinlock {
6161
/// assert_eq!(e.c, 10);
6262
/// assert_eq!(e.d.lock().a, 20);
6363
/// assert_eq!(e.d.lock().b, 30);
64+
/// assert_eq!(e.d.lock_irqsave().a, 20);
65+
/// assert_eq!(e.d.lock_irqsave().b, 30);
6466
/// ```
6567
///
6668
/// The following example shows how to use interior mutability to modify the contents of a struct
@@ -79,6 +81,12 @@ macro_rules! new_spinlock {
7981
/// guard.a += 10;
8082
/// guard.b += 20;
8183
/// }
84+
///
85+
/// fn example2(m: &SpinLock<Example>) {
86+
/// let mut guard = m.lock_irqsave();
87+
/// guard.a += 10;
88+
/// guard.b += 20;
89+
/// }
8290
/// ```
8391
///
8492
/// [`spinlock_t`]: ../../../../include/linux/spinlock.h
@@ -90,7 +98,7 @@ pub struct SpinLockBackend;
9098
// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
9199
unsafe impl super::Backend for SpinLockBackend {
92100
type State = bindings::spinlock_t;
93-
type GuardState = ();
101+
type GuardState = Option<core::ffi::c_ulong>;
94102

95103
unsafe fn init(
96104
ptr: *mut Self::State,
@@ -105,12 +113,30 @@ unsafe impl super::Backend for SpinLockBackend {
105113
unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState {
106114
// SAFETY: The safety requirements of this function ensure that `ptr` points to valid
107115
// memory, and that it has been initialised before.
108-
unsafe { bindings::spin_lock(ptr) }
116+
unsafe { bindings::spin_lock(ptr) };
117+
None
109118
}
110119

111-
unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) {
112-
// SAFETY: The safety requirements of this function ensure that `ptr` is valid and that the
113-
// caller is the owner of the mutex.
114-
unsafe { bindings::spin_unlock(ptr) }
120+
unsafe fn unlock(ptr: *mut Self::State, guard_state: &Self::GuardState) {
121+
match guard_state {
122+
// SAFETY: The safety requirements of this function ensure that `ptr` is valid and that
123+
// the caller is the owner of the mutex.
124+
Some(flags) => unsafe { bindings::spin_unlock_irqrestore(ptr, *flags) },
125+
// SAFETY: The safety requirements of this function ensure that `ptr` is valid and that
126+
// the caller is the owner of the mutex.
127+
None => unsafe { bindings::spin_unlock(ptr) },
128+
}
129+
}
130+
}
131+
132+
// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion. We use the `irqsave`
133+
// variant of the C lock acquisition functions to disable interrupts and retrieve the original
134+
// interrupt state, and the `irqrestore` variant of the lock release functions to restore the state
135+
// in `unlock` -- we use the guard context to determine which method was used to acquire the lock.
136+
unsafe impl super::IrqSaveBackend for SpinLockBackend {
137+
unsafe fn lock_irqsave(ptr: *mut Self::State) -> Self::GuardState {
138+
// SAFETY: The safety requirements of this function ensure that `ptr` points to valid
139+
// memory, and that it has been initialised before.
140+
Some(unsafe { bindings::spin_lock_irqsave(ptr) })
115141
}
116142
}

0 commit comments

Comments
 (0)