| From: Jan Kara <jack@suse.cz> |
| Date: Tue, 27 May 2014 12:48:55 -0400 |
| Subject: ext4: fix zeroing of page during writeback |
| |
| commit eeece469dedadf3918bad50ad80f4616a0064e90 upstream. |
| |
| Tail of a page straddling inode size must be zeroed when being written |
| out due to POSIX requirement that modifications of mmaped page beyond |
| inode size must not be written to the file. ext4_bio_write_page() did |
| this only for blocks fully beyond inode size but didn't properly zero |
| blocks partially beyond inode size. Fix this. |
| |
| The problem has been uncovered by mmap_11-4 test in openposix test suite |
| (part of LTP). |
| |
| Reported-by: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com> |
| Fixes: 5a0dc7365c240 |
| Fixes: bd2d0210cf22f |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| [bwh: Backported to 3.2: |
| - Adjust context |
| - block_end was used instead of block_start + blocksize] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/ext4/page-io.c | 24 +++++++++++------------- |
| 1 file changed, 11 insertions(+), 13 deletions(-) |
| |
| --- a/fs/ext4/page-io.c |
| +++ b/fs/ext4/page-io.c |
| @@ -386,24 +386,24 @@ int ext4_bio_write_page(struct ext4_io_s |
| set_page_writeback(page); |
| ClearPageError(page); |
| |
| + /* |
| + * Comments copied from block_write_full_page_endio: |
| + * |
| + * The page straddles i_size. It must be zeroed out on each and every |
| + * writepage invocation because it may be mmapped. "A file is mapped |
| + * in multiples of the page size. For a file that is not a multiple of |
| + * the page size, the remaining memory is zeroed when mapped, and |
| + * writes to that region are not written out to the file." |
| + */ |
| + if (len < PAGE_CACHE_SIZE) |
| + zero_user_segment(page, len, PAGE_CACHE_SIZE); |
| + |
| for (bh = head = page_buffers(page), block_start = 0; |
| bh != head || !block_start; |
| block_start = block_end, bh = bh->b_this_page) { |
| |
| block_end = block_start + blocksize; |
| if (block_start >= len) { |
| - /* |
| - * Comments copied from block_write_full_page_endio: |
| - * |
| - * The page straddles i_size. It must be zeroed out on |
| - * each and every writepage invocation because it may |
| - * be mmapped. "A file is mapped in multiples of the |
| - * page size. For a file that is not a multiple of |
| - * the page size, the remaining memory is zeroed when |
| - * mapped, and writes to that region are not written |
| - * out to the file." |
| - */ |
| - zero_user_segment(page, block_start, block_end); |
| clear_buffer_dirty(bh); |
| set_buffer_uptodate(bh); |
| continue; |