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 | linux-475ecade683566b19ebb84972de864039ac5fce3.tar.bz2 | |
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) |