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