| // SPDX-License-Identifier: GPL-2.0 | |
| //! Sleepable read-copy update (SRCU) support. | |
| //! | |
| //! C header: [`include/linux/srcu.h`](srctree/include/linux/srcu.h) | |
| use crate::{ | |
| bindings, | |
| error::to_result, | |
| prelude::*, | |
| sync::LockClassKey, | |
| types::{ | |
| NotThreadSafe, | |
| Opaque, // | |
| }, | |
| }; | |
| use pin_init::pin_data; | |
| /// Creates an [`Srcu`] initialiser with the given name and a newly-created lock class. | |
| #[doc(hidden)] | |
| #[macro_export] | |
| macro_rules! new_srcu { | |
| ($($name:literal)?) => { | |
| $crate::sync::Srcu::new($crate::optional_name!($($name)?), $crate::static_lock_class!()) | |
| }; | |
| } | |
| pub use new_srcu; | |
| /// Sleepable read-copy update primitive. | |
| /// | |
| /// SRCU readers may sleep while holding the read-side guard. | |
| /// | |
| /// The destructor waits for active readers and callbacks, so it may sleep. | |
| /// If a read-side guard has been leaked, dropping an [`Srcu`] may never return. | |
| /// | |
| /// # Invariants | |
| /// | |
| /// This represents a valid `struct srcu_struct` initialized by the C SRCU API | |
| /// and it remains pinned and valid until the pinned destructor runs. | |
| #[repr(transparent)] | |
| #[pin_data(PinnedDrop)] | |
| pub struct Srcu { | |
| #[pin] | |
| inner: Opaque<bindings::srcu_struct>, | |
| } | |
| impl Srcu { | |
| /// Creates a new SRCU instance. | |
| #[inline] | |
| pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self, Error> { | |
| try_pin_init!(Self { | |
| // INVARIANT: On success, the C initializer creates a valid `srcu_struct` and | |
| // it remains pinned until `PinnedDrop` runs. | |
| inner <- Opaque::try_ffi_init(|ptr: *mut bindings::srcu_struct| { | |
| // SAFETY: `ptr` points to valid uninitialised memory for a `srcu_struct`. | |
| to_result(unsafe { | |
| bindings::init_srcu_struct_with_key(ptr, name.as_char_ptr(), key.as_ptr()) | |
| }) | |
| }), | |
| }) | |
| } | |
| /// Enters an SRCU read-side critical section. | |
| /// | |
| /// Leaking the returned [`Guard`] leaves the SRCU read-side critical | |
| /// section active and makes `drop` sleep forever. | |
| #[inline] | |
| pub fn read_lock(&self) -> Guard<'_> { | |
| // SAFETY: By the type invariants, `self` contains a valid `struct srcu_struct`. | |
| let idx = unsafe { bindings::srcu_read_lock(self.inner.get()) }; | |
| // INVARIANT: `idx` was returned by `srcu_read_lock()` for this `Srcu`. | |
| Guard { | |
| srcu: self, | |
| idx, | |
| _not_send: NotThreadSafe, | |
| } | |
| } | |
| /// Waits until all pre-existing SRCU readers have completed. | |
| #[inline] | |
| pub fn synchronize(&self) { | |
| // SAFETY: By the type invariants, `self` contains a valid `struct srcu_struct`. | |
| unsafe { bindings::synchronize_srcu(self.inner.get()) }; | |
| } | |
| /// Waits until all pre-existing SRCU readers have completed, expedited. | |
| /// | |
| /// This requests a lower-latency grace period than [`Srcu::synchronize`] typically | |
| /// at the cost of higher system-wide overhead. Prefer [`Srcu::synchronize`] by default | |
| /// and use this variant only when reducing reset or teardown latency is more important | |
| /// than the extra cost. | |
| #[inline] | |
| pub fn synchronize_expedited(&self) { | |
| // SAFETY: By the type invariants, `self` contains a valid `struct srcu_struct`. | |
| unsafe { bindings::synchronize_srcu_expedited(self.inner.get()) }; | |
| } | |
| } | |
| #[pinned_drop] | |
| impl PinnedDrop for Srcu { | |
| fn drop(self: Pin<&mut Self>) { | |
| let ptr = self.inner.get(); | |
| if crate::warn_on!( | |
| // SAFETY: By the type invariants, `self` contains a valid and pinned `struct srcu_struct` | |
| // and `srcu_readers_active()` only checks the active reader count. | |
| unsafe { bindings::srcu_readers_active(ptr) } | |
| ) { | |
| // `cleanup_srcu_struct()` may return early if there are still active readers. | |
| // This should only happen if a guard was leaked with `mem::forget`, which is | |
| // "WRONG" code and may cause a UAF because Rust will free the `srcu_struct` | |
| // while it is still referenced from the C side (e.g. by `call_srcu()` callbacks). | |
| // | |
| // Another consequence of leaking guards is that `call_srcu()` callbacks will | |
| // never run because the grace period can never complete due to permanently | |
| // active readers (i.e. leaked guards). | |
| // | |
| // If this ever happens, that means the guard was leaked by mistake and the | |
| // caller must fix the bug. Sleeping here is intentional and less harmful | |
| // than risking a UAF. | |
| // | |
| // SAFETY: By the type invariants, `self` contains a valid and pinned | |
| // `struct srcu_struct`. | |
| unsafe { bindings::synchronize_srcu(ptr) }; | |
| } | |
| // Ensure all SRCU callbacks have been finished before freeing. | |
| // SAFETY: By the type invariants, `self` contains a valid and pinned `struct srcu_struct`. | |
| unsafe { bindings::srcu_barrier(ptr) }; | |
| // SAFETY: By the type invariants, `self` contains a valid and pinned `struct srcu_struct`. | |
| unsafe { bindings::cleanup_srcu_struct(ptr) }; | |
| } | |
| } | |
| // SAFETY: `srcu_struct` may be shared and used across threads. | |
| unsafe impl Send for Srcu {} | |
| // SAFETY: `srcu_struct` may be shared and used concurrently. | |
| unsafe impl Sync for Srcu {} | |
| /// Guard for an active SRCU read-side critical section on a particular [`Srcu`]. | |
| /// | |
| /// Leaking this guard with [`core::mem::forget`] leaves the SRCU read-side | |
| /// critical section active and makes dropping the associated [`Srcu`] sleep forever. | |
| /// | |
| /// # Invariants | |
| /// | |
| /// `idx` is the index returned by `srcu_read_lock()` for `srcu`. | |
| #[must_use = "if unused, the lock will be immediately unlocked"] | |
| pub struct Guard<'a> { | |
| srcu: &'a Srcu, | |
| idx: i32, | |
| _not_send: NotThreadSafe, | |
| } | |
| impl Guard<'_> { | |
| /// Explicitly releases the SRCU read-side critical section. | |
| #[inline] | |
| pub fn unlock(self) {} | |
| } | |
| impl Drop for Guard<'_> { | |
| #[inline] | |
| fn drop(&mut self) { | |
| // SAFETY: `Guard` is only constructible through `Srcu::read_lock()`, | |
| // which returns a valid index for the SRCU instance. | |
| unsafe { bindings::srcu_read_unlock(self.srcu.inner.get(), self.idx) }; | |
| } | |
| } |