splice() from pipe should return 0 when there is no pipe writer. However, since commit a194dfe6e6f6f720 ("pipe: Rearrange sequence in pipe_write() to preallocate slot") started inserting empty pages, splice() from pipe also returns 0 when all ready buffers are empty pages. ---------- #define _GNU_SOURCE #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { const int fd = open("/tmp/testfile", O_WRONLY | O_CREAT, 0600); int pipe_fd[2] = { -1, -1 }; pipe(pipe_fd); write(pipe_fd[1], NULL, 4096); /* This splice() should wait unless interrupted. */ return !splice(pipe_fd[0], NULL, fd, NULL, 65536, 0); } ---------- Since such behavior might confuse splice() users, let's fix it by waiting for non-empty pages inside splice_from_pipe_next(). Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx> Fixes: a194dfe6e6f6f720 ("pipe: Rearrange sequence in pipe_write() to preallocate slot") Cc: stable@xxxxxxxxxxxxxxx # 5.5+ --- fs/splice.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/fs/splice.c b/fs/splice.c index c3d00dfc7344..b58c7ebf6805 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -538,6 +538,8 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des */ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) { + unsigned int head, tail, mask; + /* * Check for signal early to make process killable when there are * always buffers available @@ -545,6 +547,7 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des if (signal_pending(current)) return -ERESTARTSYS; + refill: while (pipe_empty(pipe->head, pipe->tail)) { if (!pipe->writers) return 0; @@ -566,7 +569,21 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des pipe_wait_readable(pipe); } - return 1; + head = pipe->head; + tail = pipe->tail; + mask = pipe->ring_size - 1; + + /* dismiss the empty buffers */ + while (!pipe_empty(head, tail)) { + struct pipe_buffer *buf = &pipe->bufs[tail & mask]; + + if (likely(buf->len)) + return 1; + pipe_buf_release(pipe, buf); + pipe->tail = ++tail; + } + /* wait again if all buffers were empty */ + goto refill; } /** -- 2.18.4