Skip to content

feat(fast_io): add io_uring LINKAT wrapper and kernel probe#3738

Merged
oferchen merged 3 commits into
masterfrom
feat/io-uring-linkat-1921
May 6, 2026
Merged

feat(fast_io): add io_uring LINKAT wrapper and kernel probe#3738
oferchen merged 3 commits into
masterfrom
feat/io-uring-linkat-1921

Conversation

@oferchen
Copy link
Copy Markdown
Owner

@oferchen oferchen commented May 5, 2026

Summary

  • Add IORING_OP_LINKAT (Linux 5.15+) wrapper in a new crates/fast_io/src/io_uring/linkat.rs submodule with an OnceLock-cached kernel probe (linkat_supported), a borrowed-arg struct (LinkAtArgs<'a> over &CStr paths), the gated builder (build_linkat_sqe), an unchecked encoder for tests, and a blocking submitter (submit_linkat_blocking).
  • Mirror the API surface in the non-Linux stub (io_uring_stub.rs) with linkat_supported() -> false and Unsupported round-trips so cross-platform call sites compile unchanged.
  • Re-export the new constants and functions through crates/fast_io/src/io_uring/mod.rs and crates/fast_io/src/lib.rs.
  • Closes Fix unreachable arch dispatcher code #1921 and Fix oc-rsyncd test config section #1923.

Implementation notes

  • LINKAT_MIN_KERNEL = (5, 15) and IORING_OP_LINKAT = 39 follow the kernel UAPI in include/uapi/linux/io_uring.h.
  • linkat_supported short-circuits on is_io_uring_available() before building a throwaway ring + Probe, matching the convention in shared_ring::probe_poll_add and splice::is_splice_available.
  • LinkAtArgs<'a> ties source/destination CStr lifetimes to the SQE so the compiler enforces the kernel's path-lifetime contract.

Test plan

  • CI: fmt+clippy, nextest stable, Windows, macOS, Linux musl
  • Unit tests: cached probe idempotence, opcode constant equality, unchecked SQE smoke, stub Unsupported round-trip
  • Linux integration: tests/io_uring_linkat.rs submits a real LINKAT, verifies the hardlink, then removes the destination and confirms the source survives; skips when the kernel does not advertise the opcode

Compatibility

  • Pure addition; no public API removed or altered.
  • Expected mechanical conflict on crates/fast_io/src/io_uring/mod.rs and crates/fast_io/src/lib.rs with the parallel RENAMEAT2 PR; the module list and re-exports rebase cleanly.

@github-actions github-actions Bot added the enhancement New feature or request label May 5, 2026
oferchen added 3 commits May 6, 2026 11:40
Closes #1921, #1923.

Adds a typed wrapper around `IORING_OP_LINKAT` (Linux 5.15+) so the
receiver can submit hardlink creation alongside disk writes on the same
ring instead of issuing a synchronous `linkat(2)` syscall per hardlinked
file.

The new `linkat` submodule mirrors the conventions used by
`shared_ring::probe_poll_add` and `splice::is_splice_available`:

- `LINKAT_MIN_KERNEL = (5, 15)` and `IORING_OP_LINKAT = 39` constants.
- `linkat_supported()` short-circuits on `is_io_uring_available()`,
  builds a throwaway ring, and asks the kernel via
  `IORING_REGISTER_PROBE` whether opcode 39 is supported. The result is
  cached in a process-wide `OnceLock`.
- `LinkAtArgs<'a>` borrows source/destination `&CStr` paths plus dirfds
  and `flags` so the compiler enforces the kernel's path lifetime
  contract.
- `build_linkat_sqe` returns `io::ErrorKind::Unsupported` when the probe
  is `false`; `build_linkat_sqe_unchecked` exposes the encoder for unit
  tests.
- `submit_linkat_blocking` builds a private 2-entry ring, submits the
  SQE, and returns the kernel's CQE result.

The non-Linux stub in `io_uring_stub.rs` provides the same names with
`linkat_supported() -> false` and `Unsupported` round-trips. Public
re-exports in `crates/fast_io/src/lib.rs` and the Linux `io_uring`
module make the API available to consumer crates.

Tests:

- Unit tests verify `opcode::LinkAt::CODE == 39`, the cached probe is
  idempotent, the unchecked SQE encoder accepts user_data, and the stub
  consistently returns `Unsupported`.
- `tests/io_uring_linkat.rs` (Linux+`io_uring` feature) submits a real
  LINKAT, verifies the destination hardlink, and unlinks it; skips when
  the kernel does not advertise the opcode.
@oferchen oferchen force-pushed the feat/io-uring-linkat-1921 branch from 38b037e to cb8e533 Compare May 6, 2026 08:45
@oferchen oferchen merged commit 40e5408 into master May 6, 2026
39 checks passed
@oferchen oferchen deleted the feat/io-uring-linkat-1921 branch May 6, 2026 18:55
oferchen added a commit that referenced this pull request May 18, 2026
* feat(fast_io): add io_uring LINKAT wrapper and kernel probe

Closes #1921, #1923.

Adds a typed wrapper around `IORING_OP_LINKAT` (Linux 5.15+) so the
receiver can submit hardlink creation alongside disk writes on the same
ring instead of issuing a synchronous `linkat(2)` syscall per hardlinked
file.

The new `linkat` submodule mirrors the conventions used by
`shared_ring::probe_poll_add` and `splice::is_splice_available`:

- `LINKAT_MIN_KERNEL = (5, 15)` and `IORING_OP_LINKAT = 39` constants.
- `linkat_supported()` short-circuits on `is_io_uring_available()`,
  builds a throwaway ring, and asks the kernel via
  `IORING_REGISTER_PROBE` whether opcode 39 is supported. The result is
  cached in a process-wide `OnceLock`.
- `LinkAtArgs<'a>` borrows source/destination `&CStr` paths plus dirfds
  and `flags` so the compiler enforces the kernel's path lifetime
  contract.
- `build_linkat_sqe` returns `io::ErrorKind::Unsupported` when the probe
  is `false`; `build_linkat_sqe_unchecked` exposes the encoder for unit
  tests.
- `submit_linkat_blocking` builds a private 2-entry ring, submits the
  SQE, and returns the kernel's CQE result.

The non-Linux stub in `io_uring_stub.rs` provides the same names with
`linkat_supported() -> false` and `Unsupported` round-trips. Public
re-exports in `crates/fast_io/src/lib.rs` and the Linux `io_uring`
module make the API available to consumer crates.

Tests:

- Unit tests verify `opcode::LinkAt::CODE == 39`, the cached probe is
  idempotent, the unchecked SQE encoder accepts user_data, and the stub
  consistently returns `Unsupported`.
- `tests/io_uring_linkat.rs` (Linux+`io_uring` feature) submits a real
  LINKAT, verifies the destination hardlink, and unlinks it; skips when
  the kernel does not advertise the opcode.

* fix(fast_io): use io::Error::other for clippy::io_other_error

* fix(fast_io): use c"..." CStr literals to satisfy clippy manual_c_str_literals
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