kernel/revocable.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Revocable objects.
4//!
5//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
6//! of a [`RevocableGuard`] ensures that objects remain valid.
7
8use pin_init::Wrapper;
9
10use crate::{
11 prelude::*,
12 sync::{
13 atomic::{
14 AtomicFlag,
15 Relaxed, //
16 },
17 rcu, //
18 },
19 types::Opaque, //
20};
21use core::{
22 marker::PhantomData,
23 ops::Deref,
24 ptr::drop_in_place, //
25};
26
27/// An object that can become inaccessible at runtime.
28///
29/// Once access is revoked and all concurrent users complete (i.e., all existing instances of
30/// [`RevocableGuard`] are dropped), the wrapped object is also dropped.
31///
32/// # Examples
33///
34/// ```
35/// # use kernel::revocable::Revocable;
36///
37/// struct Example {
38/// a: u32,
39/// b: u32,
40/// }
41///
42/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
43/// let guard = v.try_access()?;
44/// Some(guard.a + guard.b)
45/// }
46///
47/// let v = KBox::pin_init(Revocable::new(Example { a: 10, b: 20 }), GFP_KERNEL).unwrap();
48/// assert_eq!(add_two(&v), Some(30));
49/// v.revoke();
50/// assert_eq!(add_two(&v), None);
51/// ```
52///
53/// Sample example as above, but explicitly using the rcu read side lock.
54///
55/// ```
56/// # use kernel::revocable::Revocable;
57/// use kernel::sync::rcu;
58///
59/// struct Example {
60/// a: u32,
61/// b: u32,
62/// }
63///
64/// fn add_two(v: &Revocable<Example>) -> Option<u32> {
65/// let guard = rcu::read_lock();
66/// let e = v.try_access_with_guard(&guard)?;
67/// Some(e.a + e.b)
68/// }
69///
70/// let v = KBox::pin_init(Revocable::new(Example { a: 10, b: 20 }), GFP_KERNEL).unwrap();
71/// assert_eq!(add_two(&v), Some(30));
72/// v.revoke();
73/// assert_eq!(add_two(&v), None);
74/// ```
75#[pin_data(PinnedDrop)]
76pub struct Revocable<T> {
77 is_available: AtomicFlag,
78 #[pin]
79 data: Opaque<T>,
80}
81
82// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
83// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
84// this isn't supported by the wrapped object.
85unsafe impl<T: Send> Send for Revocable<T> {}
86
87// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
88// from the wrapped object as well because of `Revocable::revoke`, which can trigger the `Drop`
89// implementation of the wrapped object from an arbitrary thread.
90unsafe impl<T: Sync + Send> Sync for Revocable<T> {}
91
92impl<T> Revocable<T> {
93 /// Creates a new revocable instance of the given data.
94 pub fn new<E>(data: impl PinInit<T, E>) -> impl PinInit<Self, E> {
95 try_pin_init!(Self {
96 is_available: AtomicFlag::new(true),
97 data <- Opaque::pin_init(data),
98 }? E)
99 }
100
101 /// Tries to access the revocable wrapped object.
102 ///
103 /// Returns `None` if the object has been revoked and is therefore no longer accessible.
104 ///
105 /// Returns a guard that gives access to the object otherwise; the object is guaranteed to
106 /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
107 /// because another CPU may be waiting to complete the revocation of this object.
108 pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
109 let guard = rcu::read_lock();
110 if self.is_available.load(Relaxed) {
111 // Since `self.is_available` is true, data is initialised and has to remain valid
112 // because the RCU read side lock prevents it from being dropped.
113 Some(RevocableGuard::new(self.data.get(), guard))
114 } else {
115 None
116 }
117 }
118
119 /// Tries to access the revocable wrapped object.
120 ///
121 /// Returns `None` if the object has been revoked and is therefore no longer accessible.
122 ///
123 /// Returns a shared reference to the object otherwise; the object is guaranteed to
124 /// remain accessible while the rcu read side guard is alive. In such cases, callers are not
125 /// allowed to sleep because another CPU may be waiting to complete the revocation of this
126 /// object.
127 pub fn try_access_with_guard<'a>(&'a self, _guard: &'a rcu::Guard) -> Option<&'a T> {
128 if self.is_available.load(Relaxed) {
129 // SAFETY: Since `self.is_available` is true, data is initialised and has to remain
130 // valid because the RCU read side lock prevents it from being dropped.
131 Some(unsafe { &*self.data.get() })
132 } else {
133 None
134 }
135 }
136
137 /// Tries to access the wrapped object and run a closure on it while the guard is held.
138 ///
139 /// This is a convenience method to run short non-sleepable code blocks while ensuring the
140 /// guard is dropped afterwards. [`Self::try_access`] carries the risk that the caller will
141 /// forget to explicitly drop that returned guard before calling sleepable code; this method
142 /// adds an extra safety to make sure it doesn't happen.
143 ///
144 /// Returns [`None`] if the object has been revoked and is therefore no longer accessible, or
145 /// the result of the closure wrapped in [`Some`]. If the closure returns a [`Result`] then the
146 /// return type becomes `Option<Result<>>`, which can be inconvenient. Users are encouraged to
147 /// define their own macro that turns the [`Option`] into a proper error code and flattens the
148 /// inner result into it if it makes sense within their subsystem.
149 pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R> {
150 self.try_access().map(|t| f(&*t))
151 }
152
153 /// Directly access the revocable wrapped object.
154 ///
155 /// # Safety
156 ///
157 /// The caller must ensure this [`Revocable`] instance hasn't been revoked and won't be revoked
158 /// as long as the returned `&T` lives.
159 pub unsafe fn access(&self) -> &T {
160 // SAFETY: By the safety requirement of this function it is guaranteed that
161 // `self.data.get()` is a valid pointer to an instance of `T`.
162 unsafe { &*self.data.get() }
163 }
164
165 /// # Safety
166 ///
167 /// Callers must ensure that there are no more concurrent users of the revocable object.
168 unsafe fn revoke_internal<const SYNC: bool>(&self) -> bool {
169 let revoke = self.is_available.xchg(false, Relaxed);
170
171 if revoke {
172 if SYNC {
173 rcu::synchronize_rcu();
174 }
175
176 // SAFETY: We know `self.data` is valid because only one CPU can succeed the
177 // `compare_exchange` above that takes `is_available` from `true` to `false`.
178 unsafe { drop_in_place(self.data.get()) };
179 }
180
181 revoke
182 }
183
184 /// Revokes access to and drops the wrapped object.
185 ///
186 /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`],
187 /// expecting that there are no concurrent users of the object.
188 ///
189 /// Returns `true` if `&self` has been revoked with this call, `false` if it was revoked
190 /// already.
191 ///
192 /// # Safety
193 ///
194 /// Callers must ensure that there are no more concurrent users of the revocable object.
195 pub unsafe fn revoke_nosync(&self) -> bool {
196 // SAFETY: By the safety requirement of this function, the caller ensures that nobody is
197 // accessing the data anymore and hence we don't have to wait for the grace period to
198 // finish.
199 unsafe { self.revoke_internal::<false>() }
200 }
201
202 /// Revokes access to and drops the wrapped object.
203 ///
204 /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`].
205 ///
206 /// If there are concurrent users of the object (i.e., ones that called
207 /// [`Revocable::try_access`] beforehand and still haven't dropped the returned guard), this
208 /// function waits for the concurrent access to complete before dropping the wrapped object.
209 ///
210 /// Returns `true` if `&self` has been revoked with this call, `false` if it was revoked
211 /// already.
212 pub fn revoke(&self) -> bool {
213 // SAFETY: By passing `true` we ask `revoke_internal` to wait for the grace period to
214 // finish.
215 unsafe { self.revoke_internal::<true>() }
216 }
217}
218
219#[pinned_drop]
220impl<T> PinnedDrop for Revocable<T> {
221 fn drop(self: Pin<&mut Self>) {
222 // Drop only if the data hasn't been revoked yet (in which case it has already been
223 // dropped).
224 // SAFETY: We are not moving out of `p`, only dropping in place
225 let p = unsafe { self.get_unchecked_mut() };
226 if *p.is_available.get_mut() {
227 // SAFETY: We know `self.data` is valid because no other CPU has changed
228 // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
229 // holds the only reference (mutable) to `self` now.
230 unsafe { drop_in_place(p.data.get()) };
231 }
232 }
233}
234
235/// A guard that allows access to a revocable object and keeps it alive.
236///
237/// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context
238/// holding the RCU read-side lock.
239///
240/// # Invariants
241///
242/// The RCU read-side lock is held while the guard is alive.
243pub struct RevocableGuard<'a, T> {
244 // This can't use the `&'a T` type because references that appear in function arguments must
245 // not become dangling during the execution of the function, which can happen if the
246 // `RevocableGuard` is passed as a function argument and then dropped during execution of the
247 // function.
248 data_ref: *const T,
249 _rcu_guard: rcu::Guard,
250 _p: PhantomData<&'a ()>,
251}
252
253impl<T> RevocableGuard<'_, T> {
254 fn new(data_ref: *const T, rcu_guard: rcu::Guard) -> Self {
255 Self {
256 data_ref,
257 _rcu_guard: rcu_guard,
258 _p: PhantomData,
259 }
260 }
261}
262
263impl<T> Deref for RevocableGuard<'_, T> {
264 type Target = T;
265
266 fn deref(&self) -> &Self::Target {
267 // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is
268 // guaranteed to remain valid.
269 unsafe { &*self.data_ref }
270 }
271}