aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2007-06-07 03:36:00 -0400
committerJens Axboe <jens.axboe@oracle.com>2007-06-08 02:34:05 -0400
commit475ecade683566b19ebb84972de864039ac5fce3 (patch)
treecd2043c6c951c440988be8057380dfaab1ceb481 /fs
parent20d698db67059a63d217030dfd02872cb5f88dfb (diff)
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')
-rw-r--r--fs/splice.c18
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,
272 struct page *page; 272 struct page *page;
273 pgoff_t index, end_index; 273 pgoff_t index, end_index;
274 loff_t isize; 274 loff_t isize;
275 size_t total_len;
276 int error, page_nr; 275 int error, page_nr;
277 struct splice_pipe_desc spd = { 276 struct splice_pipe_desc spd = {
278 .pages = pages, 277 .pages = pages,
@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
298 * Now fill in the holes: 297 * Now fill in the holes:
299 */ 298 */
300 error = 0; 299 error = 0;
301 total_len = 0;
302 300
303 /* 301 /*
304 * Lookup the (hopefully) full range of pages we need. 302 * Lookup the (hopefully) full range of pages we need.
@@ -429,29 +427,33 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
429 * the length and stop 427 * the length and stop
430 */ 428 */
431 if (end_index == index) { 429 if (end_index == index) {
432 loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK); 430 unsigned int plen;
433 if (total_len + loff > isize) 431
432 /*
433 * max good bytes in this page
434 */
435 plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
436 if (plen <= loff)
434 break; 437 break;
438
435 /* 439 /*
436 * force quit after adding this page 440 * force quit after adding this page
437 */ 441 */
442 this_len = min(this_len, plen - loff);
438 len = this_len; 443 len = this_len;
439 this_len = min(this_len, loff);
440 loff = 0;
441 } 444 }
442 } 445 }
443fill_it: 446fill_it:
444 partial[page_nr].offset = loff; 447 partial[page_nr].offset = loff;
445 partial[page_nr].len = this_len; 448 partial[page_nr].len = this_len;
446 len -= this_len; 449 len -= this_len;
447 total_len += this_len;
448 loff = 0; 450 loff = 0;
449 spd.nr_pages++; 451 spd.nr_pages++;
450 index++; 452 index++;
451 } 453 }
452 454
453 /* 455 /*
454 * Release any pages at the end, if we quit early. 'i' is how far 456 * Release any pages at the end, if we quit early. 'page_nr' is how far
455 * we got, 'nr_pages' is how many pages are in the map. 457 * we got, 'nr_pages' is how many pages are in the map.
456 */ 458 */
457 while (page_nr < nr_pages) 459 while (page_nr < nr_pages)