On Wed, Sep 30, 2026 at 11:42:57AM +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`.
> 
> 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)?;

Allocating a pool with 0-bit capacity is wrong. Please don't put it
in the examples. I recall I pointed that this object would panic the
kernel if, for example, you call pool.next_zero_bit(0) immediately
after this. Sorry, but NAK.

This .with_capacity() should take num_ids: NonZero, after all...


> +    /// 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

Reply via email to