On Wed Sep 30, 2026 at 2:05 PM JST, Yury Norov wrote: > 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...
This panic is not specific to the size zero, any size triggers the same behavior when accessed out of bounds. A size of zero has nothing special in that respect, so why make an exception and forbid it? We had this discussion some time ago [1][2], and I'd recommend instead making e.g. `next_zero_bit` return `None` on out-of-bounds accesses, which is semantically correct. [1] https://lore.kernel.org/all/[email protected]/ [2] https://lore.kernel.org/all/[email protected]/
