xref: /linux/rust/kernel/sync/srcu.rs (revision 83684c4e4d62cb02b2e4d0d18963d1035439278e)
1*59cf3a5bSOnur Özkan // SPDX-License-Identifier: GPL-2.0
2*59cf3a5bSOnur Özkan 
3*59cf3a5bSOnur Özkan //! Sleepable read-copy update (SRCU) support.
4*59cf3a5bSOnur Özkan //!
5*59cf3a5bSOnur Özkan //! C header: [`include/linux/srcu.h`](srctree/include/linux/srcu.h)
6*59cf3a5bSOnur Özkan 
7*59cf3a5bSOnur Özkan use crate::{
8*59cf3a5bSOnur Özkan     bindings,
9*59cf3a5bSOnur Özkan     error::to_result,
10*59cf3a5bSOnur Özkan     prelude::*,
11*59cf3a5bSOnur Özkan     sync::LockClassKey,
12*59cf3a5bSOnur Özkan     types::{
13*59cf3a5bSOnur Özkan         NotThreadSafe,
14*59cf3a5bSOnur Özkan         Opaque, //
15*59cf3a5bSOnur Özkan     },
16*59cf3a5bSOnur Özkan };
17*59cf3a5bSOnur Özkan 
18*59cf3a5bSOnur Özkan use pin_init::pin_data;
19*59cf3a5bSOnur Özkan 
20*59cf3a5bSOnur Özkan /// Creates an [`Srcu`] initialiser with the given name and a newly-created lock class.
21*59cf3a5bSOnur Özkan #[doc(hidden)]
22*59cf3a5bSOnur Özkan #[macro_export]
23*59cf3a5bSOnur Özkan macro_rules! new_srcu {
24*59cf3a5bSOnur Özkan     ($($name:literal)?) => {
25*59cf3a5bSOnur Özkan         $crate::sync::Srcu::new($crate::optional_name!($($name)?), $crate::static_lock_class!())
26*59cf3a5bSOnur Özkan     };
27*59cf3a5bSOnur Özkan }
28*59cf3a5bSOnur Özkan pub use new_srcu;
29*59cf3a5bSOnur Özkan 
30*59cf3a5bSOnur Özkan /// Sleepable read-copy update primitive.
31*59cf3a5bSOnur Özkan ///
32*59cf3a5bSOnur Özkan /// SRCU readers may sleep while holding the read-side guard.
33*59cf3a5bSOnur Özkan ///
34*59cf3a5bSOnur Özkan /// The destructor waits for active readers and callbacks, so it may sleep.
35*59cf3a5bSOnur Özkan /// If a read-side guard has been leaked, dropping an [`Srcu`] may never return.
36*59cf3a5bSOnur Özkan ///
37*59cf3a5bSOnur Özkan /// # Invariants
38*59cf3a5bSOnur Özkan ///
39*59cf3a5bSOnur Özkan /// This represents a valid `struct srcu_struct` initialized by the C SRCU API
40*59cf3a5bSOnur Özkan /// and it remains pinned and valid until the pinned destructor runs.
41*59cf3a5bSOnur Özkan #[repr(transparent)]
42*59cf3a5bSOnur Özkan #[pin_data(PinnedDrop)]
43*59cf3a5bSOnur Özkan pub struct Srcu {
44*59cf3a5bSOnur Özkan     #[pin]
45*59cf3a5bSOnur Özkan     inner: Opaque<bindings::srcu_struct>,
46*59cf3a5bSOnur Özkan }
47*59cf3a5bSOnur Özkan 
48*59cf3a5bSOnur Özkan impl Srcu {
49*59cf3a5bSOnur Özkan     /// Creates a new SRCU instance.
50*59cf3a5bSOnur Özkan     #[inline]
new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self, Error>51*59cf3a5bSOnur Özkan     pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self, Error> {
52*59cf3a5bSOnur Özkan         try_pin_init!(Self {
53*59cf3a5bSOnur Özkan             // INVARIANT: On success, the C initializer creates a valid `srcu_struct` and
54*59cf3a5bSOnur Özkan             // it remains pinned until `PinnedDrop` runs.
55*59cf3a5bSOnur Özkan             inner <- Opaque::try_ffi_init(|ptr: *mut bindings::srcu_struct| {
56*59cf3a5bSOnur Özkan                 // SAFETY: `ptr` points to valid uninitialised memory for a `srcu_struct`.
57*59cf3a5bSOnur Özkan                 to_result(unsafe {
58*59cf3a5bSOnur Özkan                     bindings::init_srcu_struct_with_key(ptr, name.as_char_ptr(), key.as_ptr())
59*59cf3a5bSOnur Özkan                 })
60*59cf3a5bSOnur Özkan             }),
61*59cf3a5bSOnur Özkan         })
62*59cf3a5bSOnur Özkan     }
63*59cf3a5bSOnur Özkan 
64*59cf3a5bSOnur Özkan     /// Enters an SRCU read-side critical section.
65*59cf3a5bSOnur Özkan     ///
66*59cf3a5bSOnur Özkan     /// Leaking the returned [`Guard`] leaves the SRCU read-side critical
67*59cf3a5bSOnur Özkan     /// section active and makes `drop` sleep forever.
68*59cf3a5bSOnur Özkan     #[inline]
read_lock(&self) -> Guard<'_>69*59cf3a5bSOnur Özkan     pub fn read_lock(&self) -> Guard<'_> {
70*59cf3a5bSOnur Özkan         // SAFETY: By the type invariants, `self` contains a valid `struct srcu_struct`.
71*59cf3a5bSOnur Özkan         let idx = unsafe { bindings::srcu_read_lock(self.inner.get()) };
72*59cf3a5bSOnur Özkan 
73*59cf3a5bSOnur Özkan         // INVARIANT: `idx` was returned by `srcu_read_lock()` for this `Srcu`.
74*59cf3a5bSOnur Özkan         Guard {
75*59cf3a5bSOnur Özkan             srcu: self,
76*59cf3a5bSOnur Özkan             idx,
77*59cf3a5bSOnur Özkan             _not_send: NotThreadSafe,
78*59cf3a5bSOnur Özkan         }
79*59cf3a5bSOnur Özkan     }
80*59cf3a5bSOnur Özkan 
81*59cf3a5bSOnur Özkan     /// Waits until all pre-existing SRCU readers have completed.
82*59cf3a5bSOnur Özkan     #[inline]
synchronize(&self)83*59cf3a5bSOnur Özkan     pub fn synchronize(&self) {
84*59cf3a5bSOnur Özkan         // SAFETY: By the type invariants, `self` contains a valid `struct srcu_struct`.
85*59cf3a5bSOnur Özkan         unsafe { bindings::synchronize_srcu(self.inner.get()) };
86*59cf3a5bSOnur Özkan     }
87*59cf3a5bSOnur Özkan 
88*59cf3a5bSOnur Özkan     /// Waits until all pre-existing SRCU readers have completed, expedited.
89*59cf3a5bSOnur Özkan     ///
90*59cf3a5bSOnur Özkan     /// This requests a lower-latency grace period than [`Srcu::synchronize`] typically
91*59cf3a5bSOnur Özkan     /// at the cost of higher system-wide overhead. Prefer [`Srcu::synchronize`] by default
92*59cf3a5bSOnur Özkan     /// and use this variant only when reducing reset or teardown latency is more important
93*59cf3a5bSOnur Özkan     /// than the extra cost.
94*59cf3a5bSOnur Özkan     #[inline]
synchronize_expedited(&self)95*59cf3a5bSOnur Özkan     pub fn synchronize_expedited(&self) {
96*59cf3a5bSOnur Özkan         // SAFETY: By the type invariants, `self` contains a valid `struct srcu_struct`.
97*59cf3a5bSOnur Özkan         unsafe { bindings::synchronize_srcu_expedited(self.inner.get()) };
98*59cf3a5bSOnur Özkan     }
99*59cf3a5bSOnur Özkan }
100*59cf3a5bSOnur Özkan 
101*59cf3a5bSOnur Özkan #[pinned_drop]
102*59cf3a5bSOnur Özkan impl PinnedDrop for Srcu {
drop(self: Pin<&mut Self>)103*59cf3a5bSOnur Özkan     fn drop(self: Pin<&mut Self>) {
104*59cf3a5bSOnur Özkan         let ptr = self.inner.get();
105*59cf3a5bSOnur Özkan 
106*59cf3a5bSOnur Özkan         if crate::warn_on!(
107*59cf3a5bSOnur Özkan             // SAFETY: By the type invariants, `self` contains a valid and pinned `struct srcu_struct`
108*59cf3a5bSOnur Özkan             // and `srcu_readers_active()` only checks the active reader count.
109*59cf3a5bSOnur Özkan             unsafe { bindings::srcu_readers_active(ptr) }
110*59cf3a5bSOnur Özkan         ) {
111*59cf3a5bSOnur Özkan             // `cleanup_srcu_struct()` may return early if there are still active readers.
112*59cf3a5bSOnur Özkan             // This should only happen if a guard was leaked with `mem::forget`, which is
113*59cf3a5bSOnur Özkan             // "WRONG" code and may cause a UAF because Rust will free the `srcu_struct`
114*59cf3a5bSOnur Özkan             // while it is still referenced from the C side (e.g. by `call_srcu()` callbacks).
115*59cf3a5bSOnur Özkan             //
116*59cf3a5bSOnur Özkan             // Another consequence of leaking guards is that `call_srcu()` callbacks will
117*59cf3a5bSOnur Özkan             // never run because the grace period can never complete due to permanently
118*59cf3a5bSOnur Özkan             // active readers (i.e. leaked guards).
119*59cf3a5bSOnur Özkan             //
120*59cf3a5bSOnur Özkan             // If this ever happens, that means the guard was leaked by mistake and the
121*59cf3a5bSOnur Özkan             // caller must fix the bug. Sleeping here is intentional and less harmful
122*59cf3a5bSOnur Özkan             // than risking a UAF.
123*59cf3a5bSOnur Özkan             //
124*59cf3a5bSOnur Özkan             // SAFETY: By the type invariants, `self` contains a valid and pinned
125*59cf3a5bSOnur Özkan             // `struct srcu_struct`.
126*59cf3a5bSOnur Özkan             unsafe { bindings::synchronize_srcu(ptr) };
127*59cf3a5bSOnur Özkan         }
128*59cf3a5bSOnur Özkan 
129*59cf3a5bSOnur Özkan         // Ensure all SRCU callbacks have been finished before freeing.
130*59cf3a5bSOnur Özkan         // SAFETY: By the type invariants, `self` contains a valid and pinned `struct srcu_struct`.
131*59cf3a5bSOnur Özkan         unsafe { bindings::srcu_barrier(ptr) };
132*59cf3a5bSOnur Özkan 
133*59cf3a5bSOnur Özkan         // SAFETY: By the type invariants, `self` contains a valid and pinned `struct srcu_struct`.
134*59cf3a5bSOnur Özkan         unsafe { bindings::cleanup_srcu_struct(ptr) };
135*59cf3a5bSOnur Özkan     }
136*59cf3a5bSOnur Özkan }
137*59cf3a5bSOnur Özkan 
138*59cf3a5bSOnur Özkan // SAFETY: `srcu_struct` may be shared and used across threads.
139*59cf3a5bSOnur Özkan unsafe impl Send for Srcu {}
140*59cf3a5bSOnur Özkan // SAFETY: `srcu_struct` may be shared and used concurrently.
141*59cf3a5bSOnur Özkan unsafe impl Sync for Srcu {}
142*59cf3a5bSOnur Özkan 
143*59cf3a5bSOnur Özkan /// Guard for an active SRCU read-side critical section on a particular [`Srcu`].
144*59cf3a5bSOnur Özkan ///
145*59cf3a5bSOnur Özkan /// Leaking this guard with [`core::mem::forget`] leaves the SRCU read-side
146*59cf3a5bSOnur Özkan /// critical section active and makes dropping the associated [`Srcu`] sleep forever.
147*59cf3a5bSOnur Özkan ///
148*59cf3a5bSOnur Özkan /// # Invariants
149*59cf3a5bSOnur Özkan ///
150*59cf3a5bSOnur Özkan /// `idx` is the index returned by `srcu_read_lock()` for `srcu`.
151*59cf3a5bSOnur Özkan #[must_use = "if unused, the lock will be immediately unlocked"]
152*59cf3a5bSOnur Özkan pub struct Guard<'a> {
153*59cf3a5bSOnur Özkan     srcu: &'a Srcu,
154*59cf3a5bSOnur Özkan     idx: i32,
155*59cf3a5bSOnur Özkan     _not_send: NotThreadSafe,
156*59cf3a5bSOnur Özkan }
157*59cf3a5bSOnur Özkan 
158*59cf3a5bSOnur Özkan impl Guard<'_> {
159*59cf3a5bSOnur Özkan     /// Explicitly releases the SRCU read-side critical section.
160*59cf3a5bSOnur Özkan     #[inline]
unlock(self)161*59cf3a5bSOnur Özkan     pub fn unlock(self) {}
162*59cf3a5bSOnur Özkan }
163*59cf3a5bSOnur Özkan 
164*59cf3a5bSOnur Özkan impl Drop for Guard<'_> {
165*59cf3a5bSOnur Özkan     #[inline]
drop(&mut self)166*59cf3a5bSOnur Özkan     fn drop(&mut self) {
167*59cf3a5bSOnur Özkan         // SAFETY: `Guard` is only constructible through `Srcu::read_lock()`,
168*59cf3a5bSOnur Özkan         // which returns a valid index for the SRCU instance.
169*59cf3a5bSOnur Özkan         unsafe { bindings::srcu_read_unlock(self.srcu.inner.get(), self.idx) };
170*59cf3a5bSOnur Özkan     }
171*59cf3a5bSOnur Özkan }
172