Skip to content

Vendor io_uring definitions for older Linux headers - #386

Open
thliu21 wants to merge 1 commit into
apple:mainfrom
thliu21:fix/io-uring-header-compatibility-385
Open

thliu21 wants to merge 1 commit into
apple:mainfrom
thliu21:fix/io-uring-header-compatibility-385

Conversation

@thliu21

@thliu21 thliu21 commented Sep 10, 2026

Copy link
Copy Markdown

Swift System fails to compile against older Linux headers because IORING_ENTER_EXT_ARG is missing. This affects dependent packages even when they do not use IORing.

Fixes #385.

Vendor the liburing 2.12 UAPI at a pinned revision, with prefixed identifiers and fixed-width types so its definitions coexist with system headers and also work without Linux UAPI headers. Preserve the existing header-based support condition: old or missing system headers still cause IORing initialization to return ENOTSUP.

The patch includes MIT notices, deterministic regeneration, CMake header installation, and a CI compile regression covering old/current/missing headers, include order, and kernel ABI sizes, offsets, and alignment.

Validation

  • Reproduced the missing constant with authentic Linux 5.4 headers in C and Linux-target Swift; the fixed library compiles with those headers.
  • C compatibility and ABI checks pass, including headerless static SDKs and i386/x86_64/aarch64 ABI checks.
  • Swift 6.3.3 static Linux library cross-builds pass with old, current, and missing Linux headers, including all IORing sources. Because the manifest's source-exclusion conditions evaluate the macOS host, these checks used a temporary copy enabling Linux source inclusion; the submitted manifest is unchanged.
  • macOS swift test: 70 XCTest cases with 2 existing skips and no failures; 8 Swift Testing cases pass.
  • macOS CMake Release build, CSystem-only header installation, and an installed-header Linux consumer compile pass.

Linux runtime tests remain unrun. The Linux test-target build is blocked by the static SDK lacking XCTest. Full CMake installation with the Xcode generator fails to find swift/SystemPackage.swiftdoc; a baseline installation comparison was not performed.

Use a pinned, namespaced liburing UAPI header so old Linux headers no
longer leave IORING_ENTER_EXT_ARG undefined. Preserve the existing
header-based support condition and ENOTSUP behavior.

Include deterministic regeneration, MIT notices, CMake installation,
and CI compile checks for old, current, and missing headers plus ABI
sizes, offsets, and alignment.

Validation: macOS XCTest (70 cases, 2 existing skips) and Swift Testing
(8 cases) pass. Linux C and Swift cross-compilation cover the original
failure and fixed old/current/missing-header builds. CMake Release
build, CSystem header installation, and installed consumer checks pass.
Linux Swift validation used a temporary manifest source-inclusion
adaptation; native Linux runtime tests remain unrun and the static SDK
lacks XCTest. Full CMake installation is blocked by its Swift module
output-path mismatch with the Xcode generator.
The script verifies the original SHA-256 and makes only these adaptations:

- Prefix public identifiers and the include guard to coexist with system headers.
- Replace Linux integer types with fixed-width libc types, retaining explicit

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remind me why again we need to replace the integer types? Less changes to the header would be better.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The replacements were intended to support SDKs that do not ship Linux UAPI headers: the pinned liburing header includes linux/fs.h, linux/types.h, and linux/time_types.h. I used fixed-width types plus explicit 8-byte alignment for __aligned_u64 so the private definitions can also coexist with system headers. The standalone ABI checks pass for i386, x86_64, and aarch64.

I agree that reducing the transformation would help maintenance. We could retain more of the upstream type spellings through a small compatibility layer, provided it covers headerless SDKs and avoids collisions with system headers. I have not changed that implementation while the broader vendoring direction is still under discussion.

@glessard

Copy link
Copy Markdown
Contributor

I don't think we want to vendor the header wholesale.
We previously solved a similar issue for FreeBSD here: #319.

Note that in #329, we added the definition for IORING_ENTER_EXT_ARG. Finding why this causes the build failure is interesting. We either need to not define that name, or to give it a different value for old kernel versions.

@glessard glessard left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is the wrong approach: we don't want to include a foreign header file in full.

@FranzBusch

Copy link
Copy Markdown
Member

I believe this is the wrong approach: we don't want to include a foreign header file in full.

I strongly disagree with this. It is considered a best practice to vendor this header (see Netty). It protects against compile-time vs runtime-time drift. So that you can compile on a machine with an older Kernel but deploy to one with a newer one. This is often the case if you build with the static MUSL SDK.

I actually had it on my list for a long time to open a PR to vendor the io_uring header here since I personally ran into exactly this problem.

@thliu21

thliu21 commented Sep 18, 2026

Copy link
Copy Markdown
Author

I traced the #329 fallback: IORING_ENTER_EXT_ARG is defined only when linux/io_uring.h is absent. An older header that exists takes the other branch and leaves the flag undefined, which is why the Swift timeout code fails to compile despite the ENOTSUP initialization guard.

There are two possible scopes here: a narrow fallback for the missing constant with old-header regression coverage, or continuing the pinned vendoring approach while reducing its adaptations. Which would you prefer for this PR?

One scope detail to confirm: the current patch preserves the build-header support gate, so builds with old or missing headers still return ENOTSUP even on a newer runtime kernel. Should this PR remain a compile-compatibility fix, with runtime feature detection handled separately, or is runtime decoupling part of the intended change?

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.

Incompatibility (build failure) with Linux distros using kernel versions < 5.11

3 participants