diff --git a/fs/splice.c b/fs/splice.c index f4bce3589067..e6d43329ed3f 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1884,6 +1884,15 @@ static ssize_t link_pipe(struct pipe_inode_info *ipipe, unsigned int i_tail, o_tail; ssize_t ret = 0; +retry: + ret = ipipe_prep(ipipe, flags); + if (ret) + return ret; + + ret = opipe_prep(opipe, flags); + if (ret) + return ret; + /* * Potential ABBA deadlock, work around it by ordering lock * grabbing by pipe info address. Otherwise two different processes @@ -1905,13 +1914,32 @@ static ssize_t link_pipe(struct pipe_inode_info *ipipe, i_head = ipipe->head; o_tail = opipe->tail; + if (pipe_empty(i_head, i_tail) && !ipipe->writers) + break; + /* * If we have iterated all input buffers or run out of * output room, break. */ if (pipe_empty(i_head, i_tail) || - pipe_full(o_head, o_tail, opipe->max_usage)) - break; + pipe_full(o_head, o_tail, opipe->max_usage)) { + if (ret) + break; + + if (flags & SPLICE_F_NONBLOCK) { + ret = -EAGAIN; + break; + } + + /* + * We raced with another reader/writer and haven't + * linked any buffers. A zero return value means EOF, + * so retry instead. + */ + pipe_unlock(ipipe); + pipe_unlock(opipe); + goto retry; + } ibuf = pipe_buf(ipipe, i_tail); obuf = pipe_buf(opipe, o_head); @@ -1982,16 +2010,7 @@ ssize_t do_tee(struct file *in, struct file *out, size_t len, if ((in->f_flags | out->f_flags) & O_NONBLOCK) flags |= SPLICE_F_NONBLOCK; - /* - * Keep going, unless we encounter an error. The ipipe/opipe - * ordering doesn't really matter. - */ - ret = ipipe_prep(ipipe, flags); - if (!ret) { - ret = opipe_prep(opipe, flags); - if (!ret) - ret = link_pipe(ipipe, opipe, len, flags); - } + ret = link_pipe(ipipe, opipe, len, flags); } if (ret > 0) {