diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2008-02-20 10:34:51 +0100 |
---|---|---|
committer | Jens Axboe <axboe@carl.home.kernel.dk> | 2008-03-04 11:14:39 +0100 |
commit | 02cf01aea5af7a4d1a38045712fe11bffcc206b0 (patch) | |
tree | 28a5817e0bb4aaf174c9d8a87f34a8aefd754aa6 /fs/splice.c | |
parent | 5d87a052c7e5f245bbb3018721b4b0afe0afc252 (diff) | |
download | kernel-common-02cf01aea5af7a4d1a38045712fe11bffcc206b0.tar.gz kernel-common-02cf01aea5af7a4d1a38045712fe11bffcc206b0.tar.bz2 kernel-common-02cf01aea5af7a4d1a38045712fe11bffcc206b0.zip |
splice: only return -EAGAIN if there's hope of more data
sys_tee() currently is a bit eager in returning -EAGAIN, it may do so
even if we don't have a chance of anymore data becoming available. So
improve the logic and only return -EAGAIN if we have an attached writer
to the input pipe.
Reported by Johann Felix Soden <johfel@gmx.de> and
Patrick McManus <mcmanus@ducksong.com>.
Tested-by: Johann Felix Soden <johfel@users.sourceforge.net>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/fs/splice.c b/fs/splice.c index 9b559ee711a8..0670c915cd35 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1669,6 +1669,13 @@ static int link_pipe(struct pipe_inode_info *ipipe, i++; } while (len); + /* + * return EAGAIN if we have the potential of some data in the + * future, otherwise just return 0 + */ + if (!ret && ipipe->waiting_writers && (flags & SPLICE_F_NONBLOCK)) + ret = -EAGAIN; + inode_double_unlock(ipipe->inode, opipe->inode); /* @@ -1709,11 +1716,8 @@ static long do_tee(struct file *in, struct file *out, size_t len, ret = link_ipipe_prep(ipipe, flags); if (!ret) { ret = link_opipe_prep(opipe, flags); - if (!ret) { + if (!ret) ret = link_pipe(ipipe, opipe, len, flags); - if (!ret && (flags & SPLICE_F_NONBLOCK)) - ret = -EAGAIN; - } } } |