1*eafedbc7SAlice Ryhl // SPDX-License-Identifier: GPL-2.0 2*eafedbc7SAlice Ryhl 3*eafedbc7SAlice Ryhl // Copyright (C) 2025 Google LLC. 4*eafedbc7SAlice Ryhl 5*eafedbc7SAlice Ryhl use kernel::{page::PAGE_SIZE, prelude::*, seq_file::SeqFile, task::Pid}; 6*eafedbc7SAlice Ryhl 7*eafedbc7SAlice Ryhl mod tree; 8*eafedbc7SAlice Ryhl use self::tree::{FromArrayAllocs, ReserveNewTreeAlloc, TreeRangeAllocator}; 9*eafedbc7SAlice Ryhl 10*eafedbc7SAlice Ryhl mod array; 11*eafedbc7SAlice Ryhl use self::array::{ArrayRangeAllocator, EmptyArrayAlloc}; 12*eafedbc7SAlice Ryhl 13*eafedbc7SAlice Ryhl enum DescriptorState<T> { 14*eafedbc7SAlice Ryhl Reserved(Reservation), 15*eafedbc7SAlice Ryhl Allocated(Allocation<T>), 16*eafedbc7SAlice Ryhl } 17*eafedbc7SAlice Ryhl 18*eafedbc7SAlice Ryhl impl<T> DescriptorState<T> { 19*eafedbc7SAlice Ryhl fn new(is_oneway: bool, debug_id: usize, pid: Pid) -> Self { 20*eafedbc7SAlice Ryhl DescriptorState::Reserved(Reservation { 21*eafedbc7SAlice Ryhl debug_id, 22*eafedbc7SAlice Ryhl is_oneway, 23*eafedbc7SAlice Ryhl pid, 24*eafedbc7SAlice Ryhl }) 25*eafedbc7SAlice Ryhl } 26*eafedbc7SAlice Ryhl 27*eafedbc7SAlice Ryhl fn pid(&self) -> Pid { 28*eafedbc7SAlice Ryhl match self { 29*eafedbc7SAlice Ryhl DescriptorState::Reserved(inner) => inner.pid, 30*eafedbc7SAlice Ryhl DescriptorState::Allocated(inner) => inner.reservation.pid, 31*eafedbc7SAlice Ryhl } 32*eafedbc7SAlice Ryhl } 33*eafedbc7SAlice Ryhl 34*eafedbc7SAlice Ryhl fn is_oneway(&self) -> bool { 35*eafedbc7SAlice Ryhl match self { 36*eafedbc7SAlice Ryhl DescriptorState::Reserved(inner) => inner.is_oneway, 37*eafedbc7SAlice Ryhl DescriptorState::Allocated(inner) => inner.reservation.is_oneway, 38*eafedbc7SAlice Ryhl } 39*eafedbc7SAlice Ryhl } 40*eafedbc7SAlice Ryhl } 41*eafedbc7SAlice Ryhl 42*eafedbc7SAlice Ryhl #[derive(Clone)] 43*eafedbc7SAlice Ryhl struct Reservation { 44*eafedbc7SAlice Ryhl debug_id: usize, 45*eafedbc7SAlice Ryhl is_oneway: bool, 46*eafedbc7SAlice Ryhl pid: Pid, 47*eafedbc7SAlice Ryhl } 48*eafedbc7SAlice Ryhl 49*eafedbc7SAlice Ryhl impl Reservation { 50*eafedbc7SAlice Ryhl fn allocate<T>(self, data: Option<T>) -> Allocation<T> { 51*eafedbc7SAlice Ryhl Allocation { 52*eafedbc7SAlice Ryhl data, 53*eafedbc7SAlice Ryhl reservation: self, 54*eafedbc7SAlice Ryhl } 55*eafedbc7SAlice Ryhl } 56*eafedbc7SAlice Ryhl } 57*eafedbc7SAlice Ryhl 58*eafedbc7SAlice Ryhl struct Allocation<T> { 59*eafedbc7SAlice Ryhl reservation: Reservation, 60*eafedbc7SAlice Ryhl data: Option<T>, 61*eafedbc7SAlice Ryhl } 62*eafedbc7SAlice Ryhl 63*eafedbc7SAlice Ryhl impl<T> Allocation<T> { 64*eafedbc7SAlice Ryhl fn deallocate(self) -> (Reservation, Option<T>) { 65*eafedbc7SAlice Ryhl (self.reservation, self.data) 66*eafedbc7SAlice Ryhl } 67*eafedbc7SAlice Ryhl 68*eafedbc7SAlice Ryhl fn debug_id(&self) -> usize { 69*eafedbc7SAlice Ryhl self.reservation.debug_id 70*eafedbc7SAlice Ryhl } 71*eafedbc7SAlice Ryhl 72*eafedbc7SAlice Ryhl fn take(&mut self) -> Option<T> { 73*eafedbc7SAlice Ryhl self.data.take() 74*eafedbc7SAlice Ryhl } 75*eafedbc7SAlice Ryhl } 76*eafedbc7SAlice Ryhl 77*eafedbc7SAlice Ryhl /// The array implementation must switch to the tree if it wants to go beyond this number of 78*eafedbc7SAlice Ryhl /// ranges. 79*eafedbc7SAlice Ryhl const TREE_THRESHOLD: usize = 8; 80*eafedbc7SAlice Ryhl 81*eafedbc7SAlice Ryhl /// Represents a range of pages that have just become completely free. 82*eafedbc7SAlice Ryhl #[derive(Copy, Clone)] 83*eafedbc7SAlice Ryhl pub(crate) struct FreedRange { 84*eafedbc7SAlice Ryhl pub(crate) start_page_idx: usize, 85*eafedbc7SAlice Ryhl pub(crate) end_page_idx: usize, 86*eafedbc7SAlice Ryhl } 87*eafedbc7SAlice Ryhl 88*eafedbc7SAlice Ryhl impl FreedRange { 89*eafedbc7SAlice Ryhl fn interior_pages(offset: usize, size: usize) -> FreedRange { 90*eafedbc7SAlice Ryhl FreedRange { 91*eafedbc7SAlice Ryhl // Divide round up 92*eafedbc7SAlice Ryhl start_page_idx: offset.div_ceil(PAGE_SIZE), 93*eafedbc7SAlice Ryhl // Divide round down 94*eafedbc7SAlice Ryhl end_page_idx: (offset + size) / PAGE_SIZE, 95*eafedbc7SAlice Ryhl } 96*eafedbc7SAlice Ryhl } 97*eafedbc7SAlice Ryhl } 98*eafedbc7SAlice Ryhl 99*eafedbc7SAlice Ryhl struct Range<T> { 100*eafedbc7SAlice Ryhl offset: usize, 101*eafedbc7SAlice Ryhl size: usize, 102*eafedbc7SAlice Ryhl state: DescriptorState<T>, 103*eafedbc7SAlice Ryhl } 104*eafedbc7SAlice Ryhl 105*eafedbc7SAlice Ryhl impl<T> Range<T> { 106*eafedbc7SAlice Ryhl fn endpoint(&self) -> usize { 107*eafedbc7SAlice Ryhl self.offset + self.size 108*eafedbc7SAlice Ryhl } 109*eafedbc7SAlice Ryhl } 110*eafedbc7SAlice Ryhl 111*eafedbc7SAlice Ryhl pub(crate) struct RangeAllocator<T> { 112*eafedbc7SAlice Ryhl inner: Impl<T>, 113*eafedbc7SAlice Ryhl } 114*eafedbc7SAlice Ryhl 115*eafedbc7SAlice Ryhl enum Impl<T> { 116*eafedbc7SAlice Ryhl Empty(usize), 117*eafedbc7SAlice Ryhl Array(ArrayRangeAllocator<T>), 118*eafedbc7SAlice Ryhl Tree(TreeRangeAllocator<T>), 119*eafedbc7SAlice Ryhl } 120*eafedbc7SAlice Ryhl 121*eafedbc7SAlice Ryhl impl<T> RangeAllocator<T> { 122*eafedbc7SAlice Ryhl pub(crate) fn new(size: usize) -> Self { 123*eafedbc7SAlice Ryhl Self { 124*eafedbc7SAlice Ryhl inner: Impl::Empty(size), 125*eafedbc7SAlice Ryhl } 126*eafedbc7SAlice Ryhl } 127*eafedbc7SAlice Ryhl 128*eafedbc7SAlice Ryhl pub(crate) fn free_oneway_space(&self) -> usize { 129*eafedbc7SAlice Ryhl match &self.inner { 130*eafedbc7SAlice Ryhl Impl::Empty(size) => size / 2, 131*eafedbc7SAlice Ryhl Impl::Array(array) => array.free_oneway_space(), 132*eafedbc7SAlice Ryhl Impl::Tree(tree) => tree.free_oneway_space(), 133*eafedbc7SAlice Ryhl } 134*eafedbc7SAlice Ryhl } 135*eafedbc7SAlice Ryhl 136*eafedbc7SAlice Ryhl pub(crate) fn count_buffers(&self) -> usize { 137*eafedbc7SAlice Ryhl match &self.inner { 138*eafedbc7SAlice Ryhl Impl::Empty(_size) => 0, 139*eafedbc7SAlice Ryhl Impl::Array(array) => array.count_buffers(), 140*eafedbc7SAlice Ryhl Impl::Tree(tree) => tree.count_buffers(), 141*eafedbc7SAlice Ryhl } 142*eafedbc7SAlice Ryhl } 143*eafedbc7SAlice Ryhl 144*eafedbc7SAlice Ryhl pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> { 145*eafedbc7SAlice Ryhl match &self.inner { 146*eafedbc7SAlice Ryhl Impl::Empty(_size) => Ok(()), 147*eafedbc7SAlice Ryhl Impl::Array(array) => array.debug_print(m), 148*eafedbc7SAlice Ryhl Impl::Tree(tree) => tree.debug_print(m), 149*eafedbc7SAlice Ryhl } 150*eafedbc7SAlice Ryhl } 151*eafedbc7SAlice Ryhl 152*eafedbc7SAlice Ryhl /// Try to reserve a new buffer, using the provided allocation if necessary. 153*eafedbc7SAlice Ryhl pub(crate) fn reserve_new(&mut self, mut args: ReserveNewArgs<T>) -> Result<ReserveNew<T>> { 154*eafedbc7SAlice Ryhl match &mut self.inner { 155*eafedbc7SAlice Ryhl Impl::Empty(size) => { 156*eafedbc7SAlice Ryhl let empty_array = match args.empty_array_alloc.take() { 157*eafedbc7SAlice Ryhl Some(empty_array) => ArrayRangeAllocator::new(*size, empty_array), 158*eafedbc7SAlice Ryhl None => { 159*eafedbc7SAlice Ryhl return Ok(ReserveNew::NeedAlloc(ReserveNewNeedAlloc { 160*eafedbc7SAlice Ryhl args, 161*eafedbc7SAlice Ryhl need_empty_array_alloc: true, 162*eafedbc7SAlice Ryhl need_new_tree_alloc: false, 163*eafedbc7SAlice Ryhl need_tree_alloc: false, 164*eafedbc7SAlice Ryhl })) 165*eafedbc7SAlice Ryhl } 166*eafedbc7SAlice Ryhl }; 167*eafedbc7SAlice Ryhl 168*eafedbc7SAlice Ryhl self.inner = Impl::Array(empty_array); 169*eafedbc7SAlice Ryhl self.reserve_new(args) 170*eafedbc7SAlice Ryhl } 171*eafedbc7SAlice Ryhl Impl::Array(array) if array.is_full() => { 172*eafedbc7SAlice Ryhl let allocs = match args.new_tree_alloc { 173*eafedbc7SAlice Ryhl Some(ref mut allocs) => allocs, 174*eafedbc7SAlice Ryhl None => { 175*eafedbc7SAlice Ryhl return Ok(ReserveNew::NeedAlloc(ReserveNewNeedAlloc { 176*eafedbc7SAlice Ryhl args, 177*eafedbc7SAlice Ryhl need_empty_array_alloc: false, 178*eafedbc7SAlice Ryhl need_new_tree_alloc: true, 179*eafedbc7SAlice Ryhl need_tree_alloc: true, 180*eafedbc7SAlice Ryhl })) 181*eafedbc7SAlice Ryhl } 182*eafedbc7SAlice Ryhl }; 183*eafedbc7SAlice Ryhl 184*eafedbc7SAlice Ryhl let new_tree = 185*eafedbc7SAlice Ryhl TreeRangeAllocator::from_array(array.total_size(), &mut array.ranges, allocs); 186*eafedbc7SAlice Ryhl 187*eafedbc7SAlice Ryhl self.inner = Impl::Tree(new_tree); 188*eafedbc7SAlice Ryhl self.reserve_new(args) 189*eafedbc7SAlice Ryhl } 190*eafedbc7SAlice Ryhl Impl::Array(array) => { 191*eafedbc7SAlice Ryhl let offset = 192*eafedbc7SAlice Ryhl array.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid)?; 193*eafedbc7SAlice Ryhl Ok(ReserveNew::Success(ReserveNewSuccess { 194*eafedbc7SAlice Ryhl offset, 195*eafedbc7SAlice Ryhl oneway_spam_detected: false, 196*eafedbc7SAlice Ryhl _empty_array_alloc: args.empty_array_alloc, 197*eafedbc7SAlice Ryhl _new_tree_alloc: args.new_tree_alloc, 198*eafedbc7SAlice Ryhl _tree_alloc: args.tree_alloc, 199*eafedbc7SAlice Ryhl })) 200*eafedbc7SAlice Ryhl } 201*eafedbc7SAlice Ryhl Impl::Tree(tree) => { 202*eafedbc7SAlice Ryhl let alloc = match args.tree_alloc { 203*eafedbc7SAlice Ryhl Some(alloc) => alloc, 204*eafedbc7SAlice Ryhl None => { 205*eafedbc7SAlice Ryhl return Ok(ReserveNew::NeedAlloc(ReserveNewNeedAlloc { 206*eafedbc7SAlice Ryhl args, 207*eafedbc7SAlice Ryhl need_empty_array_alloc: false, 208*eafedbc7SAlice Ryhl need_new_tree_alloc: false, 209*eafedbc7SAlice Ryhl need_tree_alloc: true, 210*eafedbc7SAlice Ryhl })); 211*eafedbc7SAlice Ryhl } 212*eafedbc7SAlice Ryhl }; 213*eafedbc7SAlice Ryhl let (offset, oneway_spam_detected) = 214*eafedbc7SAlice Ryhl tree.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid, alloc)?; 215*eafedbc7SAlice Ryhl Ok(ReserveNew::Success(ReserveNewSuccess { 216*eafedbc7SAlice Ryhl offset, 217*eafedbc7SAlice Ryhl oneway_spam_detected, 218*eafedbc7SAlice Ryhl _empty_array_alloc: args.empty_array_alloc, 219*eafedbc7SAlice Ryhl _new_tree_alloc: args.new_tree_alloc, 220*eafedbc7SAlice Ryhl _tree_alloc: None, 221*eafedbc7SAlice Ryhl })) 222*eafedbc7SAlice Ryhl } 223*eafedbc7SAlice Ryhl } 224*eafedbc7SAlice Ryhl } 225*eafedbc7SAlice Ryhl 226*eafedbc7SAlice Ryhl /// Deletes the allocations at `offset`. 227*eafedbc7SAlice Ryhl pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result<FreedRange> { 228*eafedbc7SAlice Ryhl match &mut self.inner { 229*eafedbc7SAlice Ryhl Impl::Empty(_size) => Err(EINVAL), 230*eafedbc7SAlice Ryhl Impl::Array(array) => array.reservation_abort(offset), 231*eafedbc7SAlice Ryhl Impl::Tree(tree) => { 232*eafedbc7SAlice Ryhl let freed_range = tree.reservation_abort(offset)?; 233*eafedbc7SAlice Ryhl if tree.is_empty() { 234*eafedbc7SAlice Ryhl self.inner = Impl::Empty(tree.total_size()); 235*eafedbc7SAlice Ryhl } 236*eafedbc7SAlice Ryhl Ok(freed_range) 237*eafedbc7SAlice Ryhl } 238*eafedbc7SAlice Ryhl } 239*eafedbc7SAlice Ryhl } 240*eafedbc7SAlice Ryhl 241*eafedbc7SAlice Ryhl /// Called when an allocation is no longer in use by the kernel. 242*eafedbc7SAlice Ryhl /// 243*eafedbc7SAlice Ryhl /// The value in `data` will be stored, if any. A mutable reference is used to avoid dropping 244*eafedbc7SAlice Ryhl /// the `T` when an error is returned. 245*eafedbc7SAlice Ryhl pub(crate) fn reservation_commit(&mut self, offset: usize, data: &mut Option<T>) -> Result { 246*eafedbc7SAlice Ryhl match &mut self.inner { 247*eafedbc7SAlice Ryhl Impl::Empty(_size) => Err(EINVAL), 248*eafedbc7SAlice Ryhl Impl::Array(array) => array.reservation_commit(offset, data), 249*eafedbc7SAlice Ryhl Impl::Tree(tree) => tree.reservation_commit(offset, data), 250*eafedbc7SAlice Ryhl } 251*eafedbc7SAlice Ryhl } 252*eafedbc7SAlice Ryhl 253*eafedbc7SAlice Ryhl /// Called when the kernel starts using an allocation. 254*eafedbc7SAlice Ryhl /// 255*eafedbc7SAlice Ryhl /// Returns the size of the existing entry and the data associated with it. 256*eafedbc7SAlice Ryhl pub(crate) fn reserve_existing(&mut self, offset: usize) -> Result<(usize, usize, Option<T>)> { 257*eafedbc7SAlice Ryhl match &mut self.inner { 258*eafedbc7SAlice Ryhl Impl::Empty(_size) => Err(EINVAL), 259*eafedbc7SAlice Ryhl Impl::Array(array) => array.reserve_existing(offset), 260*eafedbc7SAlice Ryhl Impl::Tree(tree) => tree.reserve_existing(offset), 261*eafedbc7SAlice Ryhl } 262*eafedbc7SAlice Ryhl } 263*eafedbc7SAlice Ryhl 264*eafedbc7SAlice Ryhl /// Call the provided callback at every allocated region. 265*eafedbc7SAlice Ryhl /// 266*eafedbc7SAlice Ryhl /// This destroys the range allocator. Used only during shutdown. 267*eafedbc7SAlice Ryhl pub(crate) fn take_for_each<F: Fn(usize, usize, usize, Option<T>)>(&mut self, callback: F) { 268*eafedbc7SAlice Ryhl match &mut self.inner { 269*eafedbc7SAlice Ryhl Impl::Empty(_size) => {} 270*eafedbc7SAlice Ryhl Impl::Array(array) => array.take_for_each(callback), 271*eafedbc7SAlice Ryhl Impl::Tree(tree) => tree.take_for_each(callback), 272*eafedbc7SAlice Ryhl } 273*eafedbc7SAlice Ryhl } 274*eafedbc7SAlice Ryhl } 275*eafedbc7SAlice Ryhl 276*eafedbc7SAlice Ryhl /// The arguments for `reserve_new`. 277*eafedbc7SAlice Ryhl #[derive(Default)] 278*eafedbc7SAlice Ryhl pub(crate) struct ReserveNewArgs<T> { 279*eafedbc7SAlice Ryhl pub(crate) size: usize, 280*eafedbc7SAlice Ryhl pub(crate) is_oneway: bool, 281*eafedbc7SAlice Ryhl pub(crate) debug_id: usize, 282*eafedbc7SAlice Ryhl pub(crate) pid: Pid, 283*eafedbc7SAlice Ryhl pub(crate) empty_array_alloc: Option<EmptyArrayAlloc<T>>, 284*eafedbc7SAlice Ryhl pub(crate) new_tree_alloc: Option<FromArrayAllocs<T>>, 285*eafedbc7SAlice Ryhl pub(crate) tree_alloc: Option<ReserveNewTreeAlloc<T>>, 286*eafedbc7SAlice Ryhl } 287*eafedbc7SAlice Ryhl 288*eafedbc7SAlice Ryhl /// The return type of `ReserveNew`. 289*eafedbc7SAlice Ryhl pub(crate) enum ReserveNew<T> { 290*eafedbc7SAlice Ryhl Success(ReserveNewSuccess<T>), 291*eafedbc7SAlice Ryhl NeedAlloc(ReserveNewNeedAlloc<T>), 292*eafedbc7SAlice Ryhl } 293*eafedbc7SAlice Ryhl 294*eafedbc7SAlice Ryhl /// Returned by `reserve_new` when the reservation was successul. 295*eafedbc7SAlice Ryhl pub(crate) struct ReserveNewSuccess<T> { 296*eafedbc7SAlice Ryhl pub(crate) offset: usize, 297*eafedbc7SAlice Ryhl pub(crate) oneway_spam_detected: bool, 298*eafedbc7SAlice Ryhl 299*eafedbc7SAlice Ryhl // If the user supplied an allocation that we did not end up using, then we return it here. 300*eafedbc7SAlice Ryhl // The caller will kfree it outside of the lock. 301*eafedbc7SAlice Ryhl _empty_array_alloc: Option<EmptyArrayAlloc<T>>, 302*eafedbc7SAlice Ryhl _new_tree_alloc: Option<FromArrayAllocs<T>>, 303*eafedbc7SAlice Ryhl _tree_alloc: Option<ReserveNewTreeAlloc<T>>, 304*eafedbc7SAlice Ryhl } 305*eafedbc7SAlice Ryhl 306*eafedbc7SAlice Ryhl /// Returned by `reserve_new` to request the caller to make an allocation before calling the method 307*eafedbc7SAlice Ryhl /// again. 308*eafedbc7SAlice Ryhl pub(crate) struct ReserveNewNeedAlloc<T> { 309*eafedbc7SAlice Ryhl args: ReserveNewArgs<T>, 310*eafedbc7SAlice Ryhl need_empty_array_alloc: bool, 311*eafedbc7SAlice Ryhl need_new_tree_alloc: bool, 312*eafedbc7SAlice Ryhl need_tree_alloc: bool, 313*eafedbc7SAlice Ryhl } 314*eafedbc7SAlice Ryhl 315*eafedbc7SAlice Ryhl impl<T> ReserveNewNeedAlloc<T> { 316*eafedbc7SAlice Ryhl /// Make the necessary allocations for another call to `reserve_new`. 317*eafedbc7SAlice Ryhl pub(crate) fn make_alloc(mut self) -> Result<ReserveNewArgs<T>> { 318*eafedbc7SAlice Ryhl if self.need_empty_array_alloc && self.args.empty_array_alloc.is_none() { 319*eafedbc7SAlice Ryhl self.args.empty_array_alloc = Some(EmptyArrayAlloc::try_new(TREE_THRESHOLD)?); 320*eafedbc7SAlice Ryhl } 321*eafedbc7SAlice Ryhl if self.need_new_tree_alloc && self.args.new_tree_alloc.is_none() { 322*eafedbc7SAlice Ryhl self.args.new_tree_alloc = Some(FromArrayAllocs::try_new(TREE_THRESHOLD)?); 323*eafedbc7SAlice Ryhl } 324*eafedbc7SAlice Ryhl if self.need_tree_alloc && self.args.tree_alloc.is_none() { 325*eafedbc7SAlice Ryhl self.args.tree_alloc = Some(ReserveNewTreeAlloc::try_new()?); 326*eafedbc7SAlice Ryhl } 327*eafedbc7SAlice Ryhl Ok(self.args) 328*eafedbc7SAlice Ryhl } 329*eafedbc7SAlice Ryhl } 330