feat: bound io_uring buffer group ID allocation#4005
Merged
Conversation
Add BgidAllocator with a process-wide monotonic AtomicU32 counter to detect exhaustion of the u16 buffer group ID namespace (65,536 values). Returns BgidExhausted when all IDs have been issued rather than wrapping and silently colliding with active rings still held by the kernel. The non-Linux stub mirrors the same interface so cross-platform callers can compile without cfg-gating.
This was referenced May 13, 2026
oferchen
added a commit
that referenced
this pull request
May 14, 2026
* feat: reuse io_uring buffer group IDs via free-list Track returned bgids in a process-wide free-list so long-running daemons that cycle through many `BufferRing` instances can reuse identifiers instead of monotonically exhausting the 16-bit namespace. `allocate` drains the free-list before advancing the counter, `deallocate` returns an id (idempotent on duplicates), and `remaining` reflects free-list size so callers can probe headroom. `BufferRing::new_with_allocator` is the new entry point that takes ownership of an allocator-issued bgid; its `Drop` returns the id via `BgidAllocator::deallocate`. Caller-supplied bgids passed to `new` remain caller-owned and are not touched on drop. Refs #2044, follow-up to #4005. * style: apply cargo fmt to bgid free-list
oferchen
added a commit
that referenced
this pull request
May 18, 2026
* feat: bound io_uring buffer group ID allocation Add BgidAllocator with a process-wide monotonic AtomicU32 counter to detect exhaustion of the u16 buffer group ID namespace (65,536 values). Returns BgidExhausted when all IDs have been issued rather than wrapping and silently colliding with active rings still held by the kernel. The non-Linux stub mirrors the same interface so cross-platform callers can compile without cfg-gating. * fix: re-export BgidAllocator at io_uring_stub top level
oferchen
added a commit
that referenced
this pull request
May 18, 2026
* feat: reuse io_uring buffer group IDs via free-list Track returned bgids in a process-wide free-list so long-running daemons that cycle through many `BufferRing` instances can reuse identifiers instead of monotonically exhausting the 16-bit namespace. `allocate` drains the free-list before advancing the counter, `deallocate` returns an id (idempotent on duplicates), and `remaining` reflects free-list size so callers can probe headroom. `BufferRing::new_with_allocator` is the new entry point that takes ownership of an allocator-issued bgid; its `Drop` returns the id via `BgidAllocator::deallocate`. Caller-supplied bgids passed to `new` remain caller-owned and are not touched on drop. Refs #2044, follow-up to #4005. * style: apply cargo fmt to bgid free-list
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
io_uring provided buffer rings (
IORING_REGISTER_PBUF_RING) are identified by a 16-bit Buffer Group ID. The namespace has 65,536 values total. A long-running process that continuously allocates buffer rings without recycling bgids would silently exhaust this space, eventually colliding with rings still active in the kernel.This PR adds
BgidAllocator, a process-wide monotonic counter that:u16starting at 0.BufferRingError::BgidExhausted(mapped toio::ErrorKind::InvalidInput) when all 65,536 IDs have been issued.AtomicU32internally so values aboveu16::MAXare detected without wrapping; on exhaustion the counter is capped to prevent an eventual u32 wrap from resuming valid u16 IDs.remaining()for diagnostics.The non-Linux stub mirrors the same interface so cross-platform callers can pattern-match
BgidExhaustedwithoutcfg-gating.Closes #2044.
Test plan
bgid_allocator_returns_distinct_ids- consecutive allocations are uniquebgid_allocator_exhaustion_returns_error- forces the counter to the namespace limit, verifies the guard firesbgid_exhausted_converts_to_invalid_input_io_error- error maps toio::ErrorKind::InvalidInputand message cites the 65,535 limitbgid_allocator_remaining_does_not_increase- sequential reads are monotonically non-increasing