Commit 475ecade authored by Hugh Dickins's avatar Hugh Dickins Committed by Jens Axboe

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: default avatarHugh Dickins <hugh@veritas.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 20d698db
...@@ -272,7 +272,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -272,7 +272,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
struct page *page; struct page *page;
pgoff_t index, end_index; pgoff_t index, end_index;
loff_t isize; loff_t isize;
size_t total_len;
int error, page_nr; int error, page_nr;
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
...@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
* Now fill in the holes: * Now fill in the holes:
*/ */
error = 0; error = 0;
total_len = 0;
/* /*
* Lookup the (hopefully) full range of pages we need. * Lookup the (hopefully) full range of pages we need.
...@@ -429,29 +427,33 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -429,29 +427,33 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
* the length and stop * the length and stop
*/ */
if (end_index == index) { if (end_index == index) {
loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK); unsigned int plen;
if (total_len + loff > isize)
/*
* max good bytes in this page
*/
plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
if (plen <= loff)
break; break;
/* /*
* force quit after adding this page * force quit after adding this page
*/ */
this_len = min(this_len, plen - loff);
len = this_len; len = this_len;
this_len = min(this_len, loff);
loff = 0;
} }
} }
fill_it: fill_it:
partial[page_nr].offset = loff; partial[page_nr].offset = loff;
partial[page_nr].len = this_len; partial[page_nr].len = this_len;
len -= this_len; len -= this_len;
total_len += this_len;
loff = 0; loff = 0;
spd.nr_pages++; spd.nr_pages++;
index++; 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. * we got, 'nr_pages' is how many pages are in the map.
*/ */
while (page_nr < nr_pages) while (page_nr < nr_pages)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment