xref: /linux/rust/kernel/xarray.rs (revision ec7714e4947909190ffb3041a03311a975350fe0)
1*210b8157STamir Duberstein // SPDX-License-Identifier: GPL-2.0
2*210b8157STamir Duberstein 
3*210b8157STamir Duberstein //! XArray abstraction.
4*210b8157STamir Duberstein //!
5*210b8157STamir Duberstein //! C header: [`include/linux/xarray.h`](srctree/include/linux/xarray.h)
6*210b8157STamir Duberstein 
7*210b8157STamir Duberstein use crate::{
8*210b8157STamir Duberstein     alloc, bindings, build_assert,
9*210b8157STamir Duberstein     error::{Error, Result},
10*210b8157STamir Duberstein     types::{ForeignOwnable, NotThreadSafe, Opaque},
11*210b8157STamir Duberstein };
12*210b8157STamir Duberstein use core::{iter, marker::PhantomData, mem, pin::Pin, ptr::NonNull};
13*210b8157STamir Duberstein use pin_init::{pin_data, pin_init, pinned_drop, PinInit};
14*210b8157STamir Duberstein 
15*210b8157STamir Duberstein /// An array which efficiently maps sparse integer indices to owned objects.
16*210b8157STamir Duberstein ///
17*210b8157STamir Duberstein /// This is similar to a [`crate::alloc::kvec::Vec<Option<T>>`], but more efficient when there are
18*210b8157STamir Duberstein /// holes in the index space, and can be efficiently grown.
19*210b8157STamir Duberstein ///
20*210b8157STamir Duberstein /// # Invariants
21*210b8157STamir Duberstein ///
22*210b8157STamir Duberstein /// `self.xa` is always an initialized and valid [`bindings::xarray`] whose entries are either
23*210b8157STamir Duberstein /// `XA_ZERO_ENTRY` or came from `T::into_foreign`.
24*210b8157STamir Duberstein ///
25*210b8157STamir Duberstein /// # Examples
26*210b8157STamir Duberstein ///
27*210b8157STamir Duberstein /// ```rust
28*210b8157STamir Duberstein /// use kernel::alloc::KBox;
29*210b8157STamir Duberstein /// use kernel::xarray::{AllocKind, XArray};
30*210b8157STamir Duberstein ///
31*210b8157STamir Duberstein /// let xa = KBox::pin_init(XArray::new(AllocKind::Alloc1), GFP_KERNEL)?;
32*210b8157STamir Duberstein ///
33*210b8157STamir Duberstein /// let dead = KBox::new(0xdead, GFP_KERNEL)?;
34*210b8157STamir Duberstein /// let beef = KBox::new(0xbeef, GFP_KERNEL)?;
35*210b8157STamir Duberstein ///
36*210b8157STamir Duberstein /// let mut guard = xa.lock();
37*210b8157STamir Duberstein ///
38*210b8157STamir Duberstein /// assert_eq!(guard.get(0), None);
39*210b8157STamir Duberstein ///
40*210b8157STamir Duberstein /// assert_eq!(guard.store(0, dead, GFP_KERNEL)?.as_deref(), None);
41*210b8157STamir Duberstein /// assert_eq!(guard.get(0).copied(), Some(0xdead));
42*210b8157STamir Duberstein ///
43*210b8157STamir Duberstein /// *guard.get_mut(0).unwrap() = 0xffff;
44*210b8157STamir Duberstein /// assert_eq!(guard.get(0).copied(), Some(0xffff));
45*210b8157STamir Duberstein ///
46*210b8157STamir Duberstein /// assert_eq!(guard.store(0, beef, GFP_KERNEL)?.as_deref().copied(), Some(0xffff));
47*210b8157STamir Duberstein /// assert_eq!(guard.get(0).copied(), Some(0xbeef));
48*210b8157STamir Duberstein ///
49*210b8157STamir Duberstein /// guard.remove(0);
50*210b8157STamir Duberstein /// assert_eq!(guard.get(0), None);
51*210b8157STamir Duberstein ///
52*210b8157STamir Duberstein /// # Ok::<(), Error>(())
53*210b8157STamir Duberstein /// ```
54*210b8157STamir Duberstein #[pin_data(PinnedDrop)]
55*210b8157STamir Duberstein pub struct XArray<T: ForeignOwnable> {
56*210b8157STamir Duberstein     #[pin]
57*210b8157STamir Duberstein     xa: Opaque<bindings::xarray>,
58*210b8157STamir Duberstein     _p: PhantomData<T>,
59*210b8157STamir Duberstein }
60*210b8157STamir Duberstein 
61*210b8157STamir Duberstein #[pinned_drop]
62*210b8157STamir Duberstein impl<T: ForeignOwnable> PinnedDrop for XArray<T> {
drop(self: Pin<&mut Self>)63*210b8157STamir Duberstein     fn drop(self: Pin<&mut Self>) {
64*210b8157STamir Duberstein         self.iter().for_each(|ptr| {
65*210b8157STamir Duberstein             let ptr = ptr.as_ptr();
66*210b8157STamir Duberstein             // SAFETY: `ptr` came from `T::into_foreign`.
67*210b8157STamir Duberstein             //
68*210b8157STamir Duberstein             // INVARIANT: we own the only reference to the array which is being dropped so the
69*210b8157STamir Duberstein             // broken invariant is not observable on function exit.
70*210b8157STamir Duberstein             drop(unsafe { T::from_foreign(ptr) })
71*210b8157STamir Duberstein         });
72*210b8157STamir Duberstein 
73*210b8157STamir Duberstein         // SAFETY: `self.xa` is always valid by the type invariant.
74*210b8157STamir Duberstein         unsafe { bindings::xa_destroy(self.xa.get()) };
75*210b8157STamir Duberstein     }
76*210b8157STamir Duberstein }
77*210b8157STamir Duberstein 
78*210b8157STamir Duberstein /// Flags passed to [`XArray::new`] to configure the array's allocation tracking behavior.
79*210b8157STamir Duberstein pub enum AllocKind {
80*210b8157STamir Duberstein     /// Consider the first element to be at index 0.
81*210b8157STamir Duberstein     Alloc,
82*210b8157STamir Duberstein     /// Consider the first element to be at index 1.
83*210b8157STamir Duberstein     Alloc1,
84*210b8157STamir Duberstein }
85*210b8157STamir Duberstein 
86*210b8157STamir Duberstein impl<T: ForeignOwnable> XArray<T> {
87*210b8157STamir Duberstein     /// Creates a new initializer for this type.
new(kind: AllocKind) -> impl PinInit<Self>88*210b8157STamir Duberstein     pub fn new(kind: AllocKind) -> impl PinInit<Self> {
89*210b8157STamir Duberstein         let flags = match kind {
90*210b8157STamir Duberstein             AllocKind::Alloc => bindings::XA_FLAGS_ALLOC,
91*210b8157STamir Duberstein             AllocKind::Alloc1 => bindings::XA_FLAGS_ALLOC1,
92*210b8157STamir Duberstein         };
93*210b8157STamir Duberstein         pin_init!(Self {
94*210b8157STamir Duberstein             // SAFETY: `xa` is valid while the closure is called.
95*210b8157STamir Duberstein             //
96*210b8157STamir Duberstein             // INVARIANT: `xa` is initialized here to an empty, valid [`bindings::xarray`].
97*210b8157STamir Duberstein             xa <- Opaque::ffi_init(|xa| unsafe {
98*210b8157STamir Duberstein                 bindings::xa_init_flags(xa, flags)
99*210b8157STamir Duberstein             }),
100*210b8157STamir Duberstein             _p: PhantomData,
101*210b8157STamir Duberstein         })
102*210b8157STamir Duberstein     }
103*210b8157STamir Duberstein 
iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + '_104*210b8157STamir Duberstein     fn iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + '_ {
105*210b8157STamir Duberstein         let mut index = 0;
106*210b8157STamir Duberstein 
107*210b8157STamir Duberstein         // SAFETY: `self.xa` is always valid by the type invariant.
108*210b8157STamir Duberstein         iter::once(unsafe {
109*210b8157STamir Duberstein             bindings::xa_find(self.xa.get(), &mut index, usize::MAX, bindings::XA_PRESENT)
110*210b8157STamir Duberstein         })
111*210b8157STamir Duberstein         .chain(iter::from_fn(move || {
112*210b8157STamir Duberstein             // SAFETY: `self.xa` is always valid by the type invariant.
113*210b8157STamir Duberstein             Some(unsafe {
114*210b8157STamir Duberstein                 bindings::xa_find_after(self.xa.get(), &mut index, usize::MAX, bindings::XA_PRESENT)
115*210b8157STamir Duberstein             })
116*210b8157STamir Duberstein         }))
117*210b8157STamir Duberstein         .map_while(|ptr| NonNull::new(ptr.cast()))
118*210b8157STamir Duberstein     }
119*210b8157STamir Duberstein 
120*210b8157STamir Duberstein     /// Attempts to lock the [`XArray`] for exclusive access.
try_lock(&self) -> Option<Guard<'_, T>>121*210b8157STamir Duberstein     pub fn try_lock(&self) -> Option<Guard<'_, T>> {
122*210b8157STamir Duberstein         // SAFETY: `self.xa` is always valid by the type invariant.
123*210b8157STamir Duberstein         if (unsafe { bindings::xa_trylock(self.xa.get()) } != 0) {
124*210b8157STamir Duberstein             Some(Guard {
125*210b8157STamir Duberstein                 xa: self,
126*210b8157STamir Duberstein                 _not_send: NotThreadSafe,
127*210b8157STamir Duberstein             })
128*210b8157STamir Duberstein         } else {
129*210b8157STamir Duberstein             None
130*210b8157STamir Duberstein         }
131*210b8157STamir Duberstein     }
132*210b8157STamir Duberstein 
133*210b8157STamir Duberstein     /// Locks the [`XArray`] for exclusive access.
lock(&self) -> Guard<'_, T>134*210b8157STamir Duberstein     pub fn lock(&self) -> Guard<'_, T> {
135*210b8157STamir Duberstein         // SAFETY: `self.xa` is always valid by the type invariant.
136*210b8157STamir Duberstein         unsafe { bindings::xa_lock(self.xa.get()) };
137*210b8157STamir Duberstein 
138*210b8157STamir Duberstein         Guard {
139*210b8157STamir Duberstein             xa: self,
140*210b8157STamir Duberstein             _not_send: NotThreadSafe,
141*210b8157STamir Duberstein         }
142*210b8157STamir Duberstein     }
143*210b8157STamir Duberstein }
144*210b8157STamir Duberstein 
145*210b8157STamir Duberstein /// A lock guard.
146*210b8157STamir Duberstein ///
147*210b8157STamir Duberstein /// The lock is unlocked when the guard goes out of scope.
148*210b8157STamir Duberstein #[must_use = "the lock unlocks immediately when the guard is unused"]
149*210b8157STamir Duberstein pub struct Guard<'a, T: ForeignOwnable> {
150*210b8157STamir Duberstein     xa: &'a XArray<T>,
151*210b8157STamir Duberstein     _not_send: NotThreadSafe,
152*210b8157STamir Duberstein }
153*210b8157STamir Duberstein 
154*210b8157STamir Duberstein impl<T: ForeignOwnable> Drop for Guard<'_, T> {
drop(&mut self)155*210b8157STamir Duberstein     fn drop(&mut self) {
156*210b8157STamir Duberstein         // SAFETY:
157*210b8157STamir Duberstein         // - `self.xa.xa` is always valid by the type invariant.
158*210b8157STamir Duberstein         // - The caller holds the lock, so it is safe to unlock it.
159*210b8157STamir Duberstein         unsafe { bindings::xa_unlock(self.xa.xa.get()) };
160*210b8157STamir Duberstein     }
161*210b8157STamir Duberstein }
162*210b8157STamir Duberstein 
163*210b8157STamir Duberstein /// The error returned by [`store`](Guard::store).
164*210b8157STamir Duberstein ///
165*210b8157STamir Duberstein /// Contains the underlying error and the value that was not stored.
166*210b8157STamir Duberstein pub struct StoreError<T> {
167*210b8157STamir Duberstein     /// The error that occurred.
168*210b8157STamir Duberstein     pub error: Error,
169*210b8157STamir Duberstein     /// The value that was not stored.
170*210b8157STamir Duberstein     pub value: T,
171*210b8157STamir Duberstein }
172*210b8157STamir Duberstein 
173*210b8157STamir Duberstein impl<T> From<StoreError<T>> for Error {
from(value: StoreError<T>) -> Self174*210b8157STamir Duberstein     fn from(value: StoreError<T>) -> Self {
175*210b8157STamir Duberstein         value.error
176*210b8157STamir Duberstein     }
177*210b8157STamir Duberstein }
178*210b8157STamir Duberstein 
179*210b8157STamir Duberstein impl<'a, T: ForeignOwnable> Guard<'a, T> {
load<F, U>(&self, index: usize, f: F) -> Option<U> where F: FnOnce(NonNull<T::PointedTo>) -> U,180*210b8157STamir Duberstein     fn load<F, U>(&self, index: usize, f: F) -> Option<U>
181*210b8157STamir Duberstein     where
182*210b8157STamir Duberstein         F: FnOnce(NonNull<T::PointedTo>) -> U,
183*210b8157STamir Duberstein     {
184*210b8157STamir Duberstein         // SAFETY: `self.xa.xa` is always valid by the type invariant.
185*210b8157STamir Duberstein         let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), index) };
186*210b8157STamir Duberstein         let ptr = NonNull::new(ptr.cast())?;
187*210b8157STamir Duberstein         Some(f(ptr))
188*210b8157STamir Duberstein     }
189*210b8157STamir Duberstein 
190*210b8157STamir Duberstein     /// Provides a reference to the element at the given index.
get(&self, index: usize) -> Option<T::Borrowed<'_>>191*210b8157STamir Duberstein     pub fn get(&self, index: usize) -> Option<T::Borrowed<'_>> {
192*210b8157STamir Duberstein         self.load(index, |ptr| {
193*210b8157STamir Duberstein             // SAFETY: `ptr` came from `T::into_foreign`.
194*210b8157STamir Duberstein             unsafe { T::borrow(ptr.as_ptr()) }
195*210b8157STamir Duberstein         })
196*210b8157STamir Duberstein     }
197*210b8157STamir Duberstein 
198*210b8157STamir Duberstein     /// Provides a mutable reference to the element at the given index.
get_mut(&mut self, index: usize) -> Option<T::BorrowedMut<'_>>199*210b8157STamir Duberstein     pub fn get_mut(&mut self, index: usize) -> Option<T::BorrowedMut<'_>> {
200*210b8157STamir Duberstein         self.load(index, |ptr| {
201*210b8157STamir Duberstein             // SAFETY: `ptr` came from `T::into_foreign`.
202*210b8157STamir Duberstein             unsafe { T::borrow_mut(ptr.as_ptr()) }
203*210b8157STamir Duberstein         })
204*210b8157STamir Duberstein     }
205*210b8157STamir Duberstein 
206*210b8157STamir Duberstein     /// Removes and returns the element at the given index.
remove(&mut self, index: usize) -> Option<T>207*210b8157STamir Duberstein     pub fn remove(&mut self, index: usize) -> Option<T> {
208*210b8157STamir Duberstein         // SAFETY:
209*210b8157STamir Duberstein         // - `self.xa.xa` is always valid by the type invariant.
210*210b8157STamir Duberstein         // - The caller holds the lock.
211*210b8157STamir Duberstein         let ptr = unsafe { bindings::__xa_erase(self.xa.xa.get(), index) }.cast();
212*210b8157STamir Duberstein         // SAFETY:
213*210b8157STamir Duberstein         // - `ptr` is either NULL or came from `T::into_foreign`.
214*210b8157STamir Duberstein         // - `&mut self` guarantees that the lifetimes of [`T::Borrowed`] and [`T::BorrowedMut`]
215*210b8157STamir Duberstein         // borrowed from `self` have ended.
216*210b8157STamir Duberstein         unsafe { T::try_from_foreign(ptr) }
217*210b8157STamir Duberstein     }
218*210b8157STamir Duberstein 
219*210b8157STamir Duberstein     /// Stores an element at the given index.
220*210b8157STamir Duberstein     ///
221*210b8157STamir Duberstein     /// May drop the lock if needed to allocate memory, and then reacquire it afterwards.
222*210b8157STamir Duberstein     ///
223*210b8157STamir Duberstein     /// On success, returns the element which was previously at the given index.
224*210b8157STamir Duberstein     ///
225*210b8157STamir Duberstein     /// On failure, returns the element which was attempted to be stored.
store( &mut self, index: usize, value: T, gfp: alloc::Flags, ) -> Result<Option<T>, StoreError<T>>226*210b8157STamir Duberstein     pub fn store(
227*210b8157STamir Duberstein         &mut self,
228*210b8157STamir Duberstein         index: usize,
229*210b8157STamir Duberstein         value: T,
230*210b8157STamir Duberstein         gfp: alloc::Flags,
231*210b8157STamir Duberstein     ) -> Result<Option<T>, StoreError<T>> {
232*210b8157STamir Duberstein         build_assert!(
233*210b8157STamir Duberstein             mem::align_of::<T::PointedTo>() >= 4,
234*210b8157STamir Duberstein             "pointers stored in XArray must be 4-byte aligned"
235*210b8157STamir Duberstein         );
236*210b8157STamir Duberstein         let new = value.into_foreign();
237*210b8157STamir Duberstein 
238*210b8157STamir Duberstein         let old = {
239*210b8157STamir Duberstein             let new = new.cast();
240*210b8157STamir Duberstein             // SAFETY:
241*210b8157STamir Duberstein             // - `self.xa.xa` is always valid by the type invariant.
242*210b8157STamir Duberstein             // - The caller holds the lock.
243*210b8157STamir Duberstein             //
244*210b8157STamir Duberstein             // INVARIANT: `new` came from `T::into_foreign`.
245*210b8157STamir Duberstein             unsafe { bindings::__xa_store(self.xa.xa.get(), index, new, gfp.as_raw()) }
246*210b8157STamir Duberstein         };
247*210b8157STamir Duberstein 
248*210b8157STamir Duberstein         // SAFETY: `__xa_store` returns the old entry at this index on success or `xa_err` if an
249*210b8157STamir Duberstein         // error happened.
250*210b8157STamir Duberstein         let errno = unsafe { bindings::xa_err(old) };
251*210b8157STamir Duberstein         if errno != 0 {
252*210b8157STamir Duberstein             // SAFETY: `new` came from `T::into_foreign` and `__xa_store` does not take
253*210b8157STamir Duberstein             // ownership of the value on error.
254*210b8157STamir Duberstein             let value = unsafe { T::from_foreign(new) };
255*210b8157STamir Duberstein             Err(StoreError {
256*210b8157STamir Duberstein                 value,
257*210b8157STamir Duberstein                 error: Error::from_errno(errno),
258*210b8157STamir Duberstein             })
259*210b8157STamir Duberstein         } else {
260*210b8157STamir Duberstein             let old = old.cast();
261*210b8157STamir Duberstein             // SAFETY: `ptr` is either NULL or came from `T::into_foreign`.
262*210b8157STamir Duberstein             //
263*210b8157STamir Duberstein             // NB: `XA_ZERO_ENTRY` is never returned by functions belonging to the Normal XArray
264*210b8157STamir Duberstein             // API; such entries present as `NULL`.
265*210b8157STamir Duberstein             Ok(unsafe { T::try_from_foreign(old) })
266*210b8157STamir Duberstein         }
267*210b8157STamir Duberstein     }
268*210b8157STamir Duberstein }
269*210b8157STamir Duberstein 
270*210b8157STamir Duberstein // SAFETY: `XArray<T>` has no shared mutable state so it is `Send` iff `T` is `Send`.
271*210b8157STamir Duberstein unsafe impl<T: ForeignOwnable + Send> Send for XArray<T> {}
272*210b8157STamir Duberstein 
273*210b8157STamir Duberstein // SAFETY: `XArray<T>` serialises the interior mutability it provides so it is `Sync` iff `T` is
274*210b8157STamir Duberstein // `Send`.
275*210b8157STamir Duberstein unsafe impl<T: ForeignOwnable + Send> Sync for XArray<T> {}
276