summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-03-12 08:18:16 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-03-12 08:18:16 +0000
commit8b2bd3ddf4ecbde7032ed514b8bd7c73b493b222 (patch)
treef24c752c32cf2c3ecd318e687a20f61d1f65dcd8
parent3e0e74cef5424866f16f724f54bf7ea29264131f (diff)
parent9d636818dbac53c07c1bf7aa006c06ec32253187 (diff)
ext4: fix data corruption in data=journal mode
am: 9d636818db Change-Id: Idc4320c3f0fa867216d8770b5ad186226e61152a
-rw-r--r--fs/ext4/inode.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 790961e33961..8a08807359b5 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1232,7 +1232,9 @@ errout:
* set the buffer to be dirty, since in data=journalled mode we need
* to call ext4_handle_dirty_metadata() instead.
*/
-static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+static void ext4_journalled_zero_new_buffers(handle_t *handle,
+ struct page *page,
+ unsigned from, unsigned to)
{
unsigned int block_start = 0, block_end;
struct buffer_head *head, *bh;
@@ -1249,7 +1251,7 @@ static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
size = min(to, block_end) - start;
zero_user(page, start, size);
- set_buffer_uptodate(bh);
+ write_end_fn(handle, bh);
}
clear_buffer_new(bh);
}
@@ -1282,15 +1284,16 @@ static int ext4_journalled_write_end(struct file *file,
if (ext4_has_inline_data(inode))
copied = ext4_write_inline_data_end(inode, pos, len,
copied, page);
- else {
- if (copied < len) {
- if (!PageUptodate(page))
- copied = 0;
- zero_new_buffers(page, from+copied, to);
- }
-
+ else if (unlikely(copied < len) && !PageUptodate(page)) {
+ copied = 0;
+ ext4_journalled_zero_new_buffers(handle, page, from, to);
+ } else {
+ if (unlikely(copied < len))
+ ext4_journalled_zero_new_buffers(handle, page,
+ from + copied, to);
ret = ext4_walk_page_buffers(handle, page_buffers(page), from,
- to, &partial, write_end_fn);
+ from + copied, &partial,
+ write_end_fn);
if (!partial)
SetPageUptodate(page);
}