Skip to content

feat: bound io_uring buffer group ID allocation#4005

Merged
oferchen merged 2 commits into
masterfrom
feat/io-uring-bgid-bound-2044
May 13, 2026
Merged

feat: bound io_uring buffer group ID allocation#4005
oferchen merged 2 commits into
masterfrom
feat/io-uring-bgid-bound-2044

Conversation

@oferchen
Copy link
Copy Markdown
Owner

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:

  • Returns a monotonically increasing u16 starting at 0.
  • Returns BufferRingError::BgidExhausted (mapped to io::ErrorKind::InvalidInput) when all 65,536 IDs have been issued.
  • Uses AtomicU32 internally so values above u16::MAX are detected without wrapping; on exhaustion the counter is capped to prevent an eventual u32 wrap from resuming valid u16 IDs.
  • Exposes remaining() for diagnostics.

The non-Linux stub mirrors the same interface so cross-platform callers can pattern-match BgidExhausted without cfg-gating.

Closes #2044.

Test plan

  • Unit test: bgid_allocator_returns_distinct_ids - consecutive allocations are unique
  • Unit test: bgid_allocator_exhaustion_returns_error - forces the counter to the namespace limit, verifies the guard fires
  • Unit test: bgid_exhausted_converts_to_invalid_input_io_error - error maps to io::ErrorKind::InvalidInput and message cites the 65,535 limit
  • Unit test: bgid_allocator_remaining_does_not_increase - sequential reads are monotonically non-increasing

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.
@github-actions github-actions Bot added the enhancement New feature or request label May 13, 2026
@oferchen oferchen merged commit 8b81ec6 into master May 13, 2026
37 of 39 checks passed
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 oferchen deleted the feat/io-uring-bgid-bound-2044 branch May 14, 2026 14:57
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant