Skip to content

fix(ublk-zc): close wake eventfd if ZC thread spawn fails#84

Merged
jaredLunde merged 1 commit into
mainfrom
jared/fix-zc-wakefd-leak
Jun 26, 2026
Merged

fix(ublk-zc): close wake eventfd if ZC thread spawn fails#84
jaredLunde merged 1 commit into
mainfrom
jared/fix-zc-wakefd-leak

Conversation

@jaredLunde

Copy link
Copy Markdown
Contributor

Problem

Hunting for an fd leak on the ublk happy path turned up one real leak — on an error path adjacent to it.

In start_zc_queue (glidefs/src/block/ublk/device.rs), the cross-thread wake eventfd is created before the ZC queue thread is spawned, but it only becomes owned by ZcThreadGuard after a successful spawn:

let wake_fd = libc::eventfd(...);          // created here
let join = Builder::new().spawn(...)?;     // <-- early return leaks wake_fd
...
let _zc_guard = ZcThreadGuard { wake_fd, ... };  // owner constructed here

If Builder::spawn fails — e.g. resource exhaustion during a multi-device recovery storm, which is exactly when fds are scarce — the ? returns early and leaks one eventfd per queue, because the guard that would close() it is never constructed.

The happy path itself is clean (RawFd is Copy, the thread borrows a copy, the guard closes the canonical fd in Drop). This only bites on spawn failure.

Fix

Wrap wake_fd in an OwnedFd immediately after creation so any early return closes it via Drop, then release ownership to the guard (into_raw_fd) once the spawn succeeds. Ownership semantics on the happy path are unchanged.

🤖 Generated with Claude Code

The cross-thread wake eventfd is created before the ZC queue thread is
spawned, but only becomes owned by `ZcThreadGuard` after a successful
spawn. If `Builder::spawn` failed (e.g. resource exhaustion during a
multi-device recovery storm — exactly when fds are scarce), the `?`
returned early and leaked one eventfd per queue, since the guard that
would `close` it was never constructed.

Wrap `wake_fd` in an `OwnedFd` immediately after creation so any early
return closes it via Drop, then release ownership to the guard once the
spawn succeeds. The ZC thread only borrows the raw value (RawFd is Copy),
so ownership semantics are unchanged on the happy path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jaredLunde jaredLunde merged commit 2e8b9d2 into main Jun 26, 2026
25 checks passed
@jaredLunde jaredLunde deleted the jared/fix-zc-wakefd-leak branch June 26, 2026 05:05
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