Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[sfrench/cifs-2.6.git] / fs / splice.c
index 53fc2082a4681fdc311adcf0596f11fb6d45a8c5..0a09732180847ce6cb7d67f91477c2314296003a 100644 (file)
@@ -265,7 +265,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                           unsigned int flags)
 {
        struct address_space *mapping = in->f_mapping;
-       unsigned int loff, nr_pages;
+       unsigned int loff, nr_pages, req_pages;
        struct page *pages[PIPE_BUFFERS];
        struct partial_page partial[PIPE_BUFFERS];
        struct page *page;
@@ -281,28 +281,24 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 
        index = *ppos >> PAGE_CACHE_SHIFT;
        loff = *ppos & ~PAGE_CACHE_MASK;
-       nr_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
-       if (nr_pages > PIPE_BUFFERS)
-               nr_pages = PIPE_BUFFERS;
-
-       /*
-        * Don't try to 2nd guess the read-ahead logic, call into
-        * page_cache_readahead() like the page cache reads would do.
-        */
-       page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
+       req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       nr_pages = min(req_pages, (unsigned)PIPE_BUFFERS);
 
        /*
         * Lookup the (hopefully) full range of pages we need.
         */
        spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, pages);
+       index += spd.nr_pages;
 
        /*
         * If find_get_pages_contig() returned fewer pages than we needed,
-        * allocate the rest and fill in the holes.
+        * readahead/allocate the rest and fill in the holes.
         */
+       if (spd.nr_pages < nr_pages)
+               page_cache_sync_readahead(mapping, &in->f_ra, in,
+                               index, req_pages - spd.nr_pages);
+
        error = 0;
-       index += spd.nr_pages;
        while (spd.nr_pages < nr_pages) {
                /*
                 * Page could be there, find_get_pages_contig() breaks on
@@ -310,12 +306,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                 */
                page = find_get_page(mapping, index);
                if (!page) {
-                       /*
-                        * Make sure the read-ahead engine is notified
-                        * about this failure.
-                        */
-                       handle_ra_miss(mapping, &in->f_ra, index);
-
                        /*
                         * page didn't exist, allocate one.
                         */
@@ -361,6 +351,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
                page = pages[page_nr];
 
+               if (PageReadahead(page))
+                       page_cache_async_readahead(mapping, &in->f_ra, in,
+                                       page, index, req_pages - page_nr);
+
                /*
                 * If the page isn't uptodate, we may need to start io on it
                 */
@@ -453,6 +447,7 @@ fill_it:
         */
        while (page_nr < nr_pages)
                page_cache_release(pages[page_nr++]);
+       in->f_ra.prev_index = index;
 
        if (spd.nr_pages)
                return splice_to_pipe(pipe, &spd);
@@ -599,7 +594,7 @@ find_page:
                ret = add_to_page_cache_lru(page, mapping, index,
                                            GFP_KERNEL);
                if (unlikely(ret))
-                       goto out;
+                       goto out_release;
        }
 
        ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len);
@@ -655,8 +650,9 @@ find_page:
         */
        mark_page_accessed(page);
 out:
-       page_cache_release(page);
        unlock_page(page);
+out_release:
+       page_cache_release(page);
 out_ret:
        return ret;
 }