diff options
| author | Nickolai Zeldovich <nickolai@csail.mit.edu> | 2026-10-17 22:58:24 -0400 |
|---|---|---|
| committer | Jens Axboe <axboe@kernel.dk> | 2026-10-19 15:01:45 -0600 |
| commit | c82621eb2c9a00b514a459951609e04843d467bb (patch) | |
| tree | 843bb0d76d263e2c478880491dbd58166d32837e /include/uapi | |
| parent | 96262cfab554cf11412de7a6247f0e82c94e130f (diff) | |
io_uring/waitid: return -EAGAIN for a non-blocking pidfd
IORING_OP_WAITID on a pidfd opened with PIDFD_NONBLOCK completes at
once with res 0 and an all-zero siginfo when the child has not changed
state, although WNOHANG was not requested. waitid(2) with the same
arguments fails with -EAGAIN. An application that submits the same
request it would pass to waitid(2) and treats res 0 as "the child
changed state" sees si_signo 0 and si_pid 0 instead.
kernel_waitid_prepare() turns an O_NONBLOCK pidfd into WNOHANG in
wo->wo_flags. kernel_waitid() then maps the resulting 0 return to
-EAGAIN when the caller did not ask for WNOHANG itself, as added in
commit ba7d25f3dff6 ("exit: support non-blocking pidfds").
io_waitid() uses kernel_waitid_prepare() and __do_wait() directly and
does not do that mapping.
Do the same check in io_waitid() before completing the request. Only
the inline path needs it: with WNOHANG set, __do_wait() never returns
-ERESTARTSYS, so such a request is never armed on the wait queue.
Reproduced on x86_64 under QEMU: with a PIDFD_NONBLOCK pidfd of a
running child and options = WEXITED, waitid(2) fails with -EAGAIN and
IORING_OP_WAITID completed with res 0 before the change; it completes
with res -EAGAIN after it.
Fixes: f31ecf671ddc ("io_uring: add IORING_OP_WAITID support")
Assisted-by: LLM
Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
Link: https://patch.msgid.link/20261018025824.799245-1-nickolai@csail.mit.edu
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'include/uapi')
0 files changed, 0 insertions, 0 deletions
