1*2cdae413SBurak Emir // SPDX-License-Identifier: GPL-2.0 2*2cdae413SBurak Emir 3*2cdae413SBurak Emir // Copyright (C) 2025 Google LLC. 4*2cdae413SBurak Emir 5*2cdae413SBurak Emir //! Rust API for an ID pool backed by a [`BitmapVec`]. 6*2cdae413SBurak Emir 7*2cdae413SBurak Emir use crate::alloc::{AllocError, Flags}; 8*2cdae413SBurak Emir use crate::bitmap::BitmapVec; 9*2cdae413SBurak Emir 10*2cdae413SBurak Emir const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize; 11*2cdae413SBurak Emir 12*2cdae413SBurak Emir /// Represents a dynamic ID pool backed by a [`BitmapVec`]. 13*2cdae413SBurak Emir /// 14*2cdae413SBurak Emir /// Clients acquire and release IDs from unset bits in a bitmap. 15*2cdae413SBurak Emir /// 16*2cdae413SBurak Emir /// The capacity of the ID pool may be adjusted by users as 17*2cdae413SBurak Emir /// needed. The API supports the scenario where users need precise control 18*2cdae413SBurak Emir /// over the time of allocation of a new backing bitmap, which may require 19*2cdae413SBurak Emir /// release of spinlock. 20*2cdae413SBurak Emir /// Due to concurrent updates, all operations are re-verified to determine 21*2cdae413SBurak Emir /// if the grow or shrink is sill valid. 22*2cdae413SBurak Emir /// 23*2cdae413SBurak Emir /// # Examples 24*2cdae413SBurak Emir /// 25*2cdae413SBurak Emir /// Basic usage 26*2cdae413SBurak Emir /// 27*2cdae413SBurak Emir /// ``` 28*2cdae413SBurak Emir /// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; 29*2cdae413SBurak Emir /// use kernel::id_pool::IdPool; 30*2cdae413SBurak Emir /// 31*2cdae413SBurak Emir /// let mut pool = IdPool::new(64, GFP_KERNEL)?; 32*2cdae413SBurak Emir /// for i in 0..64 { 33*2cdae413SBurak Emir /// assert_eq!(i, pool.acquire_next_id(i).ok_or(ENOSPC)?); 34*2cdae413SBurak Emir /// } 35*2cdae413SBurak Emir /// 36*2cdae413SBurak Emir /// pool.release_id(23); 37*2cdae413SBurak Emir /// assert_eq!(23, pool.acquire_next_id(0).ok_or(ENOSPC)?); 38*2cdae413SBurak Emir /// 39*2cdae413SBurak Emir /// assert_eq!(None, pool.acquire_next_id(0)); // time to realloc. 40*2cdae413SBurak Emir /// let resizer = pool.grow_request().ok_or(ENOSPC)?.realloc(GFP_KERNEL)?; 41*2cdae413SBurak Emir /// pool.grow(resizer); 42*2cdae413SBurak Emir /// 43*2cdae413SBurak Emir /// assert_eq!(pool.acquire_next_id(0), Some(64)); 44*2cdae413SBurak Emir /// # Ok::<(), Error>(()) 45*2cdae413SBurak Emir /// ``` 46*2cdae413SBurak Emir /// 47*2cdae413SBurak Emir /// Releasing spinlock to grow the pool 48*2cdae413SBurak Emir /// 49*2cdae413SBurak Emir /// ```no_run 50*2cdae413SBurak Emir /// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; 51*2cdae413SBurak Emir /// use kernel::sync::{new_spinlock, SpinLock}; 52*2cdae413SBurak Emir /// use kernel::id_pool::IdPool; 53*2cdae413SBurak Emir /// 54*2cdae413SBurak Emir /// fn get_id_maybe_realloc(guarded_pool: &SpinLock<IdPool>) -> Result<usize, AllocError> { 55*2cdae413SBurak Emir /// let mut pool = guarded_pool.lock(); 56*2cdae413SBurak Emir /// loop { 57*2cdae413SBurak Emir /// match pool.acquire_next_id(0) { 58*2cdae413SBurak Emir /// Some(index) => return Ok(index), 59*2cdae413SBurak Emir /// None => { 60*2cdae413SBurak Emir /// let alloc_request = pool.grow_request(); 61*2cdae413SBurak Emir /// drop(pool); 62*2cdae413SBurak Emir /// let resizer = alloc_request.ok_or(AllocError)?.realloc(GFP_KERNEL)?; 63*2cdae413SBurak Emir /// pool = guarded_pool.lock(); 64*2cdae413SBurak Emir /// pool.grow(resizer) 65*2cdae413SBurak Emir /// } 66*2cdae413SBurak Emir /// } 67*2cdae413SBurak Emir /// } 68*2cdae413SBurak Emir /// } 69*2cdae413SBurak Emir /// ``` 70*2cdae413SBurak Emir pub struct IdPool { 71*2cdae413SBurak Emir map: BitmapVec, 72*2cdae413SBurak Emir } 73*2cdae413SBurak Emir 74*2cdae413SBurak Emir /// Indicates that an [`IdPool`] should change to a new target size. 75*2cdae413SBurak Emir pub struct ReallocRequest { 76*2cdae413SBurak Emir num_ids: usize, 77*2cdae413SBurak Emir } 78*2cdae413SBurak Emir 79*2cdae413SBurak Emir /// Contains a [`BitmapVec`] of a size suitable for reallocating [`IdPool`]. 80*2cdae413SBurak Emir pub struct PoolResizer { 81*2cdae413SBurak Emir new: BitmapVec, 82*2cdae413SBurak Emir } 83*2cdae413SBurak Emir 84*2cdae413SBurak Emir impl ReallocRequest { 85*2cdae413SBurak Emir /// Allocates a new backing [`BitmapVec`] for [`IdPool`]. 86*2cdae413SBurak Emir /// 87*2cdae413SBurak Emir /// This method only prepares reallocation and does not complete it. 88*2cdae413SBurak Emir /// Reallocation will complete after passing the [`PoolResizer`] to the 89*2cdae413SBurak Emir /// [`IdPool::grow`] or [`IdPool::shrink`] operation, which will check 90*2cdae413SBurak Emir /// that reallocation still makes sense. 91*2cdae413SBurak Emir pub fn realloc(&self, flags: Flags) -> Result<PoolResizer, AllocError> { 92*2cdae413SBurak Emir let new = BitmapVec::new(self.num_ids, flags)?; 93*2cdae413SBurak Emir Ok(PoolResizer { new }) 94*2cdae413SBurak Emir } 95*2cdae413SBurak Emir } 96*2cdae413SBurak Emir 97*2cdae413SBurak Emir impl IdPool { 98*2cdae413SBurak Emir /// Constructs a new [`IdPool`]. 99*2cdae413SBurak Emir /// 100*2cdae413SBurak Emir /// A capacity below [`BITS_PER_LONG`] is adjusted to 101*2cdae413SBurak Emir /// [`BITS_PER_LONG`]. 102*2cdae413SBurak Emir /// 103*2cdae413SBurak Emir /// [`BITS_PER_LONG`]: srctree/include/asm-generic/bitsperlong.h 104*2cdae413SBurak Emir #[inline] 105*2cdae413SBurak Emir pub fn new(num_ids: usize, flags: Flags) -> Result<Self, AllocError> { 106*2cdae413SBurak Emir let num_ids = core::cmp::max(num_ids, BITS_PER_LONG); 107*2cdae413SBurak Emir let map = BitmapVec::new(num_ids, flags)?; 108*2cdae413SBurak Emir Ok(Self { map }) 109*2cdae413SBurak Emir } 110*2cdae413SBurak Emir 111*2cdae413SBurak Emir /// Returns how many IDs this pool can currently have. 112*2cdae413SBurak Emir #[inline] 113*2cdae413SBurak Emir pub fn capacity(&self) -> usize { 114*2cdae413SBurak Emir self.map.len() 115*2cdae413SBurak Emir } 116*2cdae413SBurak Emir 117*2cdae413SBurak Emir /// Returns a [`ReallocRequest`] if the [`IdPool`] can be shrunk, [`None`] otherwise. 118*2cdae413SBurak Emir /// 119*2cdae413SBurak Emir /// The capacity of an [`IdPool`] cannot be shrunk below [`BITS_PER_LONG`]. 120*2cdae413SBurak Emir /// 121*2cdae413SBurak Emir /// [`BITS_PER_LONG`]: srctree/include/asm-generic/bitsperlong.h 122*2cdae413SBurak Emir /// 123*2cdae413SBurak Emir /// # Examples 124*2cdae413SBurak Emir /// 125*2cdae413SBurak Emir /// ``` 126*2cdae413SBurak Emir /// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; 127*2cdae413SBurak Emir /// use kernel::id_pool::{ReallocRequest, IdPool}; 128*2cdae413SBurak Emir /// 129*2cdae413SBurak Emir /// let mut pool = IdPool::new(1024, GFP_KERNEL)?; 130*2cdae413SBurak Emir /// let alloc_request = pool.shrink_request().ok_or(AllocError)?; 131*2cdae413SBurak Emir /// let resizer = alloc_request.realloc(GFP_KERNEL)?; 132*2cdae413SBurak Emir /// pool.shrink(resizer); 133*2cdae413SBurak Emir /// assert_eq!(pool.capacity(), kernel::bindings::BITS_PER_LONG as usize); 134*2cdae413SBurak Emir /// # Ok::<(), AllocError>(()) 135*2cdae413SBurak Emir /// ``` 136*2cdae413SBurak Emir #[inline] 137*2cdae413SBurak Emir pub fn shrink_request(&self) -> Option<ReallocRequest> { 138*2cdae413SBurak Emir let cap = self.capacity(); 139*2cdae413SBurak Emir // Shrinking below [`BITS_PER_LONG`] is never possible. 140*2cdae413SBurak Emir if cap <= BITS_PER_LONG { 141*2cdae413SBurak Emir return None; 142*2cdae413SBurak Emir } 143*2cdae413SBurak Emir // Determine if the bitmap can shrink based on the position of 144*2cdae413SBurak Emir // its last set bit. If the bit is within the first quarter of 145*2cdae413SBurak Emir // the bitmap then shrinking is possible. In this case, the 146*2cdae413SBurak Emir // bitmap should shrink to half its current size. 147*2cdae413SBurak Emir let Some(bit) = self.map.last_bit() else { 148*2cdae413SBurak Emir return Some(ReallocRequest { 149*2cdae413SBurak Emir num_ids: BITS_PER_LONG, 150*2cdae413SBurak Emir }); 151*2cdae413SBurak Emir }; 152*2cdae413SBurak Emir if bit >= (cap / 4) { 153*2cdae413SBurak Emir return None; 154*2cdae413SBurak Emir } 155*2cdae413SBurak Emir let num_ids = usize::max(BITS_PER_LONG, cap / 2); 156*2cdae413SBurak Emir Some(ReallocRequest { num_ids }) 157*2cdae413SBurak Emir } 158*2cdae413SBurak Emir 159*2cdae413SBurak Emir /// Shrinks pool by using a new [`BitmapVec`], if still possible. 160*2cdae413SBurak Emir #[inline] 161*2cdae413SBurak Emir pub fn shrink(&mut self, mut resizer: PoolResizer) { 162*2cdae413SBurak Emir // Between request to shrink that led to allocation of `resizer` and now, 163*2cdae413SBurak Emir // bits may have changed. 164*2cdae413SBurak Emir // Verify that shrinking is still possible. In case shrinking to 165*2cdae413SBurak Emir // the size of `resizer` is no longer possible, do nothing, 166*2cdae413SBurak Emir // drop `resizer` and move on. 167*2cdae413SBurak Emir let Some(updated) = self.shrink_request() else { 168*2cdae413SBurak Emir return; 169*2cdae413SBurak Emir }; 170*2cdae413SBurak Emir if updated.num_ids > resizer.new.len() { 171*2cdae413SBurak Emir return; 172*2cdae413SBurak Emir } 173*2cdae413SBurak Emir 174*2cdae413SBurak Emir resizer.new.copy_and_extend(&self.map); 175*2cdae413SBurak Emir self.map = resizer.new; 176*2cdae413SBurak Emir } 177*2cdae413SBurak Emir 178*2cdae413SBurak Emir /// Returns a [`ReallocRequest`] for growing this [`IdPool`], if possible. 179*2cdae413SBurak Emir /// 180*2cdae413SBurak Emir /// The capacity of an [`IdPool`] cannot be grown above [`i32::MAX`]. 181*2cdae413SBurak Emir #[inline] 182*2cdae413SBurak Emir pub fn grow_request(&self) -> Option<ReallocRequest> { 183*2cdae413SBurak Emir let num_ids = self.capacity() * 2; 184*2cdae413SBurak Emir if num_ids > i32::MAX.try_into().unwrap() { 185*2cdae413SBurak Emir return None; 186*2cdae413SBurak Emir } 187*2cdae413SBurak Emir Some(ReallocRequest { num_ids }) 188*2cdae413SBurak Emir } 189*2cdae413SBurak Emir 190*2cdae413SBurak Emir /// Grows pool by using a new [`BitmapVec`], if still necessary. 191*2cdae413SBurak Emir /// 192*2cdae413SBurak Emir /// The `resizer` arguments has to be obtained by calling [`Self::grow_request`] 193*2cdae413SBurak Emir /// on this object and performing a [`ReallocRequest::realloc`]. 194*2cdae413SBurak Emir #[inline] 195*2cdae413SBurak Emir pub fn grow(&mut self, mut resizer: PoolResizer) { 196*2cdae413SBurak Emir // Between request to grow that led to allocation of `resizer` and now, 197*2cdae413SBurak Emir // another thread may have already grown the capacity. 198*2cdae413SBurak Emir // In this case, do nothing, drop `resizer` and move on. 199*2cdae413SBurak Emir if resizer.new.len() <= self.capacity() { 200*2cdae413SBurak Emir return; 201*2cdae413SBurak Emir } 202*2cdae413SBurak Emir 203*2cdae413SBurak Emir resizer.new.copy_and_extend(&self.map); 204*2cdae413SBurak Emir self.map = resizer.new; 205*2cdae413SBurak Emir } 206*2cdae413SBurak Emir 207*2cdae413SBurak Emir /// Acquires a new ID by finding and setting the next zero bit in the 208*2cdae413SBurak Emir /// bitmap. 209*2cdae413SBurak Emir /// 210*2cdae413SBurak Emir /// Upon success, returns its index. Otherwise, returns [`None`] 211*2cdae413SBurak Emir /// to indicate that a [`Self::grow_request`] is needed. 212*2cdae413SBurak Emir #[inline] 213*2cdae413SBurak Emir pub fn acquire_next_id(&mut self, offset: usize) -> Option<usize> { 214*2cdae413SBurak Emir let next_zero_bit = self.map.next_zero_bit(offset); 215*2cdae413SBurak Emir if let Some(nr) = next_zero_bit { 216*2cdae413SBurak Emir self.map.set_bit(nr); 217*2cdae413SBurak Emir } 218*2cdae413SBurak Emir next_zero_bit 219*2cdae413SBurak Emir } 220*2cdae413SBurak Emir 221*2cdae413SBurak Emir /// Releases an ID. 222*2cdae413SBurak Emir #[inline] 223*2cdae413SBurak Emir pub fn release_id(&mut self, id: usize) { 224*2cdae413SBurak Emir self.map.clear_bit(id); 225*2cdae413SBurak Emir } 226*2cdae413SBurak Emir } 227