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