On Thu, Aug 27, 2026 at 04:28:39PM +0900, Eliot Courtney wrote: > Current code in IdPool::with_capacity rounds the capacity up to > BitmapVec::MAX_INLINE_LEN, but BitmapVec::new works fine with values > smaller than this and still uses an inline representation. Remove this > behaviour. > > This allows specifying a real capacity of 0, which was not previously > possible. This breaks `grow_request` in this case, so change it to grow > to at least `BitmapVec::MAX_INLINE_LEN`, mirroring the capacity floor in > `shrink_request`.
It wasn't possible previously for a reason: allocating 0-bit bitmap is something questionable. > Signed-off-by: Eliot Courtney <[email protected]> > --- > rust/kernel/id_pool.rs | 38 ++++++++++++++++++++++++++++++++------ > 1 file changed, 32 insertions(+), 6 deletions(-) > > diff --git a/rust/kernel/id_pool.rs b/rust/kernel/id_pool.rs > index 06a4c71c4c6c..4f329249df9d 100644 > --- a/rust/kernel/id_pool.rs > +++ b/rust/kernel/id_pool.rs > @@ -112,13 +112,8 @@ pub fn new() -> Self { > } > > /// Constructs a new [`IdPool`] with space for a specific number of bits. > - /// > - /// A capacity below [`MAX_INLINE_LEN`] is adjusted to > [`MAX_INLINE_LEN`]. > - /// > - /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN > #[inline] > pub fn with_capacity(num_ids: usize, flags: Flags) -> Result<Self, > AllocError> { > - let num_ids = usize::max(num_ids, BitmapVec::MAX_INLINE_LEN); > let map = BitmapVec::new(num_ids, flags)?; > Ok(Self { map }) > } > @@ -152,6 +147,13 @@ pub fn capacity(&self) -> usize { > /// let resizer = alloc_request.realloc(GFP_KERNEL)?; > /// pool.shrink(resizer); > /// assert_eq!(pool.capacity(), BitmapVec::MAX_INLINE_LEN); > + /// > + /// // A pool at the `MAX_INLINE_LEN` floor cannot shrink further. > + /// assert!(pool.shrink_request().is_none()); > + /// > + /// // Neither can a pool with a capacity below `MAX_INLINE_LEN`. > + /// let small = IdPool::with_capacity(8, GFP_KERNEL)?; > + /// assert!(small.shrink_request().is_none()); > /// # Ok::<(), AllocError>(()) > /// ``` > #[inline] > @@ -198,12 +200,36 @@ pub fn shrink(&mut self, mut resizer: PoolResizer) { > > /// Returns a [`ReallocRequest`] for growing this [`IdPool`], if > possible. > /// > + /// Grows to at least [`MAX_INLINE_LEN`]. > /// The capacity of an [`IdPool`] cannot be grown above [`MAX_LEN`]. > /// > + /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN > /// [`MAX_LEN`]: BitmapVec::MAX_LEN > + /// > + /// # Examples > + /// > + /// ``` > + /// use kernel::{ > + /// alloc::AllocError, > + /// bitmap::BitmapVec, > + /// id_pool::IdPool, // > + /// }; > + /// > + /// // Grow goes to at least BitmapVec::MAX_INLINE_LEN. > + /// let mut pool = IdPool::with_capacity(0, GFP_KERNEL)?; Please don't add explicit examples for creating ID pools with 0 capacity. It's a factual error, and should not be explicitly expressed in documentation. Also, it looks like your 0-bit bitmamp would trigger bitmap assertion: IdPool::find_unused_id(0) -> Bitmap::next_zero_bit() -> assert!(start < self.len()) -> assert!(0 < 0) -> panic if CONFIG_RUST_BITMAP_HARDENED=y I like your version because it allows to create an arbitrary capacity for ID pool, i.e. 4 bits. Right now one can explicitly create ID pool for 4 IDs, and allocate up to MAX_INLINE_LEN from it. But 0-bit ID pools must be prohibited. > + /// let resizer = > pool.grow_request().ok_or(AllocError)?.realloc(GFP_KERNEL)?; > + /// pool.grow(resizer); > + /// assert_eq!(pool.capacity(), BitmapVec::MAX_INLINE_LEN); > + /// > + /// // Grow doubles if at least BitmapVec::MAX_INLINE_LEN. > + /// let resizer = > pool.grow_request().ok_or(AllocError)?.realloc(GFP_KERNEL)?; > + /// pool.grow(resizer); > + /// assert_eq!(pool.capacity(), 2 * BitmapVec::MAX_INLINE_LEN); > + /// # Ok::<(), AllocError>(()) > + /// ``` > #[inline] > pub fn grow_request(&self) -> Option<ReallocRequest> { > - let num_ids = self.capacity() * 2; > + let num_ids = usize::max(BitmapVec::MAX_INLINE_LEN, self.capacity() > * 2); > if num_ids > BitmapVec::MAX_LEN { > return None; > } > > -- > 2.55.0
