Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=475ecade683566b19ebb84972de864039ac5fce3
Commit:     475ecade683566b19ebb84972de864039ac5fce3
Parent:     20d698db67059a63d217030dfd02872cb5f88dfb
Author:     Hugh Dickins <[EMAIL PROTECTED]>
AuthorDate: Thu Jun 7 09:36:00 2007 +0200
Committer:  Jens Axboe <[EMAIL PROTECTED]>
CommitDate: Fri Jun 8 08:34:05 2007 +0200

    splice: __generic_file_splice_read: fix i_size_read() length checks
    
    __generic_file_splice_read's partial page check, at eof after readpage,
    not only got its calculations wrong, but also reused the loff variable:
    causing data corruption when splicing from a non-0 offset in the file's
    last page (revealed by ext2 -b 1024 testing on a loop of a tmpfs file).
    
    Signed-off-by: Hugh Dickins <[EMAIL PROTECTED]>
    Signed-off-by: Jens Axboe <[EMAIL PROTECTED]>
---
 fs/splice.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/fs/splice.c b/fs/splice.c
index 6349d31..123fcdb 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -272,7 +272,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
        struct page *page;
        pgoff_t index, end_index;
        loff_t isize;
-       size_t total_len;
        int error, page_nr;
        struct splice_pipe_desc spd = {
                .pages = pages,
@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
         * Now fill in the holes:
         */
        error = 0;
-       total_len = 0;
 
        /*
         * Lookup the (hopefully) full range of pages we need.
@@ -429,29 +427,33 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                         * the length and stop
                         */
                        if (end_index == index) {
-                               loff = PAGE_CACHE_SIZE - (isize & 
~PAGE_CACHE_MASK);
-                               if (total_len + loff > isize)
+                               unsigned int plen;
+
+                               /*
+                                * max good bytes in this page
+                                */
+                               plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
+                               if (plen <= loff)
                                        break;
+
                                /*
                                 * force quit after adding this page
                                 */
+                               this_len = min(this_len, plen - loff);
                                len = this_len;
-                               this_len = min(this_len, loff);
-                               loff = 0;
                        }
                }
 fill_it:
                partial[page_nr].offset = loff;
                partial[page_nr].len = this_len;
                len -= this_len;
-               total_len += this_len;
                loff = 0;
                spd.nr_pages++;
                index++;
        }
 
        /*
-        * Release any pages at the end, if we quit early. 'i' is how far
+        * Release any pages at the end, if we quit early. 'page_nr' is how far
         * we got, 'nr_pages' is how many pages are in the map.
         */
        while (page_nr < nr_pages)
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to