Skip to content

io_uring: fixed-file support is unimplemented behind a malformed accept SQE — readiness checklist before it can be enabled #541

Description

@FumingPower3925

Fixed files are disabled at runtime on every kernel I have tested, and the reason is our SQE, not
the kernel.

prepMultishotAcceptDirect (engine/iouring/sqe.go) builds on prepMultishotAccept, which sets
accept_flags = SOCK_NONBLOCK|SOCK_CLOEXEC, and then writes IORING_FILE_INDEX_ALLOC into
file_index. The kernel's io_accept_prep rejects a fixed file slot combined with SOCK_CLOEXEC
with -EINVAL — a direct descriptor lives in the ring's file table, not the process fd table, so
close-on-exec is meaningless for it.

So the probe fails, and every run logs:

INFO fixed files runtime probe failed, disabling
  reason="ACCEPT_DIRECT rejected by kernel: cqe.res=-22 (likely -EINVAL=-22)"
INFO io_uring engine selected tier=high ... fixed_files=false

-22 is EINVAL. The comment at probe.go:333 attributes this to the kernel — "the kernel
registered files but refuses ACCEPT_DIRECT (seen on 6.6.10-cix aarch64). Treat as unsupported."

but it reproduces on 7.0.12-linuxkit aarch64 too, and it is our flag combination.

Measured

Dropping SOCK_CLOEXEC from the direct variant only:

prepAccept(sqePtr, listenFD, uint32(unix.SOCK_NONBLOCK))

flips the probe immediately:

INFO io_uring engine selected tier=high multishot_accept=true multishot_recv=true
  provided_buffers=true fixed_files=true send_zc=true
INFO io_uring engine listening ... fixed_files=true ... kernel=7.0.12-linuxkit

No other change. Same kernel, same container, same run.

Why I am not shipping the one-line fix yet

Because it would turn on a code path that has, as far as I can tell, never executed. Fixed files
have been silently off everywhere, so everything gated on cs.fixedFile is effectively unexercised
— and celeris#538 is already an example of what is waiting there: two async unix.Write(cs.fd, ...)
sites with no !cs.fixedFile guard, where cs.fd is a table index rather than a descriptor, so the
bytes would go to whatever real fd holds that number.

Sequencing this the other way round would take a dormant defect and activate it. #538 (and a sweep
of every other cs.fixedFile branch) should land first, then this, then a full validation pass —
the performance win is real but it is not worth enabling an untested path immediately before a
release.

Found by a multi-agent audit of the io_uring SQE builders; confirmed experimentally against main
at 0a1ceff.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions