// SPDX-License-Identifier: GPL-2.0 //! Maple trees. //! //! C header: [`include/linux/maple_tree.h`](srctree/include/linux/maple_tree.h) //! //! Reference: use core::{ marker::PhantomData, ops::{Bound, RangeBounds}, ptr, }; use kernel::{ alloc::Flags, error::to_result, prelude::*, types::{ForeignOwnable, Opaque}, }; /// A maple tree optimized for storing non-overlapping ranges. /// /// # Invariants /// /// Each range in the maple tree owns an instance of `T`. #[pin_data(PinnedDrop)] #[repr(transparent)] pub struct MapleTree { #[pin] tree: Opaque, _p: PhantomData, } /// A maple tree with `MT_FLAGS_ALLOC_RANGE` set. /// /// All methods on [`MapleTree`] are also accessible on this type. #[pin_data] #[repr(transparent)] pub struct MapleTreeAlloc { #[pin] tree: MapleTree, } // Make MapleTree methods usable on MapleTreeAlloc. impl core::ops::Deref for MapleTreeAlloc { type Target = MapleTree; #[inline] fn deref(&self) -> &MapleTree { &self.tree } } #[inline] fn to_maple_range(range: impl RangeBounds) -> Option<(usize, usize)> { let first = match range.start_bound() { Bound::Included(start) => *start, Bound::Excluded(start) => start.checked_add(1)?, Bound::Unbounded => 0, }; let last = match range.end_bound() { Bound::Included(end) => *end, Bound::Excluded(end) => end.checked_sub(1)?, Bound::Unbounded => usize::MAX, }; if last < first { return None; } Some((first, last)) } impl MapleTree { /// Create a new maple tree. /// /// The tree will use the regular implementation with a higher branching factor, rather than /// the allocation tree. #[inline] pub fn new() -> impl PinInit { pin_init!(MapleTree { // SAFETY: This initializes a maple tree into a pinned slot. The maple tree will be // destroyed in Drop before the memory location becomes invalid. tree <- Opaque::ffi_init(|slot| unsafe { bindings::mt_init_flags(slot, 0) }), _p: PhantomData, }) } /// Insert the value at the given index. /// /// # Errors /// /// If the maple tree already contains a range using the given index, then this call will /// return an [`InsertErrorKind::Occupied`]. It may also fail if memory allocation fails. /// /// # Examples /// /// ``` /// use kernel::maple_tree::{InsertErrorKind, MapleTree}; /// /// let tree = KBox::pin_init(MapleTree::>::new(), GFP_KERNEL)?; /// /// let ten = KBox::new(10, GFP_KERNEL)?; /// let twenty = KBox::new(20, GFP_KERNEL)?; /// let the_answer = KBox::new(42, GFP_KERNEL)?; /// /// // These calls will succeed. /// tree.insert(100, ten, GFP_KERNEL)?; /// tree.insert(101, twenty, GFP_KERNEL)?; /// /// // This will fail because the index is already in use. /// assert_eq!( /// tree.insert(100, the_answer, GFP_KERNEL).unwrap_err().cause, /// InsertErrorKind::Occupied, /// ); /// # Ok::<_, Error>(()) /// ``` #[inline] pub fn insert(&self, index: usize, value: T, gfp: Flags) -> Result<(), InsertError> { self.insert_range(index..=index, value, gfp) } /// Insert a value to the specified range, failing on overlap. /// /// This accepts the usual types of Rust ranges using the `..` and `..=` syntax for exclusive /// and inclusive ranges respectively. The range must not be empty, and must not overlap with /// any existing range. /// /// # Errors /// /// If the maple tree already contains an overlapping range, then this call will return an /// [`InsertErrorKind::Occupied`]. It may also fail if memory allocation fails or if the /// requested range is invalid (e.g. empty). /// /// # Examples /// /// ``` /// use kernel::maple_tree::{InsertErrorKind, MapleTree}; /// /// let tree = KBox::pin_init(MapleTree::>::new(), GFP_KERNEL)?; /// /// let ten = KBox::new(10, GFP_KERNEL)?; /// let twenty = KBox::new(20, GFP_KERNEL)?; /// let the_answer = KBox::new(42, GFP_KERNEL)?; /// let hundred = KBox::new(100, GFP_KERNEL)?; /// /// // Insert the value 10 at the indices 100 to 499. /// tree.insert_range(100..500, ten, GFP_KERNEL)?; /// /// // Insert the value 20 at the indices 500 to 1000. /// tree.insert_range(500..=1000, twenty, GFP_KERNEL)?; /// /// // This will fail due to overlap with the previous range on index 1000. /// assert_eq!( /// tree.insert_range(1000..1200, the_answer, GFP_KERNEL).unwrap_err().cause, /// InsertErrorKind::Occupied, /// ); /// /// // When using .. to specify the range, you must be careful to ensure that the range is /// // non-empty. /// assert_eq!( /// tree.insert_range(72..72, hundred, GFP_KERNEL).unwrap_err().cause, /// InsertErrorKind::InvalidRequest, /// ); /// # Ok::<_, Error>(()) /// ``` pub fn insert_range(&self, range: R, value: T, gfp: Flags) -> Result<(), InsertError> where R: RangeBounds, { let Some((first, last)) = to_maple_range(range) else { return Err(InsertError { value, cause: InsertErrorKind::InvalidRequest, }); }; let ptr = T::into_foreign(value); // SAFETY: The tree is valid, and we are passing a pointer to an owned instance of `T`. let res = to_result(unsafe { bindings::mtree_insert_range(self.tree.get(), first, last, ptr, gfp.as_raw()) }); if let Err(err) = res { // SAFETY: As `mtree_insert_range` failed, it is safe to take back ownership. let value = unsafe { T::from_foreign(ptr) }; let cause = if err == ENOMEM { InsertErrorKind::AllocError(kernel::alloc::AllocError) } else if err == EEXIST { InsertErrorKind::Occupied } else { InsertErrorKind::InvalidRequest }; Err(InsertError { value, cause }) } else { Ok(()) } } /// Erase the range containing the given index. /// /// # Examples /// /// ``` /// use kernel::maple_tree::MapleTree; /// /// let tree = KBox::pin_init(MapleTree::>::new(), GFP_KERNEL)?; /// /// let ten = KBox::new(10, GFP_KERNEL)?; /// let twenty = KBox::new(20, GFP_KERNEL)?; /// /// tree.insert_range(100..500, ten, GFP_KERNEL)?; /// tree.insert(67, twenty, GFP_KERNEL)?; /// /// assert_eq!(tree.erase(67).map(|v| *v), Some(20)); /// assert_eq!(tree.erase(275).map(|v| *v), Some(10)); /// /// // The previous call erased the entire range, not just index 275. /// assert!(tree.erase(127).is_none()); /// # Ok::<_, Error>(()) /// ``` #[inline] pub fn erase(&self, index: usize) -> Option { // SAFETY: `self.tree` contains a valid maple tree. let ret = unsafe { bindings::mtree_erase(self.tree.get(), index) }; // SAFETY: If the pointer is not null, then we took ownership of a valid instance of `T` // from the tree. unsafe { T::try_from_foreign(ret) } } /// Lock the internal spinlock. #[inline] pub fn lock(&self) -> MapleGuard<'_, T> { // SAFETY: It's safe to lock the spinlock in a maple tree. unsafe { bindings::spin_lock(self.ma_lock()) }; // INVARIANT: We just took the spinlock. MapleGuard(self) } #[inline] fn ma_lock(&self) -> *mut bindings::spinlock_t { // SAFETY: This pointer offset operation stays in-bounds. let lock_ptr = unsafe { &raw mut (*self.tree.get()).__bindgen_anon_1.ma_lock }; lock_ptr.cast() } /// Free all `T` instances in this tree. /// /// # Safety /// /// This frees Rust data referenced by the maple tree without removing it from the maple tree, /// leaving it in an invalid state. The caller must ensure that this invalid state cannot be /// observed by the end-user. unsafe fn free_all_entries(self: Pin<&mut Self>) { // SAFETY: The caller provides exclusive access to the entire maple tree, so we have // exclusive access to the entire maple tree despite not holding the lock. let mut ma_state = unsafe { MaState::new_raw(self.into_ref().get_ref(), 0, usize::MAX) }; loop { // This uses the raw accessor because we're destroying pointers without removing them // from the maple tree, which is only valid because this is the destructor. let ptr = ma_state.mas_find_raw(usize::MAX); if ptr.is_null() { break; } // SAFETY: By the type invariants, this pointer references a valid value of type `T`. // By the safety requirements, it is okay to free it without removing it from the maple // tree. drop(unsafe { T::from_foreign(ptr) }); } } } #[pinned_drop] impl PinnedDrop for MapleTree { #[inline] fn drop(mut self: Pin<&mut Self>) { // We only iterate the tree if the Rust value has a destructor. if core::mem::needs_drop::() { // SAFETY: Other than the below `mtree_destroy` call, the tree will not be accessed // after this call. unsafe { self.as_mut().free_all_entries() }; } // SAFETY: The tree is valid, and will not be accessed after this call. unsafe { bindings::mtree_destroy(self.tree.get()) }; } } /// A reference to a [`MapleTree`] that owns the inner lock. /// /// # Invariants /// /// This guard owns the inner spinlock. #[must_use = "if unused, the lock will be immediately unlocked"] pub struct MapleGuard<'tree, T: ForeignOwnable>(&'tree MapleTree); impl<'tree, T: ForeignOwnable> Drop for MapleGuard<'tree, T> { #[inline] fn drop(&mut self) { // SAFETY: By the type invariants, we hold this spinlock. unsafe { bindings::spin_unlock(self.0.ma_lock()) }; } } impl<'tree, T: ForeignOwnable> MapleGuard<'tree, T> { /// Create a [`MaState`] protected by this lock guard. pub fn ma_state(&mut self, first: usize, end: usize) -> MaState<'_, T> { // SAFETY: The `MaState` borrows this `MapleGuard`, so it can also borrow the `MapleGuard`s // read/write permissions to the maple tree. unsafe { MaState::new_raw(self.0, first, end) } } /// Load the value at the given index. /// /// # Examples /// /// Read the value while holding the spinlock. /// /// ``` /// use kernel::maple_tree::MapleTree; /// /// let tree = KBox::pin_init(MapleTree::>::new(), GFP_KERNEL)?; /// /// let ten = KBox::new(10, GFP_KERNEL)?; /// let twenty = KBox::new(20, GFP_KERNEL)?; /// tree.insert(100, ten, GFP_KERNEL)?; /// tree.insert(200, twenty, GFP_KERNEL)?; /// /// let mut lock = tree.lock(); /// assert_eq!(lock.load(100).map(|v| *v), Some(10)); /// assert_eq!(lock.load(200).map(|v| *v), Some(20)); /// assert_eq!(lock.load(300).map(|v| *v), None); /// # Ok::<_, Error>(()) /// ``` /// /// Increment refcount under the lock, to keep value alive afterwards. /// /// ``` /// use kernel::maple_tree::MapleTree; /// use kernel::sync::Arc; /// /// let tree = KBox::pin_init(MapleTree::>::new(), GFP_KERNEL)?; /// /// let ten = Arc::new(10, GFP_KERNEL)?; /// let twenty = Arc::new(20, GFP_KERNEL)?; /// tree.insert(100, ten, GFP_KERNEL)?; /// tree.insert(200, twenty, GFP_KERNEL)?; /// /// // Briefly take the lock to increment the refcount. /// let value = tree.lock().load(100).map(Arc::from); /// /// // At this point, another thread might remove the value. /// tree.erase(100); /// /// // But we can still access it because we took a refcount. /// assert_eq!(value.map(|v| *v), Some(10)); /// # Ok::<_, Error>(()) /// ``` #[inline] pub fn load(&mut self, index: usize) -> Option> { // SAFETY: `self.tree` contains a valid maple tree. let ret = unsafe { bindings::mtree_load(self.0.tree.get(), index) }; if ret.is_null() { return None; } // SAFETY: If the pointer is not null, then it references a valid instance of `T`. It is // safe to borrow the instance mutably because the signature of this function enforces that // the mutable borrow is not used after the spinlock is dropped. Some(unsafe { T::borrow_mut(ret) }) } } impl MapleTreeAlloc { /// Create a new allocation tree. pub fn new() -> impl PinInit { let tree = pin_init!(MapleTree { // SAFETY: This initializes a maple tree into a pinned slot. The maple tree will be // destroyed in Drop before the memory location becomes invalid. tree <- Opaque::ffi_init(|slot| unsafe { bindings::mt_init_flags(slot, bindings::MT_FLAGS_ALLOC_RANGE) }), _p: PhantomData, }); pin_init!(MapleTreeAlloc { tree <- tree }) } /// Insert an entry with the given size somewhere in the given range. /// /// The maple tree will search for a location in the given range where there is space to insert /// the new range. If there is not enough available space, then an error will be returned. /// /// The index of the new range is returned. /// /// # Examples /// /// ``` /// use kernel::maple_tree::{MapleTreeAlloc, AllocErrorKind}; /// /// let tree = KBox::pin_init(MapleTreeAlloc::>::new(), GFP_KERNEL)?; /// /// let ten = KBox::new(10, GFP_KERNEL)?; /// let twenty = KBox::new(20, GFP_KERNEL)?; /// let thirty = KBox::new(30, GFP_KERNEL)?; /// let hundred = KBox::new(100, GFP_KERNEL)?; /// /// // Allocate three ranges. /// let idx1 = tree.alloc_range(100, ten, ..1000, GFP_KERNEL)?; /// let idx2 = tree.alloc_range(100, twenty, ..1000, GFP_KERNEL)?; /// let idx3 = tree.alloc_range(100, thirty, ..1000, GFP_KERNEL)?; /// /// assert_eq!(idx1, 0); /// assert_eq!(idx2, 100); /// assert_eq!(idx3, 200); /// /// // This will fail because the remaining space is too small. /// assert_eq!( /// tree.alloc_range(800, hundred, ..1000, GFP_KERNEL).unwrap_err().cause, /// AllocErrorKind::Busy, /// ); /// # Ok::<_, Error>(()) /// ``` pub fn alloc_range( &self, size: usize, value: T, range: R, gfp: Flags, ) -> Result> where R: RangeBounds, { let Some((min, max)) = to_maple_range(range) else { return Err(AllocError { value, cause: AllocErrorKind::InvalidRequest, }); }; let ptr = T::into_foreign(value); let mut index = 0; // SAFETY: The tree is valid, and we are passing a pointer to an owned instance of `T`. let res = to_result(unsafe { bindings::mtree_alloc_range( self.tree.tree.get(), &mut index, ptr, size, min, max, gfp.as_raw(), ) }); if let Err(err) = res { // SAFETY: As `mtree_alloc_range` failed, it is safe to take back ownership. let value = unsafe { T::from_foreign(ptr) }; let cause = if err == ENOMEM { AllocErrorKind::AllocError(kernel::alloc::AllocError) } else if err == EBUSY { AllocErrorKind::Busy } else { AllocErrorKind::InvalidRequest }; Err(AllocError { value, cause }) } else { Ok(index) } } } /// A helper type used for navigating a [`MapleTree`]. /// /// # Invariants /// /// For the duration of `'tree`: /// /// * The `ma_state` references a valid `MapleTree`. /// * The `ma_state` has read/write access to the tree. pub struct MaState<'tree, T: ForeignOwnable> { state: bindings::ma_state, _phantom: PhantomData<&'tree mut MapleTree>, } impl<'tree, T: ForeignOwnable> MaState<'tree, T> { /// Initialize a new `MaState` with the given tree. /// /// # Safety /// /// The caller must ensure that this `MaState` has read/write access to the maple tree. #[inline] unsafe fn new_raw(mt: &'tree MapleTree, first: usize, end: usize) -> Self { // INVARIANT: // * Having a reference ensures that the `MapleTree` is valid for `'tree`. // * The caller ensures that we have read/write access. Self { state: bindings::ma_state { tree: mt.tree.get(), index: first, last: end, node: ptr::null_mut(), status: bindings::maple_status_ma_start, min: 0, max: usize::MAX, alloc: ptr::null_mut(), mas_flags: 0, store_type: bindings::store_type_wr_invalid, ..Default::default() }, _phantom: PhantomData, } } #[inline] fn as_raw(&mut self) -> *mut bindings::ma_state { &raw mut self.state } #[inline] fn mas_find_raw(&mut self, max: usize) -> *mut c_void { // SAFETY: By the type invariants, the `ma_state` is active and we have read/write access // to the tree. unsafe { bindings::mas_find(self.as_raw(), max) } } /// Find the next entry in the maple tree. /// /// # Examples /// /// Iterate the maple tree. /// /// ``` /// use kernel::maple_tree::MapleTree; /// use kernel::sync::Arc; /// /// let tree = KBox::pin_init(MapleTree::>::new(), GFP_KERNEL)?; /// /// let ten = Arc::new(10, GFP_KERNEL)?; /// let twenty = Arc::new(20, GFP_KERNEL)?; /// tree.insert(100, ten, GFP_KERNEL)?; /// tree.insert(200, twenty, GFP_KERNEL)?; /// /// let mut ma_lock = tree.lock(); /// let mut iter = ma_lock.ma_state(0, usize::MAX); /// /// assert_eq!(iter.find(usize::MAX).map(|v| *v), Some(10)); /// assert_eq!(iter.find(usize::MAX).map(|v| *v), Some(20)); /// assert!(iter.find(usize::MAX).is_none()); /// # Ok::<_, Error>(()) /// ``` #[inline] pub fn find(&mut self, max: usize) -> Option> { let ret = self.mas_find_raw(max); if ret.is_null() { return None; } // SAFETY: If the pointer is not null, then it references a valid instance of `T`. It's // safe to access it mutably as the returned reference borrows this `MaState`, and the // `MaState` has read/write access to the maple tree. Some(unsafe { T::borrow_mut(ret) }) } } /// Error type for failure to insert a new value. pub struct InsertError { /// The value that could not be inserted. pub value: T, /// The reason for the failure to insert. pub cause: InsertErrorKind, } /// The reason for the failure to insert. #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum InsertErrorKind { /// There is already a value in the requested range. Occupied, /// Failure to allocate memory. AllocError(kernel::alloc::AllocError), /// The insertion request was invalid. InvalidRequest, } impl From for Error { #[inline] fn from(kind: InsertErrorKind) -> Error { match kind { InsertErrorKind::Occupied => EEXIST, InsertErrorKind::AllocError(kernel::alloc::AllocError) => ENOMEM, InsertErrorKind::InvalidRequest => EINVAL, } } } impl From> for Error { #[inline] fn from(insert_err: InsertError) -> Error { Error::from(insert_err.cause) } } /// Error type for failure to insert a new value. pub struct AllocError { /// The value that could not be inserted. pub value: T, /// The reason for the failure to insert. pub cause: AllocErrorKind, } /// The reason for the failure to insert. #[derive(PartialEq, Eq, Copy, Clone)] pub enum AllocErrorKind { /// There is not enough space for the requested allocation. Busy, /// Failure to allocate memory. AllocError(kernel::alloc::AllocError), /// The insertion request was invalid. InvalidRequest, } impl From for Error { #[inline] fn from(kind: AllocErrorKind) -> Error { match kind { AllocErrorKind::Busy => EBUSY, AllocErrorKind::AllocError(kernel::alloc::AllocError) => ENOMEM, AllocErrorKind::InvalidRequest => EINVAL, } } } impl From> for Error { #[inline] fn from(insert_err: AllocError) -> Error { Error::from(insert_err.cause) } }