Skip to main content

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}