diff options
Diffstat (limited to 'mm/shmem.c')
| -rw-r--r-- | mm/shmem.c | 31 | 
1 files changed, 20 insertions, 11 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 529c9ad3e926..4b2fea33158e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2513,7 +2513,6 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)  		pgoff_t end_index;  		unsigned long nr, ret;  		loff_t i_size = i_size_read(inode); -		bool got_page;  		end_index = i_size >> PAGE_SHIFT;  		if (index > end_index) @@ -2570,24 +2569,34 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)  			 */  			if (!offset)  				mark_page_accessed(page); -			got_page = true; +			/* +			 * Ok, we have the page, and it's up-to-date, so +			 * now we can copy it to user space... +			 */ +			ret = copy_page_to_iter(page, offset, nr, to); +			put_page(page); + +		} else if (iter_is_iovec(to)) { +			/* +			 * Copy to user tends to be so well optimized, but +			 * clear_user() not so much, that it is noticeably +			 * faster to copy the zero page instead of clearing. +			 */ +			ret = copy_page_to_iter(ZERO_PAGE(0), offset, nr, to);  		} else { -			page = ZERO_PAGE(0); -			got_page = false; +			/* +			 * But submitting the same page twice in a row to +			 * splice() - or others? - can result in confusion: +			 * so don't attempt that optimization on pipes etc. +			 */ +			ret = iov_iter_zero(nr, to);  		} -		/* -		 * Ok, we have the page, and it's up-to-date, so -		 * now we can copy it to user space... -		 */ -		ret = copy_page_to_iter(page, offset, nr, to);  		retval += ret;  		offset += ret;  		index += offset >> PAGE_SHIFT;  		offset &= ~PAGE_MASK; -		if (got_page) -			put_page(page);  		if (!iov_iter_count(to))  			break;  		if (ret < nr) {  | 
