splice: fix infinite loop in generic_file_splice_read()
There's a quirky loop in generic_file_splice_read() that could go on indefinitely, if the file splice returns 0 permanently (and not just as a temporary condition). Get rid of the loop and pass back -EAGAIN correctly from __generic_file_splice_read(), so we handle that condition properly as well. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
parent
f4be31ec96
commit
8191ecd1d1
31
fs/splice.c
31
fs/splice.c
|
@ -370,8 +370,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
|
|||
* for an in-flight io page
|
||||
*/
|
||||
if (flags & SPLICE_F_NONBLOCK) {
|
||||
if (TestSetPageLocked(page))
|
||||
if (TestSetPageLocked(page)) {
|
||||
error = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
lock_page(page);
|
||||
|
||||
|
@ -479,9 +481,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
|
|||
struct pipe_inode_info *pipe, size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
ssize_t spliced;
|
||||
int ret;
|
||||
loff_t isize, left;
|
||||
int ret;
|
||||
|
||||
isize = i_size_read(in->f_mapping->host);
|
||||
if (unlikely(*ppos >= isize))
|
||||
|
@ -491,29 +492,9 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
|
|||
if (unlikely(left < len))
|
||||
len = left;
|
||||
|
||||
ret = 0;
|
||||
spliced = 0;
|
||||
while (len && !spliced) {
|
||||
ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
|
||||
|
||||
if (ret < 0)
|
||||
break;
|
||||
else if (!ret) {
|
||||
if (spliced)
|
||||
break;
|
||||
if (flags & SPLICE_F_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
|
||||
if (ret > 0)
|
||||
*ppos += ret;
|
||||
len -= ret;
|
||||
spliced += ret;
|
||||
}
|
||||
|
||||
if (spliced)
|
||||
return spliced;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue