[PATCH 6/6 v5] ext4: fix partial page writes
From: Allison Henderson <hidden>
Date: 2011-08-21 02:26:44
Subsystem:
ext4 file system, filesystems (vfs and infrastructure), the rest · Maintainers:
"Theodore Ts'o", Alexander Viro, Christian Brauner, Linus Torvalds
These bugs were also found during extended fsx testing for blocksize = 1k. When ever a write operation begins or ends in a hole, or extends EOF, the partial page contained in the hole or beyond EOF needs to be zeroed out. To correct this the new ext4_discard_partial_page_buffers_no_lock routine is used to zero out the partial page, but only for buffer heads that are already unmapped. Signed-off-by: Allison Henderson <redacted> --- :100644 100644 c1b42cb... 78c723b... M fs/ext4/inode.c fs/ext4/inode.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c1b42cb..78c723b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c@@ -2214,6 +2214,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, pgoff_t index; struct inode *inode = mapping->host; handle_t *handle; + loff_t page_len; index = pos >> PAGE_CACHE_SHIFT;
@@ -2260,6 +2261,11 @@ retry: */ if (pos + len > inode->i_size) ext4_truncate_failed_write(inode); + } else { + page_len = pos & (PAGE_CACHE_SIZE - 1); + ext4_discard_partial_page_buffers_no_lock(handle, + inode, page, pos - page_len, page_len, + EXT4_DSCRD_PARTIAL_PG_ZERO_UNMAPED); } if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -2302,6 +2308,7 @@ static int ext4_da_write_end(struct file *file, loff_t new_i_size; unsigned long start, end; int write_mode = (int)(unsigned long)fsdata; + loff_t page_len; if (write_mode == FALL_BACK_TO_NONDELALLOC) { if (ext4_should_order_data(inode)) {
@@ -2350,6 +2357,14 @@ static int ext4_da_write_end(struct file *file, } ret2 = generic_write_end(file, mapping, pos, len, copied, page, fsdata); + + page_len = PAGE_CACHE_SIZE - + ((pos + copied) & (PAGE_CACHE_SIZE - 1)); + + ext4_discard_partial_page_buffers_no_lock(handle, + inode, page, pos + copied, page_len, + EXT4_DSCRD_PARTIAL_PG_ZERO_UNMAPED); + copied = ret2; if (ret2 < 0) ret = ret2;
--
1.7.1