Skip to content

Commit 50a0816

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 3df09ba commit 50a0816

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

rust/helpers.c

Lines changed: 16 additions & 0 deletions
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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ macro_rules! new_spinlock {
5555
/// assert_eq!(e.c, 10);
5656
/// assert_eq!(e.d.lock().a, 20);
5757
/// assert_eq!(e.d.lock().b, 30);
58+
/// assert_eq!(e.d.lock_irqsave().a, 20);
59+
/// assert_eq!(e.d.lock_irqsave().b, 30);
5860
/// ```
5961
///
6062
/// The following example shows how to use interior mutability to modify the contents of a struct
@@ -73,6 +75,12 @@ macro_rules! new_spinlock {
7375
/// guard.a += 10;
7476
/// guard.b += 20;
7577
/// }
78+
///
79+
/// fn example2(m: &SpinLock<Example>) {
80+
/// let mut guard = m.lock_irqsave();
81+
/// guard.a += 10;
82+
/// guard.b += 20;
83+
/// }
7684
/// ```
7785
///
7886
/// [`spinlock_t`]: ../../../../include/linux/spinlock.h
@@ -84,7 +92,7 @@ pub struct SpinLockBackend;
8492
// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion.
8593
unsafe impl super::Backend for SpinLockBackend {
8694
type State = bindings::spinlock_t;
87-
type GuardState = ();
95+
type GuardState = Option<core::ffi::c_ulong>;
8896

8997
unsafe fn init(
9098
ptr: *mut Self::State,
@@ -99,12 +107,30 @@ unsafe impl super::Backend for SpinLockBackend {
99107
unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState {
100108
// SAFETY: The safety requirements of this function ensure that `ptr` points to valid
101109
// memory, and that it has been initialised before.
102-
unsafe { bindings::spin_lock(ptr) }
110+
unsafe { bindings::spin_lock(ptr) };
111+
None
103112
}
104113

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

0 commit comments

Comments
 (0)