__io_read() treats a short read on pipes and sockets as success and returns without filling the iov. However, __io_complete_rw_common() compared the transfer length against the original iov size and set REQ_F_FAIL when they did not match. That incorrectly failed linked requests behind a successful head request, for example a nop after a naturally disarmed link timeout. Treat short reads and writes on non-regular files as success in __io_complete_rw_common(), matching the issue path. Signed-off-by: Yang Xiuwei --- io_uring/rw.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/io_uring/rw.c b/io_uring/rw.c index 0c4834645279..dd3f24b380b1 100644 --- a/io_uring/rw.c +++ b/io_uring/rw.c @@ -547,10 +547,23 @@ static void io_req_io_end(struct io_kiocb *req) } } +static bool need_complete_io(struct io_kiocb *req) +{ + return req->flags & REQ_F_ISREG || + S_ISBLK(file_inode(req->file)->i_mode); +} + static void __io_complete_rw_common(struct io_kiocb *req, long res) { if (res == req->cqe.res) return; + /* + * For non-regular files, __io_read()/__io_write() may return a short + * transfer without looping to fill the iter. That is success, not a + * failure to be propagated to linked requests. + */ + if (res > 0 && res < req->cqe.res && !need_complete_io(req)) + return; if ((res == -EOPNOTSUPP || res == -EAGAIN) && io_rw_should_reissue(req)) { req->flags |= REQ_F_REISSUE | REQ_F_BL_NO_RECYCLE; } else { @@ -839,12 +852,6 @@ static inline int io_iter_do_read(struct io_rw *rw, struct iov_iter *iter) return -EINVAL; } -static bool need_complete_io(struct io_kiocb *req) -{ - return req->flags & REQ_F_ISREG || - S_ISBLK(file_inode(req->file)->i_mode); -} - static int io_rw_init_file(struct io_kiocb *req, fmode_t mode, int rw_type) { struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw); -- 2.25.1