diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2008-04-10 02:24:25 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-04-10 02:24:25 -0400 |
commit | 8191ecd1d14c6914c660dfa007154860a7908857 (patch) | |
tree | 7a2c76742945e9659db502c16ed17d33a0644bfd /fs | |
parent | f4be31ec9690cfe6e94fcbed6ae60a6a38b3c3ed (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/splice.c | 31 |
1 files changed, 6 insertions, 25 deletions
diff --git a/fs/splice.c b/fs/splice.c index a861bb318ac8..eeb1a86a7014 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -370,8 +370,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
370 | * for an in-flight io page | 370 | * for an in-flight io page |
371 | */ | 371 | */ |
372 | if (flags & SPLICE_F_NONBLOCK) { | 372 | if (flags & SPLICE_F_NONBLOCK) { |
373 | if (TestSetPageLocked(page)) | 373 | if (TestSetPageLocked(page)) { |
374 | error = -EAGAIN; | ||
374 | break; | 375 | break; |
376 | } | ||
375 | } else | 377 | } else |
376 | lock_page(page); | 378 | lock_page(page); |
377 | 379 | ||
@@ -479,9 +481,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, | |||
479 | struct pipe_inode_info *pipe, size_t len, | 481 | struct pipe_inode_info *pipe, size_t len, |
480 | unsigned int flags) | 482 | unsigned int flags) |
481 | { | 483 | { |
482 | ssize_t spliced; | ||
483 | int ret; | ||
484 | loff_t isize, left; | 484 | loff_t isize, left; |
485 | int ret; | ||
485 | 486 | ||
486 | isize = i_size_read(in->f_mapping->host); | 487 | isize = i_size_read(in->f_mapping->host); |
487 | if (unlikely(*ppos >= isize)) | 488 | if (unlikely(*ppos >= isize)) |
@@ -491,29 +492,9 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, | |||
491 | if (unlikely(left < len)) | 492 | if (unlikely(left < len)) |
492 | len = left; | 493 | len = left; |
493 | 494 | ||
494 | ret = 0; | 495 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); |
495 | spliced = 0; | 496 | if (ret > 0) |
496 | while (len && !spliced) { | ||
497 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); | ||
498 | |||
499 | if (ret < 0) | ||
500 | break; | ||
501 | else if (!ret) { | ||
502 | if (spliced) | ||
503 | break; | ||
504 | if (flags & SPLICE_F_NONBLOCK) { | ||
505 | ret = -EAGAIN; | ||
506 | break; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | *ppos += ret; | 497 | *ppos += ret; |
511 | len -= ret; | ||
512 | spliced += ret; | ||
513 | } | ||
514 | |||
515 | if (spliced) | ||
516 | return spliced; | ||
517 | 498 | ||
518 | return ret; | 499 | return ret; |
519 | } | 500 | } |