xref: /linux/rust/kernel/sync/srcu.rs (revision 9cc63f8bcd560c760d0b12e15bba8f81c86237cf)
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 
7 use crate::{
8     bindings,
9     error::to_result,
10     prelude::*,
11     sync::LockClassKey,
12     types::{
13         NotThreadSafe,
14         Opaque, //
15     },
16 };
17 
18 use 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]
23 macro_rules! new_srcu {
24     ($($name:literal)?) => {
25         $crate::sync::Srcu::new($crate::optional_name!($($name)?), $crate::static_lock_class!())
26     };
27 }
28 pub 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)]
43 pub struct Srcu {
44     #[pin]
45     inner: Opaque<bindings::srcu_struct>,
46 }
47 
48 impl 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]
102 impl 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.
139 unsafe impl Send for Srcu {}
140 // SAFETY: `srcu_struct` may be shared and used concurrently.
141 unsafe 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"]
152 pub struct Guard<'a> {
153     srcu: &'a Srcu,
154     idx: i32,
155     _not_send: NotThreadSafe,
156 }
157 
158 impl Guard<'_> {
159     /// Explicitly releases the SRCU read-side critical section.
160     #[inline]
161     pub fn unlock(self) {}
162 }
163 
164 impl 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 }
172