Skip to content

support zcrx#56

Merged
wokron merged 5 commits into
masterfrom
support-zcrx
Jul 2, 2026
Merged

support zcrx#56
wokron merged 5 commits into
masterfrom
support-zcrx

Conversation

@wokron

@wokron wokron commented Feb 24, 2026

Copy link
Copy Markdown
Member

We will soon have device-less mode for zcrx.

for linux 7.1

axboe/liburing#1527

@wokron wokron changed the title support zcrx [Next] support zcrx Mar 3, 2026
@wokron

wokron commented Mar 24, 2026

Copy link
Copy Markdown
Member Author

@wokron wokron force-pushed the support-zcrx branch 3 times, most recently from 84cfbad to 3400da0 Compare March 27, 2026 08:32
@wokron wokron force-pushed the support-zcrx branch 4 times, most recently from 7c6192e to baca902 Compare April 24, 2026 11:30
@wokron wokron force-pushed the support-zcrx branch 2 times, most recently from 3fa1d64 to d676028 Compare June 2, 2026 12:28
@wokron wokron force-pushed the support-zcrx branch 2 times, most recently from 7c9c2ba to 2ba4c32 Compare June 20, 2026 05:26
@wokron wokron force-pushed the support-zcrx branch 2 times, most recently from 7870067 to 3eec9e9 Compare June 30, 2026 02:57
@wokron wokron changed the title [Next] support zcrx support zcrx Jun 30, 2026
@wokron wokron force-pushed the support-zcrx branch 3 times, most recently from c670105 to e208167 Compare June 30, 2026 14:04
@wokron wokron force-pushed the support-zcrx branch 2 times, most recently from 841388d to 55c7b82 Compare July 1, 2026 05:13
@wokron

wokron commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

/review

@wokron wokron marked this pull request as ready for review July 1, 2026 05:13
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

In the destructor ~ZeroCopyRxBufferPool(), the munmap of rq_ring_.ring_ptr is performed unconditionally, but the mmap that sets rq_ring_.ring_ptr is only called inside register_ifq_(). If the constructor throws an exception after register_ifq_() succeeds but before rq_ring_.ring_ptr is assigned (e.g., after the mmap call but before the assignment completes), the destructor will still run and attempt to munmap an uninitialized or partially initialized pointer. However, the more realistic scenario is that if register_ifq_() throws, the destructor runs and rq_ring_.ring_ptr is zero-initialized, leading to munmap of a null pointer, which is undefined behavior.

~ZeroCopyRxBufferPool() {
    [[maybe_unused]] int r;
    if (area_size_ > 0) {
        assert(area_ptr_ != nullptr);
        r = munmap(area_ptr_, area_size_);
        assert(r == 0);
    }
    assert(rq_ring_.ring_ptr != nullptr);
    r = munmap(rq_ring_.ring_ptr, ring_size_);
    assert(r == 0);
    // TODO: Unregister ifq
}
Resource Leak

In register_ifq_(), if the mmap call for the refill ring fails (line 226-231), the function throws an exception. However, the io_uring_register_ifq call on line 220 has already succeeded, registering the interface queue with the kernel. There is no mechanism to unregister the ifq on this error path, leaving the kernel with a dangling registration. The TODO comment on line 224 acknowledges this but does not implement the cleanup.

void register_ifq_(uint32_t if_idx, uint32_t if_rxq, uint32_t rq_entries,
                   io_uring_zcrx_area_reg &area_reg, size_t page_size) {
    rq_entries = std::bit_ceil(rq_entries);
    io_uring_region_desc region_reg = {};
    ring_size_ = get_refill_ring_size_(rq_entries, page_size);
    region_reg.user_addr = 0;
    region_reg.size = ring_size_;
    region_reg.flags = 0;

    io_uring_zcrx_ifq_reg reg = {};
    reg.if_idx = if_idx;
    reg.if_rxq = if_rxq;
    reg.rq_entries = rq_entries;
    reg.area_ptr = reinterpret_cast<uint64_t>(&area_reg);
    reg.region_ptr = reinterpret_cast<uint64_t>(&region_reg);
    reg.flags = flags_;

    int r = io_uring_register_ifq(ring_->ring(), &reg);
    if (r != 0) {
        throw detail::make_system_error("io_uring_register_ifq", -r);
    }
    // TODO: unregister ifq if any exception

    void *ring_ptr = mmap(nullptr, ring_size_, PROT_READ | PROT_WRITE,
                          MAP_SHARED | MAP_POPULATE, ring_->ring()->ring_fd,
                          static_cast<off_t>(region_reg.mmap_offset));
    if (ring_ptr == MAP_FAILED) {
        throw detail::make_system_error("mmap");
    }
    rq_ring_.khead = (unsigned int *)((char *)ring_ptr + reg.offsets.head);
    rq_ring_.ktail = (unsigned int *)((char *)ring_ptr + reg.offsets.tail);
    rq_ring_.rqes =
        (struct io_uring_zcrx_rqe *)((char *)ring_ptr + reg.offsets.rqes);
    rq_ring_.rq_tail = 0;
    rq_ring_.ring_entries = reg.rq_entries;
    rq_ring_.ring_ptr = ring_ptr;

    zcrx_id_ = reg.zcrx_id;
    area_token_ = area_reg.rq_area_token;
}
Possible Issue

In the handle_finish method (line 185-195), the code accesses cqe + 1 to get the io_uring_zcrx_cqe. This assumes that the CQE is followed by an extended CQE structure. This is only valid if the ring was set up with CQE32 enabled (i.e., IORING_SETUP_CQE32). If the user creates a ZeroCopyRxBufferPool without enabling CQE32 on the runtime, this access will read out-of-bounds memory, leading to undefined behavior. The documentation and test do enable CQE32, but the pool constructor does not enforce or check this requirement.

ZeroCopyRxBuffer handle_finish(io_uring_cqe *cqe) noexcept {
    if (cqe->res < 0) {
        return ZeroCopyRxBuffer();
    }
    io_uring_zcrx_cqe *rcqe =
        reinterpret_cast<io_uring_zcrx_cqe *>(cqe + 1);
    void *data = static_cast<char *>(area_ptr_) +
                 (rcqe->off & ~IORING_ZCRX_AREA_MASK);
    size_t size = static_cast<size_t>(cqe->res);
    return ZeroCopyRxBuffer(data, size, this);
}

@wokron wokron force-pushed the support-zcrx branch 2 times, most recently from c4608cb to 58942e8 Compare July 2, 2026 04:44
@wokron wokron force-pushed the support-zcrx branch 2 times, most recently from 5ba8d27 to a6fd0c4 Compare July 2, 2026 05:21
@wokron wokron merged commit 5907d3f into master Jul 2, 2026
12 checks passed
@wokron wokron deleted the support-zcrx branch July 2, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant