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