fix(redox): translate POSIX F_DUPFD_CLOEXEC (1030) to Redox syscall ABI (5)
fcntl(F_DUPFD_CLOEXEC) reached redox_rt/kernel with the POSIX/C value 1030 instead of the Redox syscall value (syscall::F_DUPFD_CLOEXEC=5). redox_rt did not recognize it as a dup, forwarded the raw command to the kernel, and the kernel's fcntl fell through to its EINVAL catch-all. That made OwnedFd::try_clone() return EINVAL, which broke tokio Runtime::build() (its I/O reactor try_clones the epoll fd) for every tokio user on Redox: all the zbus system daemons (sessiond/polkit/udisks/upower) and the login shell. F_DUPFD and plain dup worked because they share the same value in both namespaces; F_DUPFD_CLOEXEC was the sole untranslated command. Also drop the ineffective epoll_ctl EINVAL/EBADF retry loop: it was based on a disproven 'transient scheme churn' theory; epoll registrations always succeed immediately. The real dup failure is fixed above.
This commit is contained in:
@@ -64,36 +64,7 @@ impl PalEpoll for Sys {
|
||||
// systems. If this is needed, use a box or something
|
||||
data: unsafe { (*event).data.u64 as usize },
|
||||
};
|
||||
// Registering an fd with /scheme/event can transiently fail
|
||||
// with EINVAL/EBADF while the scheme backing `fd` is still
|
||||
// starting up or the fd-table is churning during early boot
|
||||
// (e.g. a tokio/mio reactor built by a daemon that races ahead
|
||||
// of ipcd's uds_stream scheme). Without recovery, tokio's
|
||||
// Runtime::build aborts the whole runtime, killing every
|
||||
// zbus-based daemon and any tokio program (including the login
|
||||
// shell). Retry with a short backoff so the registration
|
||||
// succeeds once the scheme settles; a genuinely permanent
|
||||
// failure still surfaces after the bounded window. This mirrors
|
||||
// the park-path recovery in the P0-epoll-redox-recovery tokio
|
||||
// patch, but at the registration site the patch cannot reach.
|
||||
let mut attempts: u32 = 0;
|
||||
loop {
|
||||
match Sys::write(epfd, &ev) {
|
||||
Ok(_) => break,
|
||||
Err(Errno(err))
|
||||
if (err == EINVAL || err == EBADF) && attempts < 400 =>
|
||||
{
|
||||
attempts += 1;
|
||||
let req = syscall::data::TimeSpec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 5_000_000, // 5ms; up to ~2s total
|
||||
};
|
||||
let mut rem = syscall::data::TimeSpec::default();
|
||||
let _ = syscall::nanosleep(&req, &mut rem);
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
Sys::write(epfd, &ev)?;
|
||||
}
|
||||
EPOLL_CTL_DEL => {
|
||||
Sys::write(
|
||||
|
||||
@@ -477,7 +477,24 @@ impl Pal for Sys {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(redox_rt::sys::fcntl(fd as usize, cmd as usize, args as usize)? as c_int)
|
||||
// The POSIX/C value of `F_DUPFD_CLOEXEC` exposed by <fcntl.h> (1030,
|
||||
// matching Linux so that libc/std/mio hardcode it) does NOT match the
|
||||
// Redox syscall-ABI value that redox_rt and the kernel understand
|
||||
// (`syscall::F_DUPFD_CLOEXEC`, 5). Every other fcntl command that reaches
|
||||
// redox_rt shares the same numeric value in both namespaces, so
|
||||
// F_DUPFD_CLOEXEC is the single command that must be translated here.
|
||||
// Without this, redox_rt does not recognize 1030 as a dup, forwards the
|
||||
// raw command to the kernel, and the kernel's fcntl falls through to its
|
||||
// catch-all EINVAL arm. That made `OwnedFd::try_clone()` fail with
|
||||
// EINVAL, which in turn broke `tokio::runtime::Builder::build()` (its I/O
|
||||
// reactor try_clones the epoll fd) for every tokio user on Redox — all
|
||||
// the zbus system daemons and the login shell.
|
||||
let redox_cmd = if cmd == fcntl::F_DUPFD_CLOEXEC {
|
||||
syscall::F_DUPFD_CLOEXEC
|
||||
} else {
|
||||
cmd as usize
|
||||
};
|
||||
Ok(redox_rt::sys::fcntl(fd as usize, redox_cmd, args as usize)? as c_int)
|
||||
}
|
||||
|
||||
fn fdatasync(fd: c_int) -> Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user