splice: fix infinite loop in generic_file_splice_read()
authorJens Axboe <jens.axboe@oracle.com>
Thu, 10 Apr 2008 06:24:25 +0000 (08:24 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Thu, 10 Apr 2008 06:24:25 +0000 (08:24 +0200)
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>
fs/splice.c

index a861bb318ac83c69ca04ed6dccbc8650e386df20..eeb1a86a701467fcc90882f803ff7b39585003fc 100644 (file)
@@ -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;
 }