diff options
author | Hugh Dickins <hugh@veritas.com> | 2007-06-07 09:36:00 +0200 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-06-08 08:34:05 +0200 |
commit | 475ecade683566b19ebb84972de864039ac5fce3 (patch) | |
tree | cd2043c6c951c440988be8057380dfaab1ceb481 /fs/splice.c | |
parent | 20d698db67059a63d217030dfd02872cb5f88dfb (diff) | |
download | talos-op-linux-475ecade683566b19ebb84972de864039ac5fce3.tar.gz talos-op-linux-475ecade683566b19ebb84972de864039ac5fce3.zip |
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 <hugh@veritas.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 18 |
1 files changed, 10 insertions, 8 deletions
diff --git a/fs/splice.c b/fs/splice.c index 6349d3189e3f..123fcdb2e4d9 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) |