You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
splice and sendfile lose input into a nonblocking pipe #468
splice and sendfile lose input when the output is a pipe the guest set O_NONBLOCK. The emulation reads a whole chunk from the input before it writes it (sys_splice and splice_drain_chunk, copy_fd_range for sendfile in src/syscall/io.c). When the nonblocking write places only part of the chunk, the rest has already been consumed, and io_rewind_unsent cannot hand it back to a pipe or socket input.
Measured with a static aarch64 probe: pipe a holds 8 KiB, pipe b has O_NONBLOCK set by the guest and 4 KiB of free room, then the probe calls splice(a[0], NULL, b[1], NULL, 8192, 0) and, in a second run, sendfile(b[1], a[0], NULL, 8192).
The sendfile row has a second difference: Linux refuses a pipe as the sendfile input, and elfuse accepts it.
#463 fixed the same loss for SPLICE_F_NONBLOCK: a pipe output is polled for POLLOUT before each read and the chunk is capped at PIPE_BUF, since a ready macOS pipe has at least that much free. The O_NONBLOCK case still reaches the old path.
A blocking socket output has a related gap. Linux ignores SPLICE_F_NONBLOCK for a socket output and follows the socket's own O_NONBLOCK, so the call blocks there too. Measured: splice(pipe_with_5_bytes, NULL, full_blocking_af_unix_socket, NULL, 5, SPLICE_F_NONBLOCK) with a 2 s alarm and a handler returns -1 with EINTR on Linux under qemu. elfuse never returns: the chunk has already been read from the pipe and cannot be put back, so splice_drain_chunk keeps retrying the write instead of reporting the signal.
Goal: when the output cannot take a whole chunk without blocking, splice and sendfile read only what the output can take and report what moved, so no input byte is consumed without being written. sendfile refuses a pipe input with EINVAL, as Linux does.
Activity